diff --git a/.nancy-ignore b/.nancy-ignore index bef65c0cc7..8c135f4743 100644 --- a/.nancy-ignore +++ b/.nancy-ignore @@ -1,4 +1,2 @@ CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue. -CVE-2024-6104 # "CWE-532: Information Exposure Through Log Files" This is caused by the vulnerabilities go-retryablehttp@v0.7.4, it is only used in cmd devp2p, impact is limited. will upgrade to v0.7.7 later -CVE-2024-8421 # "CWE-400: Uncontrolled Resource Consumption (Resource Exhaustion)" This vulnerability is caused by issues in the golang.org/x/net package. Even the latest version(v0.29.0) has not yet addressed it, but we will continue to monitor updates closely. -CVE-2024-51744 # "CWE-347: Improper Verification of Cryptographic Signature" & "CWE-755: Improper Handling of Exceptional Conditions" This vulnerability is caused mishandling of JWT error code, BSC does not have the issue as it does not check the detail error code. \ No newline at end of file +CVE-2025-22872 # "CWE-1286: github.com/golang/net - Improper Validation of Syntactic Correctness of Input", golang/golang.org/x/net@v0.36.0 was indirectly dependency by devp2p, can be will upgraded in the future \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d55baa97..62341d56d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,19 @@ # Changelog +## v1.5.11 +### FEATURE +[\#3008](https://github.com/bnb-chain/bsc/pull/3008) params: add MaxwellTime +[\#3025](https://github.com/bnb-chain/bsc/pull/3025) config.toml: default value of [Eth.Miner] and [Eth.Miner.Mev] +[\#3026](https://github.com/bnb-chain/bsc/pull/3026) mev: include MaxBidsPerBuilder in MevParams +[\#3027](https://github.com/bnb-chain/bsc/pull/3027) mev: update two default mev paramater for 1.5s block interval + +### BUGFIX +[\#3007](https://github.com/bnb-chain/bsc/pull/3007) metrics: fix panic for cocurrently accessing label + +### IMPROVEMENT +[\#3006](https://github.com/bnb-chain/bsc/pull/3006) jsutil: update getKeyParameters +[\#3018](https://github.com/bnb-chain/bsc/pull/3018) nancy: update nancy ignore +[\#3021](https://github.com/bnb-chain/bsc/pull/3021) chore: remove duplicate package imports + ## v1.5.10 ### FEATURE [\#3015](https://github.com/bnb-chain/bsc/pull/3015) config: update BSC Mainnet hardfork time: Lorentz @@ -138,7 +153,7 @@ _in bsc, this feature only enabled with multi-database_ #### New EIPs [core/vm: enable bls-precompiles for Prague (](https://github.com/ethereum/go-ethereum/commit/823719b9e1b72174cd8245ae9e6f6f7d7072a8d6)[#29552](https://github.com/ethereum/go-ethereum/pull/29552)[)](https://github.com/ethereum/go-ethereum/commit/823719b9e1b72174cd8245ae9e6f6f7d7072a8d6) -[EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935) ([#29465](https://github.com/ethereum/go-ethereum/pull/29465)) +[EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935) ([#29465](https://github.com/ethereum/go-ethereum/pull/29465)) #### Clear Up [eth, eth/downloader: remove references to LightChain, LightSync (#29711)](https://github.com/ethereum/go-ethereum/pull/29711) diff --git a/README.md b/README.md index 31b9e280ce..54905b2834 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ BNB Smart Chain starts its development based on go-ethereum fork. So you may see [![API Reference]( https://pkg.go.dev/badge/github.com/ethereum/go-ethereum )](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc) +[![Build Test](https://github.com/bnb-chain/bsc/actions/workflows/build-test.yml/badge.svg)](https://github.com/bnb-chain/bsc/actions) [![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/z2VpC455eU) But from that baseline of EVM compatible, BNB Smart Chain introduces a system of 21 validators with Proof of Staked Authority (PoSA) consensus that can support short block time and lower fees. The most bonded validator candidates of staking will become validators and produce blocks. The double-sign detection and other slashing logic guarantee security, stability, and chain finality. diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 9d4587977d..5ea3fa7277 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -63,6 +63,7 @@ var ( utils.CachePreimagesFlag, utils.OverridePassedForkTime, utils.OverrideLorentz, + utils.OverrideMaxwell, utils.OverrideVerkle, utils.MultiDataBaseFlag, }, utils.DatabaseFlags), @@ -263,6 +264,10 @@ func initGenesis(ctx *cli.Context) error { v := ctx.Uint64(utils.OverrideLorentz.Name) overrides.OverrideLorentz = &v } + if ctx.IsSet(utils.OverrideMaxwell.Name) { + v := ctx.Uint64(utils.OverrideMaxwell.Name) + overrides.OverrideMaxwell = &v + } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) overrides.OverrideVerkle = &v diff --git a/cmd/geth/config.go b/cmd/geth/config.go index eba6c7aeba..55799e7937 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -155,6 +155,9 @@ func loadBaseConfig(ctx *cli.Context) gethConfig { if err := loadConfig(file, &cfg); err != nil { utils.Fatalf("%v", err) } + // some default options could be overwritten after `loadConfig()` + // apply the default value if the options are not specified in config.toml file. + ethconfig.ApplyDefaultEthConfig(&cfg.Eth) } scheme := cfg.Eth.StateScheme @@ -209,6 +212,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideLorentz.Name) cfg.Eth.OverrideLorentz = &v } + if ctx.IsSet(utils.OverrideMaxwell.Name) { + v := ctx.Uint64(utils.OverrideMaxwell.Name) + cfg.Eth.OverrideMaxwell = &v + } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) cfg.Eth.OverrideVerkle = &v diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8ac0498f89..421b536df2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -75,6 +75,7 @@ var ( utils.RialtoHash, utils.OverridePassedForkTime, utils.OverrideLorentz, + utils.OverrideMaxwell, utils.OverrideVerkle, utils.OverrideFullImmutabilityThreshold, utils.OverrideMinBlocksForBlobRequests, diff --git a/cmd/jsutils/getchainstatus.js b/cmd/jsutils/getchainstatus.js index ad5d87614f..ceb7ae4eaa 100644 --- a/cmd/jsutils/getchainstatus.js +++ b/cmd/jsutils/getchainstatus.js @@ -55,6 +55,7 @@ const provider = new ethers.JsonRpcProvider(program.rpc); const addrValidatorSet = "0x0000000000000000000000000000000000001000"; const addrSlash = "0x0000000000000000000000000000000000001001"; const addrStakeHub = "0x0000000000000000000000000000000000002002"; +const addrGovernor = "0x0000000000000000000000000000000000002004"; const validatorSetAbi = [ "function validatorExtraSet(uint256 offset) external view returns (uint256, bool, bytes)", @@ -69,7 +70,12 @@ const validatorSetAbi = [ "function burnRatio() external view returns (uint256)", // default: 10% "function systemRewardBaseRatio() external view returns (uint256)", // default: 1/16 ]; -const slashAbi = ["function getSlashIndicator(address validatorAddr) external view returns (uint256, uint256)"]; +const slashAbi = [ + "function getSlashIndicator(address validatorAddr) external view returns (uint256, uint256)", + "function misdemeanorThreshold() external view returns (uint256)", + "function felonyThreshold() external view returns (uint256)", + "function felonySlashScope() external view returns (uint256)", +]; // https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/StakeHub.sol const stakeHubAbi = [ @@ -85,9 +91,15 @@ const stakeHubAbi = [ "function felonyJailTime() public view returns (uint256)", // default 30days, ]; +const governorAbi = [ + "function votingPeriod() public view returns (uint256)", + "function lateQuorumVoteExtension() public view returns (uint64)", // it represents minPeriodAfterQuorum +]; + const validatorSet = new ethers.Contract(addrValidatorSet, validatorSetAbi, provider); const slashIndicator = new ethers.Contract(addrSlash, slashAbi, provider); const stakeHub = new ethers.Contract(addrStakeHub, stakeHubAbi, provider); +const governor = new ethers.Contract(addrGovernor, governorAbi, provider); const validatorMap = new Map([ // BSC mainnet @@ -136,6 +148,10 @@ const validatorMap = new Map([ ["0xd849d1dF66bFF1c2739B4399425755C2E0fAbbAb", "Nexa"], ["0xA015d9e9206859c13201BB3D6B324d6634276534", "Star"], ["0x5ADde0151BfAB27f329e5112c1AeDeed7f0D3692", "Veri"], + ["0xd6Ab358AD430F65EB4Aa5a1598FF2c34489dcfdE", "Saturn"], + ["0x0dC5e1CAe4d364d0C79C9AE6BDdB5DA49b10A7d9", "ListaDAO"], + ["0xE554F591cCFAc02A84Cf9a5165DDF6C1447Cc67D", "ListaDAO2"], + ["0x059a8BFd798F29cE665816D12D56400Fa47DE028", "ListaDAO3"], // Chapel ["0x08265dA01E1A65d62b903c7B34c08cB389bF3D99", "Ararat"], ["0x7f5f2cF1aec83bF0c74DF566a41aa7ed65EA84Ea", "Kita"], @@ -160,6 +176,13 @@ const validatorMap = new Map([ ["0xEe22F03961b407bCBae66499a029Be4cA0AF4ab4", "AB4"], ["0x1AE5f5C3Cb452E042b0B7b9DC60596C9CD84BaF6", "Jake"], ["0xfA4d592F9B152f7a10B5DE9bE24C27a74BCE431A", "MyTWFMM"], + ["0x26Ba9aB44feb5D8eE47aDeaa46a472f71E50fbce", "Lime"], + ["0xC8824e38440893b62CaDC4d1BD05e33895B25d74", "Skynet3k"], + ["0x9a2da2Ce5Eda5E0b4914720c3A798521956E1009", "Musala"], + ["0x9270fF2EaA8ef253B57011A5b7505D948784E2be", "Vihren"], + ["0x86eb31b90566a9f4F3AB85138c78A000EBA81685", "GucciOp3k"], + ["0x28D70c3756d4939DCBdEB3f0fFF5B4B36E6e327F", "OmegaV"], + ["0x6a5470a3B7959ab064d6815e349eD4aE2dE5210d", "Skynet10k"], ]); const builderMap = new Map([ @@ -553,19 +576,26 @@ async function getKeyParameters() { numOfCabinets = 21; } // let maxNumOfCandidates = await validatorSet.maxNumOfCandidates({blockTag:blockNum}) // deprecated - // let turnLength = await validatorSet.turnLength({blockTag:blockNum}) + let turnLength = await validatorSet.turnLength({blockTag:blockNum}) let maxNumOfWorkingCandidates = await validatorSet.maxNumOfWorkingCandidates({ blockTag: blockNum }); let maintainSlashScale = await validatorSet.maintainSlashScale({ blockTag: blockNum }); - console.log( - "numOfCabinets", - Number(numOfCabinets), - "maxNumOfWorkingCandidates", - Number(maxNumOfWorkingCandidates), - "maintainSlashScale", - maintainSlashScale - ); - - // part 2: staking + console.log("##==== ValidatorContract: 0x0000000000000000000000000000000000001000"); + console.log("\tturnLength", Number(turnLength)); + console.log("\tnumOfCabinets", Number(numOfCabinets)); + console.log("\tmaxNumOfWorkingCandidates", Number(maxNumOfWorkingCandidates)); + console.log("\tmaintainSlashScale", Number(maintainSlashScale)); + + // part 2: slash + let misdemeanorThreshold = await slashIndicator.misdemeanorThreshold({blockTag:blockNum}) + let felonyThreshold = await slashIndicator.felonyThreshold({blockTag:blockNum}) + let felonySlashScope = await slashIndicator.felonySlashScope({blockTag:blockNum}) + console.log("##==== SlashContract: 0x0000000000000000000000000000000000001001"); + console.log("\tmisdemeanorThreshold", Number(misdemeanorThreshold)); + console.log("\tfelonyThreshold", Number(felonyThreshold)); + console.log("\tfelonySlashScope", Number(felonySlashScope)); + + + // part 3: staking // let minSelfDelegationBNB = await stakeHub.minSelfDelegationBNB({blockTag:blockNum})/BigInt(10**18) let maxElectedValidators = await stakeHub.maxElectedValidators({ blockTag: blockNum }); let validatorElectionInfo = await stakeHub.getValidatorElectionInfo(0, 0, { blockTag: blockNum }); @@ -573,7 +603,10 @@ async function getKeyParameters() { let votingPowers = validatorElectionInfo[1]; let voteAddrs = validatorElectionInfo[2]; let totalLength = validatorElectionInfo[3]; - console.log("maxElectedValidators", Number(maxElectedValidators), "Registered", Number(totalLength)); + + console.log("\n##==== StakeHubContract: 0x0000000000000000000000000000000000002002") + console.log("\tmaxElectedValidators", Number(maxElectedValidators)); + console.log("\tRegistered", Number(totalLength)); let validatorTable = []; for (let i = 0; i < totalLength; i++) { validatorTable.push({ @@ -585,6 +618,13 @@ async function getKeyParameters() { } validatorTable.sort((a, b) => b.votingPower - a.votingPower); console.table(validatorTable); + + // part 4: governance + let votingPeriod = await governor.votingPeriod({ blockTag: blockNum }); + let minPeriodAfterQuorum = await governor.lateQuorumVoteExtension({ blockTag: blockNum }); + console.log("\n##==== GovernorContract: 0x0000000000000000000000000000000000002004") + console.log("\tvotingPeriod", Number(votingPeriod)); + console.log("\tminPeriodAfterQuorum", Number(minPeriodAfterQuorum)); } // 9.cmd: "getEip7623", usage: diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 15f281507a..2bf32ab5c1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -306,6 +306,11 @@ var ( Usage: "Manually specify the Lorentz fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } + OverrideMaxwell = &cli.Uint64Flag{ + Name: "override.maxwell", + Usage: "Manually specify the Maxwell fork timestamp, overriding the bundled setting", + Category: flags.EthCategory, + } OverrideVerkle = &cli.Uint64Flag{ Name: "override.verkle", Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", @@ -642,7 +647,7 @@ var ( MinerDelayLeftoverFlag = &cli.DurationFlag{ Name: "miner.delayleftover", Usage: "Time reserved to finalize a block", - Value: ethconfig.Defaults.Miner.DelayLeftOver, + Value: *ethconfig.Defaults.Miner.DelayLeftOver, Category: flags.MinerCategory, } @@ -1860,7 +1865,8 @@ func setMiner(ctx *cli.Context, cfg *minerconfig.Config) { cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name) } if ctx.IsSet(MinerDelayLeftoverFlag.Name) { - cfg.DelayLeftOver = ctx.Duration(MinerDelayLeftoverFlag.Name) + minerDelayLeftover := ctx.Duration(MinerDelayLeftoverFlag.Name) + cfg.DelayLeftOver = &minerDelayLeftover } if ctx.Bool(VotingEnabledFlag.Name) { cfg.VoteEnable = true diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index c077090287..382ce67a1e 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -83,7 +83,7 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { var frac uint64 switch config.LatestFork(header.Time) { - case forks.Lorentz, forks.Prague: + case forks.Maxwell, forks.Lorentz, forks.Prague: frac = config.BlobScheduleConfig.Prague.UpdateFraction case forks.Cancun: frac = config.BlobScheduleConfig.Cancun.UpdateFraction diff --git a/core/genesis.go b/core/genesis.go index e52bd1fb95..190c83bb3b 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -265,6 +265,7 @@ func (e *GenesisMismatchError) Error() string { type ChainOverrides struct { OverridePassedForkTime *uint64 OverrideLorentz *uint64 + OverrideMaxwell *uint64 OverrideVerkle *uint64 } @@ -288,6 +289,9 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error { if o.OverrideLorentz != nil { cfg.LorentzTime = o.OverrideLorentz } + if o.OverrideMaxwell != nil { + cfg.MaxwellTime = o.OverrideMaxwell + } if o.OverrideVerkle != nil { cfg.VerkleTime = o.OverrideVerkle } diff --git a/core/rawdb/prunedfreezer.go b/core/rawdb/prunedfreezer.go index 86856ff7ad..f15eb8ea13 100644 --- a/core/rawdb/prunedfreezer.go +++ b/core/rawdb/prunedfreezer.go @@ -30,7 +30,7 @@ type prunedfreezer struct { closeOnce sync.Once } -// newNoDataFreezer creates a chain freezer that deletes data enough ‘old’. +// newPrunedFreezer creates a chain freezer that deletes data enough ‘old’. func newPrunedFreezer(datadir string, db ethdb.KeyValueStore, offset uint64) (*prunedfreezer, error) { if info, err := os.Lstat(datadir); !os.IsNotExist(err) { if info.Mode()&os.ModeSymlink != 0 { diff --git a/core/types/bid.go b/core/types/bid.go index b457c44caf..403f5de1e5 100644 --- a/core/types/bid.go +++ b/core/types/bid.go @@ -202,6 +202,7 @@ type MevParams struct { ValidatorCommission uint64 // 100 means 1% BidSimulationLeftOver time.Duration NoInterruptLeftOver time.Duration + MaxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block GasCeil uint64 GasPrice *big.Int // Minimum avg gas price for bid block BuilderFeeCeil *big.Int diff --git a/eth/backend.go b/eth/backend.go index 5f81b60701..9c84faeee9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -213,6 +213,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainConfig.LorentzTime = config.OverrideLorentz overrides.OverrideLorentz = config.OverrideLorentz } + if config.OverrideMaxwell != nil { + chainConfig.MaxwellTime = config.OverrideMaxwell + overrides.OverrideMaxwell = config.OverrideMaxwell + } if config.OverrideVerkle != nil { chainConfig.VerkleTime = config.OverrideVerkle overrides.OverrideVerkle = config.OverrideVerkle diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index a241a9c03f..de3fc353c1 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -188,6 +188,9 @@ type Config struct { // OverrideLorentz (TODO: remove after the fork) OverrideLorentz *uint64 `toml:",omitempty"` + // OverrideMaxwell (TODO: remove after the fork) + OverrideMaxwell *uint64 `toml:",omitempty"` + // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` @@ -212,3 +215,12 @@ func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database, ee *et } return beacon.New(ethash.NewFaker()), nil } + +func ApplyDefaultEthConfig(cfg *Config) { + if cfg == nil { + log.Warn("ApplyDefaultEthConfig cfg == nil") + return + } + + minerconfig.ApplyDefaultMinerConfig(&cfg.Miner) +} diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 535244ca43..b834241706 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -65,6 +65,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCTxFeeCap float64 OverridePassedForkTime *uint64 `toml:",omitempty"` OverrideLorentz *uint64 `toml:",omitempty"` + OverrideMaxwell *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` BlobExtraReserve uint64 } @@ -118,6 +119,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.OverridePassedForkTime = c.OverridePassedForkTime enc.OverrideLorentz = c.OverrideLorentz + enc.OverrideMaxwell = c.OverrideMaxwell enc.OverrideVerkle = c.OverrideVerkle enc.BlobExtraReserve = c.BlobExtraReserve return &enc, nil @@ -175,6 +177,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCTxFeeCap *float64 OverridePassedForkTime *uint64 `toml:",omitempty"` OverrideLorentz *uint64 `toml:",omitempty"` + OverrideMaxwell *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` BlobExtraReserve *uint64 } @@ -329,6 +332,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideLorentz != nil { c.OverrideLorentz = dec.OverrideLorentz } + if dec.OverrideMaxwell != nil { + c.OverrideMaxwell = dec.OverrideMaxwell + } if dec.OverrideVerkle != nil { c.OverrideVerkle = dec.OverrideVerkle } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cd3f26c473..fdd3f85352 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/common/gopool" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" - cmath "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core" @@ -544,9 +543,9 @@ func (api *BlockChainAPI) getFinalizedNumber(ctx context.Context, verifiedValida } valLen := len(curValidators) if verifiedValidatorNum == -1 { - verifiedValidatorNum = int64(cmath.CeilDiv(valLen, 2)) + verifiedValidatorNum = int64(math.CeilDiv(valLen, 2)) } else if verifiedValidatorNum == -2 { - verifiedValidatorNum = int64(cmath.CeilDiv(valLen*2, 3)) + verifiedValidatorNum = int64(math.CeilDiv(valLen*2, 3)) } else if verifiedValidatorNum == -3 { verifiedValidatorNum = int64(valLen) } else if verifiedValidatorNum < 1 || verifiedValidatorNum > int64(valLen) { diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 6715dac83b..9d0655da85 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -201,7 +201,7 @@ func (exp *exp) publishResettingTimer(name string, metric *metrics.ResettingTime } func (exp *exp) publishLabel(name string, metric *metrics.Label) { - labels := metric.Value() + labels := metric.Snapshot().Value() for k, v := range labels { exp.getMap(name).Set(k, exp.interfaceToExpVal(v)) } diff --git a/metrics/label.go b/metrics/label.go index a78f73952b..56af8ced0c 100644 --- a/metrics/label.go +++ b/metrics/label.go @@ -1,8 +1,24 @@ package metrics +import ( + "maps" + "sync" +) + +// LabelValue is a mapping of keys to values +type LabelValue map[string]any + +// LabelSnapshot is a read-only copy of a Label. +type LabelSnapshot LabelValue + +// Value returns the value at the time the snapshot was taken. +func (l LabelSnapshot) Value() LabelValue { return LabelValue(l) } + // Label is the standard implementation of a Label. type Label struct { - value map[string]interface{} + value LabelValue + + mutex sync.Mutex } // GetOrRegisterLabel returns an existing Label or constructs and registers a @@ -16,16 +32,21 @@ func GetOrRegisterLabel(name string, r Registry) *Label { // NewLabel constructs a new Label. func NewLabel() *Label { - return &Label{value: make(map[string]interface{})} + return &Label{value: make(map[string]any)} } // Value returns label values. -func (l *Label) Value() map[string]interface{} { - return l.value +func (l *Label) Snapshot() *LabelSnapshot { + l.mutex.Lock() + defer l.mutex.Unlock() + snapshot := LabelSnapshot(maps.Clone(l.value)) + return &snapshot } // Mark records the label. func (l *Label) Mark(value map[string]interface{}) { + l.mutex.Lock() + defer l.mutex.Unlock() for k, v := range value { l.value[k] = v } diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index de4001970e..3e138e5ea2 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -71,7 +71,7 @@ func (c *collector) Add(name string, i any) error { case *metrics.ResettingTimer: c.addResettingTimer(name, m.Snapshot()) case *metrics.Label: - c.addLabel(name, m) + c.addLabel(name, m.Snapshot()) default: return fmt.Errorf("unknown prometheus metric type %T", i) } @@ -138,9 +138,10 @@ func (c *collector) addResettingTimer(name string, m *metrics.ResettingTimerSnap c.buff.WriteRune('\n') } -func (c *collector) addLabel(name string, m *metrics.Label) { - labels := make([]string, 0, len(m.Value())) - for k, v := range m.Value() { +func (c *collector) addLabel(name string, m *metrics.LabelSnapshot) { + labelValue := m.Value() + labels := make([]string, 0, len(labelValue)) + for k, v := range labelValue { labels = append(labels, fmt.Sprintf(`%s="%s"`, mutateKey(k), fmt.Sprint(v))) } c.writeLabel(mutateKey(name), "{"+strings.Join(labels, ", ")+"}") diff --git a/miner/bid_simulator.go b/miner/bid_simulator.go index 8068fd6261..da5be60841 100644 --- a/miner/bid_simulator.go +++ b/miner/bid_simulator.go @@ -119,38 +119,36 @@ type bidSimulator struct { func newBidSimulator( config *minerconfig.MevConfig, - delayLeftOver time.Duration, + delayLeftOver *time.Duration, minGasPrice *big.Int, eth Backend, chainConfig *params.ChainConfig, engine consensus.Engine, bidWorker bidWorker, ) *bidSimulator { - // Set default value - maxBids := uint32(3) - if config.MaxBidsPerBuilder > 0 { - maxBids = config.MaxBidsPerBuilder - } - b := &bidSimulator{ - config: config, - delayLeftOver: delayLeftOver, - minGasPrice: minGasPrice, - chain: eth.BlockChain(), - txpool: eth.TxPool(), - chainConfig: chainConfig, - engine: engine, - bidWorker: bidWorker, - maxBidsPerBuilder: maxBids, - exitCh: make(chan struct{}), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - builders: make(map[common.Address]*builderclient.Client), - simBidCh: make(chan *simBidReq), - newBidCh: make(chan newBidPackage, 100), - pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), - bestBid: make(map[common.Hash]*BidRuntime), - bestBidToRun: make(map[common.Hash]*types.Bid), - simulatingBid: make(map[common.Hash]*BidRuntime), + config: config, + minGasPrice: minGasPrice, + chain: eth.BlockChain(), + txpool: eth.TxPool(), + chainConfig: chainConfig, + engine: engine, + bidWorker: bidWorker, + exitCh: make(chan struct{}), + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + builders: make(map[common.Address]*builderclient.Client), + simBidCh: make(chan *simBidReq), + newBidCh: make(chan newBidPackage, 100), + pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), + bestBid: make(map[common.Hash]*BidRuntime), + bestBidToRun: make(map[common.Hash]*types.Bid), + simulatingBid: make(map[common.Hash]*BidRuntime), + } + if delayLeftOver != nil { + b.delayLeftOver = *delayLeftOver + } + if config.MaxBidsPerBuilder != nil { + b.maxBidsPerBuilder = *config.MaxBidsPerBuilder } b.chainHeadSub = b.chain.SubscribeChainHeadEvent(b.chainHeadCh) @@ -360,7 +358,7 @@ func (b *bidSimulator) canBeInterrupted(targetTime uint64) bool { return true } left := time.Until(time.UnixMilli(int64(targetTime))) - return left >= b.config.NoInterruptLeftOver + return left >= *b.config.NoInterruptLeftOver } func (b *bidSimulator) newBidLoop() { @@ -396,7 +394,7 @@ func (b *bidSimulator) newBidLoop() { continue } - bidRuntime, err := newBidRuntime(newBid.bid, b.config.ValidatorCommission) + bidRuntime, err := newBidRuntime(newBid.bid, *b.config.ValidatorCommission) if err != nil { if newBid.feedback != nil { newBid.feedback <- err @@ -408,7 +406,7 @@ func (b *bidSimulator) newBidLoop() { toCommit := true bestBidToRun := b.GetBestBidToRun(newBid.bid.ParentHash) if bestBidToRun != nil { - bestBidRuntime, _ := newBidRuntime(bestBidToRun, b.config.ValidatorCommission) + bestBidRuntime, _ := newBidRuntime(bestBidToRun, *b.config.ValidatorCommission) if bidRuntime.isExpectedBetterThan(bestBidRuntime) { // new bid has better expectedBlockReward, use bidRuntime log.Debug("new bid has better expectedBlockReward", @@ -494,7 +492,7 @@ func (b *bidSimulator) getBlockInterval(parentHeader *types.Header) uint64 { func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time { parentHeader := b.chain.GetHeaderByHash(parentHash) - return bidutil.BidBetterBefore(parentHeader, b.getBlockInterval(parentHeader), b.delayLeftOver, b.config.BidSimulationLeftOver) + return bidutil.BidBetterBefore(parentHeader, b.getBlockInterval(parentHeader), b.delayLeftOver, *b.config.BidSimulationLeftOver) } func (b *bidSimulator) clearLoop() { @@ -739,7 +737,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) { // check if bid reward is valid { - bidRuntime.packReward(b.config.ValidatorCommission) + bidRuntime.packReward(*b.config.ValidatorCommission) if !bidRuntime.validReward() { err = errors.New("reward does not achieve the expectation") return @@ -786,7 +784,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) { } // if enable greedy merge, fill bid env with transactions from mempool - if b.config.GreedyMergeTx { + if *b.config.GreedyMergeTx { endingBidsExtra := 20 * time.Millisecond // Add a buffer to ensure ending bids before `delayLeftOver` minTimeLeftForEndingBids := b.delayLeftOver + endingBidsExtra delay := b.engine.Delay(b.chain, bidRuntime.env.header, &minTimeLeftForEndingBids) @@ -802,7 +800,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) { "builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr) // recalculate the packed reward - bidRuntime.packReward(b.config.ValidatorCommission) + bidRuntime.packReward(*b.config.ValidatorCommission) } } diff --git a/miner/miner_mev.go b/miner/miner_mev.go index 9e5619a9ce..8be14b904d 100644 --- a/miner/miner_mev.go +++ b/miner/miner_mev.go @@ -97,9 +97,10 @@ func (miner *Miner) MevParams() *types.MevParams { } return &types.MevParams{ - ValidatorCommission: miner.worker.config.Mev.ValidatorCommission, - BidSimulationLeftOver: miner.worker.config.Mev.BidSimulationLeftOver, - NoInterruptLeftOver: miner.worker.config.Mev.NoInterruptLeftOver, + ValidatorCommission: *miner.worker.config.Mev.ValidatorCommission, + BidSimulationLeftOver: *miner.worker.config.Mev.BidSimulationLeftOver, + NoInterruptLeftOver: *miner.worker.config.Mev.NoInterruptLeftOver, + MaxBidsPerBuilder: *miner.worker.config.Mev.MaxBidsPerBuilder, GasCeil: miner.worker.config.GasCeil, GasPrice: miner.worker.config.GasPrice, BuilderFeeCeil: builderFeeCeil, diff --git a/miner/minerconfig/config.go b/miner/minerconfig/config.go index 00dc7b6b88..7c37112d44 100644 --- a/miner/minerconfig/config.go +++ b/miner/minerconfig/config.go @@ -23,14 +23,25 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) +var ( + defaultDelayLeftOver = 50 * time.Millisecond + // default configurations for MEV + defaultGreedyMergeTx bool = true + defaultValidatorCommission uint64 = 100 + defaultBidSimulationLeftOver = 50 * time.Millisecond + defaultNoInterruptLeftOver = 250 * time.Millisecond + defaultMaxBidsPerBuilder uint32 = 2 +) + // Config is the configuration parameters of mining. type Config struct { Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner - DelayLeftOver time.Duration // Time reserved to finalize a block(calculate root, distribute income...) + DelayLeftOver *time.Duration `toml:",omitempty"` // Time reserved to finalize a block(calculate root, distribute income...) GasFloor uint64 // Target gas floor for mined blocks. GasCeil uint64 // Target gas ceiling for mined blocks. GasPrice *big.Int // Minimum gas price for mining a transaction @@ -53,7 +64,7 @@ var DefaultConfig = Config{ // for payload generation. It should be enough for Geth to // run 3 rounds. Recommit: 3 * time.Second, - DelayLeftOver: 50 * time.Millisecond, + DelayLeftOver: &defaultDelayLeftOver, // The default value is set to 30 seconds. // Because the avg restart time in mainnet is around 30s, so the node try to wait for the next multi-proposals to be done. @@ -69,23 +80,57 @@ type BuilderConfig struct { type MevConfig struct { Enabled bool // Whether to enable Mev or not - GreedyMergeTx bool // Whether to merge local transactions to the bid + GreedyMergeTx *bool `toml:",omitempty"` // Whether to merge local transactions to the bid BuilderFeeCeil string // The maximum builder fee of a bid SentryURL string // The url of Mev sentry Builders []BuilderConfig // The list of builders - ValidatorCommission uint64 // 100 means the validator claims 1% from block reward - BidSimulationLeftOver time.Duration - NoInterruptLeftOver time.Duration - MaxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block + ValidatorCommission *uint64 `toml:",omitempty"` // 100 means the validator claims 1% from block reward + BidSimulationLeftOver *time.Duration `toml:",omitempty"` + NoInterruptLeftOver *time.Duration `toml:",omitempty"` + MaxBidsPerBuilder *uint32 `toml:",omitempty"` // Maximum number of bids allowed per builder per block } var DefaultMevConfig = MevConfig{ Enabled: false, - GreedyMergeTx: true, + GreedyMergeTx: &defaultGreedyMergeTx, SentryURL: "", Builders: nil, - ValidatorCommission: 100, - BidSimulationLeftOver: 50 * time.Millisecond, - NoInterruptLeftOver: 400 * time.Millisecond, - MaxBidsPerBuilder: 3, + ValidatorCommission: &defaultValidatorCommission, + BidSimulationLeftOver: &defaultBidSimulationLeftOver, + NoInterruptLeftOver: &defaultNoInterruptLeftOver, + MaxBidsPerBuilder: &defaultMaxBidsPerBuilder, +} + +func ApplyDefaultMinerConfig(cfg *Config) { + if cfg == nil { + log.Warn("ApplyDefaultMinerConfig cfg == nil") + return + } + // check [Eth.Miner] + if cfg.DelayLeftOver == nil { + cfg.DelayLeftOver = &defaultDelayLeftOver + log.Info("ApplyDefaultMinerConfig", "DelayLeftOver", *cfg.DelayLeftOver) + } + + // check [Eth.Miner.Mev] + if cfg.Mev.GreedyMergeTx == nil { + cfg.Mev.GreedyMergeTx = &defaultGreedyMergeTx + log.Info("ApplyDefaultMinerConfig", "Mev.GreedyMergeTx", *cfg.Mev.GreedyMergeTx) + } + if cfg.Mev.ValidatorCommission == nil { + cfg.Mev.ValidatorCommission = &defaultValidatorCommission + log.Info("ApplyDefaultMinerConfig", "Mev.ValidatorCommission", *cfg.Mev.ValidatorCommission) + } + if cfg.Mev.BidSimulationLeftOver == nil { + cfg.Mev.BidSimulationLeftOver = &defaultBidSimulationLeftOver + log.Info("ApplyDefaultMinerConfig", "Mev.BidSimulationLeftOver", *cfg.Mev.BidSimulationLeftOver) + } + if cfg.Mev.NoInterruptLeftOver == nil { + cfg.Mev.NoInterruptLeftOver = &defaultNoInterruptLeftOver + log.Info("ApplyDefaultMinerConfig", "Mev.NoInterruptLeftOver", *cfg.Mev.NoInterruptLeftOver) + } + if cfg.Mev.MaxBidsPerBuilder == nil { + cfg.Mev.MaxBidsPerBuilder = &defaultMaxBidsPerBuilder + log.Info("ApplyDefaultMinerConfig", "Mev.MaxBidsPerBuilder", *cfg.Mev.MaxBidsPerBuilder) + } } diff --git a/miner/worker.go b/miner/worker.go index 89dedca337..8a5bb0ebe1 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1292,7 +1292,7 @@ LOOP: prevWork = work workList = append(workList, work) - delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + delay := w.engine.Delay(w.chain, work.header, w.config.DelayLeftOver) if delay == nil { log.Warn("commitWork delay is nil, something is wrong") stopTimer = nil @@ -1345,7 +1345,7 @@ LOOP: newTxsNum := 0 // stopTimer was the maximum delay for each fillTransactions // but now it is used to wait until (head.Time - DelayLeftOver) is reached. - stopTimer.Reset(time.Until(time.UnixMilli(int64(work.header.MilliTimestamp()))) - w.config.DelayLeftOver) + stopTimer.Reset(time.Until(time.UnixMilli(int64(work.header.MilliTimestamp()))) - *w.config.DelayLeftOver) LOOP_WAIT: for { select { @@ -1356,7 +1356,7 @@ LOOP: log.Debug("commitWork interruptCh closed, new block imported or resubmit triggered") return case ev := <-txsCh: - delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + delay := w.engine.Delay(w.chain, work.header, w.config.DelayLeftOver) log.Debug("commitWork txsCh arrived", "fillDuration", fillDuration.String(), "delay", delay.String(), "work.tcount", work.tcount, "newTxsNum", newTxsNum, "len(ev.Txs)", len(ev.Txs)) @@ -1411,7 +1411,7 @@ LOOP: inturnBlocksGauge.Inc(1) // We want to start sealing the block as late as possible here if mev is enabled, so we could give builder the chance to send their final bid. // Time left till sealing the block. - tillSealingTime := time.Until(time.UnixMilli(int64(bestWork.header.MilliTimestamp()))) - w.config.DelayLeftOver + tillSealingTime := time.Until(time.UnixMilli(int64(bestWork.header.MilliTimestamp()))) - *w.config.DelayLeftOver if tillSealingTime > 0 { // Still some time left, wait for the best bid. // This happens during the peak time of the network, the local block building LOOP would break earlier than @@ -1441,7 +1441,7 @@ LOOP: if bestBid != nil && bestReward.CmpBig(bestBid.packedBlockReward) < 0 { // localValidatorReward is the reward for the validator self by the local block. - localValidatorReward := new(uint256.Int).Mul(bestReward, uint256.NewInt(w.config.Mev.ValidatorCommission)) + localValidatorReward := new(uint256.Int).Mul(bestReward, uint256.NewInt(*w.config.Mev.ValidatorCommission)) localValidatorReward.Div(localValidatorReward, uint256.NewInt(10000)) log.Debug("BidSimulator: final compare", "block", bestWork.header.Number.Uint64(), diff --git a/params/config.go b/params/config.go index e1d2f00ec7..2524ae77c8 100644 --- a/params/config.go +++ b/params/config.go @@ -190,6 +190,7 @@ var ( PascalTime: newUint64(1742436600), // 2025-03-20 02:10:00 AM UTC PragueTime: newUint64(1742436600), // 2025-03-20 02:10:00 AM UTC LorentzTime: newUint64(1745903100), // 2025-04-29 05:05:00 AM UTC + MaxwellTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -235,6 +236,7 @@ var ( PascalTime: newUint64(1740452880), // 2025-02-25 03:08:00 AM UTC PragueTime: newUint64(1740452880), // 2025-02-25 03:08:00 AM UTC LorentzTime: newUint64(1744097580), // 2025-04-08 07:33:00 AM UTC + MaxwellTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -282,6 +284,7 @@ var ( PragueTime: newUint64(0), // TODO: set them to `0` when passed on the mainnet LorentzTime: nil, + MaxwellTime: nil, Parlia: &ParliaConfig{}, BlobScheduleConfig: &BlobScheduleConfig{ @@ -599,6 +602,7 @@ type ChainConfig struct { PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) LorentzTime *uint64 `json:"lorentzTime,omitempty"` // Lorentz switch time (nil = no fork, 0 = already on lorentz) + MaxwellTime *uint64 `json:"maxwellTime,omitempty"` // Maxwell switch time (nil = no fork, 0 = already on maxwell) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -765,7 +769,12 @@ func (c *ChainConfig) String() string { LorentzTime = big.NewInt(0).SetUint64(*c.LorentzTime) } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, CancunTime: %v, HaberTime: %v, HaberFixTime: %v, BohrTime: %v, PascalTime: %v, PragueTime: %v, LorentzTime: %v, Engine: %v}", + var MaxwellTime *big.Int + if c.MaxwellTime != nil { + MaxwellTime = big.NewInt(0).SetUint64(*c.MaxwellTime) + } + + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, CancunTime: %v, HaberTime: %v, HaberFixTime: %v, BohrTime: %v, PascalTime: %v, PragueTime: %v, LorentzTime: %v, MaxwellTime: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -808,6 +817,7 @@ func (c *ChainConfig) String() string { PascalTime, PragueTime, LorentzTime, + MaxwellTime, engine, ) } @@ -1164,6 +1174,20 @@ func (c *ChainConfig) IsOnLorentz(currentBlockNumber *big.Int, lastBlockTime uin return !c.IsLorentz(lastBlockNumber, lastBlockTime) && c.IsLorentz(currentBlockNumber, currentBlockTime) } +// IsMaxwell returns whether time is either equal to the Maxwell fork time or greater. +func (c *ChainConfig) IsMaxwell(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.MaxwellTime, time) +} + +// IsOnMaxwell returns whether currentBlockTime is either equal to the Maxwell fork time or greater firstly. +func (c *ChainConfig) IsOnMaxwell(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool { + lastBlockNumber := new(big.Int) + if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 { + lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1)) + } + return !c.IsMaxwell(lastBlockNumber, lastBlockTime) && c.IsMaxwell(currentBlockNumber, currentBlockTime) +} + // IsOsaka returns whether time is either equal to the Osaka fork time or greater. func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time) @@ -1253,6 +1277,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "pragueTime", timestamp: c.PragueTime}, {name: "osakaTime", timestamp: c.OsakaTime, optional: true}, {name: "lorentzTime", timestamp: c.LorentzTime}, + {name: "maxwellTime", timestamp: c.MaxwellTime}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, } { if lastFork.name != "" { @@ -1459,6 +1484,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.LorentzTime, newcfg.LorentzTime, headTimestamp) { return newTimestampCompatError("Lorentz fork timestamp", c.LorentzTime, newcfg.LorentzTime) } + if isForkTimestampIncompatible(c.MaxwellTime, newcfg.MaxwellTime, headTimestamp) { + return newTimestampCompatError("Lorentz fork timestamp", c.MaxwellTime, newcfg.MaxwellTime) + } if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) } @@ -1484,6 +1512,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { switch { case c.IsOsaka(london, time): return forks.Osaka + case c.IsMaxwell(london, time): + return forks.Maxwell case c.IsLorentz(london, time): return forks.Lorentz case c.IsPrague(london, time): @@ -1646,8 +1676,8 @@ type Rules struct { IsHertz bool IsHertzfix bool IsShanghai, IsKepler, IsFeynman, IsCancun, IsHaber bool - IsBohr, IsPascal, IsPrague, IsLorentz, IsOsaka bool - IsVerkle bool + IsBohr, IsPascal, IsPrague, IsLorentz, IsMaxwell bool + IsOsaka, IsVerkle bool } // Rules ensures c's ChainID is not nil. @@ -1690,6 +1720,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsPrague: c.IsPrague(num, timestamp), IsOsaka: c.IsOsaka(num, timestamp), IsLorentz: c.IsLorentz(num, timestamp), + IsMaxwell: c.IsMaxwell(num, timestamp), IsVerkle: c.IsVerkle(num, timestamp), IsEIP4762: isVerkle, } diff --git a/params/forks/forks.go b/params/forks/forks.go index de6ffa4d26..77accf942e 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -40,5 +40,6 @@ const ( Cancun Prague Lorentz + Maxwell Osaka ) diff --git a/version/version.go b/version/version.go index b37b6b9adb..8e6d3fde67 100644 --- a/version/version.go +++ b/version/version.go @@ -19,6 +19,6 @@ package version const ( Major = 1 // Major version component of the current release Minor = 5 // Minor version component of the current release - Patch = 10 // Patch version component of the current release + Patch = 11 // Patch version component of the current release Meta = "" // Version metadata to append to the version string )