From 2e1b0dd3ddd7baced918b56ac1841344882c944a Mon Sep 17 00:00:00 2001 From: buddh0 Date: Tue, 24 Sep 2024 18:07:15 +0800 Subject: [PATCH 1/2] BEP-440: Implement EIP-2935: Serve historical block hashes from state --- cmd/evm/internal/t8ntool/execution.go | 9 ++++- core/blockchain.go | 5 ++- core/genesis.go | 2 + core/state_processor.go | 21 ++++++++++ core/state_processor_test.go | 55 +++++++++++++++++++++++++++ eth/state_accessor.go | 6 +++ eth/tracers/api.go | 27 ++++++++++--- miner/worker.go | 5 +++ params/protocol_params.go | 6 +++ 9 files changed, 128 insertions(+), 8 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 1decb81934..df1f4d4148 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -192,7 +192,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } - + if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { + var ( + prevNumber = pre.Env.Number - 1 + prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) + ) + core.ProcessParentBlockHash(prevHash, evm, statedb) + } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index b2a56d74bf..7990a9232d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -177,11 +177,12 @@ type CacheConfig struct { } // triedbConfig derives the configures for trie database. -func (c *CacheConfig) triedbConfig() *triedb.Config { +func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config { config := &triedb.Config{ Cache: c.TrieCleanLimit, Preimages: c.Preimages, NoTries: c.NoTries, + IsVerkle: isVerkle, } if c.StateScheme == rawdb.HashScheme { config.HashDB = &hashdb.Config{ @@ -340,7 +341,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis diffLayerChanCache, _ := exlru.New(diffLayerCacheLimit) // Open trie database with provided config - triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig()) + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(false)) // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the diff --git a/core/genesis.go b/core/genesis.go index 02d27031fd..8da5c93438 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -589,6 +589,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b + // Pre-deploy EIP-2935 history contract. + params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode}, }, } if faucet != nil { diff --git a/core/state_processor.go b/core/state_processor.go index 9ef227ccc2..a4e6511399 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -92,6 +92,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if p.config.IsPrague(block.Number(), block.Time()) { + ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } // Iterate over and process the individual transactions posa, isPoSA := p.engine.(consensus.PoSA) commonTxs := make([]*types.Transaction, 0, txNum) @@ -254,3 +257,21 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } + +// ProcessParentBlockHash stores the parent block hash in the history storage contract +// as per EIP-2935. +func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { + msg := &Message{ + From: params.SystemAddress, + GasLimit: 30_000_000, + GasPrice: common.Big0, + GasFeeCap: common.Big0, + GasTipCap: common.Big0, + To: ¶ms.HistoryStorageAddress, + Data: prevHash.Bytes(), + } + vmenv.Reset(NewEVMTxContext(msg), statedb) + statedb.AddAddressToAccessList(params.HistoryStorageAddress) + _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + statedb.Finalise(true) +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index f87997c7ed..141b7a633e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -18,6 +18,7 @@ package core import ( "crypto/ecdsa" + "encoding/binary" "errors" "math/big" "testing" @@ -30,11 +31,14 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -429,3 +433,54 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) } + +func TestProcessParentBlockHash(t *testing.T) { + var ( + chainConfig = params.MergedTestChainConfig + hashA = common.Hash{0x01} + hashB = common.Hash{0x02} + header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)} + parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)} + coinbase = common.Address{} + ) + test := func(statedb *state.StateDB) { + statedb.SetNonce(params.HistoryStorageAddress, 1) + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.IntermediateRoot(true) + + vmContext := NewEVMBlockContext(header, nil, &coinbase) + evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(header.ParentHash, evm, statedb) + + vmContext = NewEVMBlockContext(parent, nil, &coinbase) + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(parent.ParentHash, evm, statedb) + + // make sure that the state is correct + if have := getParentBlockHash(statedb, 1); have != hashA { + t.Errorf("want parent hash %v, have %v", hashA, have) + } + if have := getParentBlockHash(statedb, 0); have != hashB { + t.Errorf("want parent hash %v, have %v", hashB, have) + } + } + t.Run("MPT", func(t *testing.T) { + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + test(statedb) + }) + t.Run("Verkle", func(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig.SnapshotLimit = 0 + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) + statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + test(statedb) + }) +} + +func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash { + ringIndex := number % params.HistoryServeWindow + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + return statedb.GetState(params.HistoryStorageAddress, key) +} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 946b292926..e2fee88546 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -245,6 +245,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, if !eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) { systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb) } + // If prague hardfork, insert parent block hash in the state as per EIP-2935. + if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index f18a8536c2..dba7c4916c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -402,16 +402,22 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed failed = err break } - // Clean out any pending release functions of trace state. Note this - // step must be done after constructing tracing state, because the - // tracing state of block next depends on the parent state and construction - // may fail if we release too early. - tracker.callReleases() // upgrade build-in system contract before normal txs if Feynman is not enabled if !api.backend.ChainConfig().IsFeynman(next.Number(), next.Time()) { systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), next.Number(), block.Time(), next.Time(), statedb) } + // Insert parent hash in history contract. + if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { + context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb) + } + // Clean out any pending release functions of trace state. Note this + // step must be done after constructing tracing state, because the + // tracing state of block next depends on the parent state and construction + // may fail if we release too early. + tracker.callReleases() // Send the block over to the concurrent tracers (if not in the fast-forward phase) txs := next.Transactions() @@ -562,6 +568,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) beforeSystemTx = true ) + if chainConfig.IsPrague(block.Number(), block.Time()) { + core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb) + } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -664,6 +673,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac results = make([]*txTraceResult, len(txs)) beforeSystemTx = true ) + if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } for i, tx := range txs { // upgrade build-in system contract before system txs if Feynman is enabled if beforeSystemTx { @@ -869,6 +882,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } + if chainConfig.IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + } for i, tx := range block.Transactions() { // upgrade build-in system contract before system txs if Feynman is enabled if beforeSystemTx { diff --git a/miner/worker.go b/miner/worker.go index 8513b6a9b6..4ec1145e24 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1071,6 +1071,11 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } + if w.chainConfig.IsPrague(header.Number, header.Time) { + context := core.NewEVMBlockContext(header, w.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) + core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state) + } env.size = uint32(env.header.Size()) diff --git a/params/protocol_params.go b/params/protocol_params.go index a032f2759e..acc4f8415e 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -188,6 +188,8 @@ const ( BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block + + HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) var ( @@ -214,4 +216,8 @@ var ( BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") // SystemAddress is where the system-transaction is sent from as per EIP-4788 SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") + // HistoryStorageAddress is where the historical block hashes are stored. + HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e") + // HistoryStorageCode is the code with getters for historical block hashes. + HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500") ) From 066df1f24e7b3773647d14dc79ce2e79b8b56939 Mon Sep 17 00:00:00 2001 From: buddh0 Date: Wed, 25 Sep 2024 14:13:07 +0800 Subject: [PATCH 2/2] BEP-440: add logic for deployment --- consensus/parlia/parlia.go | 8 +--- core/chain_makers.go | 4 +- core/state_processor.go | 6 +-- core/systemcontracts/upgrade.go | 22 ++++++++++- core/systemcontracts/upgrade_test.go | 4 +- eth/state_accessor.go | 9 ++--- eth/tracers/api.go | 55 ++++++++++------------------ miner/worker.go | 6 +-- params/config.go | 9 +++++ 9 files changed, 61 insertions(+), 62 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 79ff3f93af..34178e8a83 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -1275,9 +1275,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade return errors.New("parent not found") } - if p.chainConfig.IsFeynman(header.Number, header.Time) { - systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state) - } + systemcontracts.HandleBuildInContract(p.chainConfig, header.Number, parent.Time, header.Time, state, false) if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { err := p.initializeFeynmanContract(state, header, cx, txs, receipts, systemTxs, usedGas, false) @@ -1362,9 +1360,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * return nil, nil, errors.New("parent not found") } - if p.chainConfig.IsFeynman(header.Number, header.Time) { - systemcontracts.UpgradeBuildInSystemContract(p.chainConfig, header.Number, parent.Time, header.Time, state) - } + systemcontracts.HandleBuildInContract(p.chainConfig, header.Number, parent.Time, header.Time, state, false) if p.chainConfig.IsOnFeynman(header.Number, parent.Time, header.Time) { err := p.initializeFeynmanContract(state, header, cx, &txs, &receipts, nil, &header.GasUsed, true) diff --git a/core/chain_makers.go b/core/chain_makers.go index 29306c5222..c5d048b86e 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -359,9 +359,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse misc.ApplyDAOHardFork(statedb) } - if !config.IsFeynman(b.header.Number, b.header.Time) { - systemcontracts.UpgradeBuildInSystemContract(config, b.header.Number, parent.Time(), b.header.Time, statedb) - } + systemcontracts.HandleBuildInContract(config, b.header.Number, parent.Time(), b.header.Time, statedb, true) // Execute any user modifications to the block if gen != nil { diff --git a/core/state_processor.go b/core/state_processor.go index a4e6511399..338b2f85dd 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -78,10 +78,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if lastBlock == nil { return statedb, nil, nil, 0, errors.New("could not get parent block") } - if !p.config.IsFeynman(block.Number(), block.Time()) { - // Handle upgrade build-in system contract code - systemcontracts.UpgradeBuildInSystemContract(p.config, blockNumber, lastBlock.Time(), block.Time(), statedb) - } + // Handle upgrade build-in system contract code + systemcontracts.HandleBuildInContract(p.config, blockNumber, lastBlock.Time(), block.Time(), statedb, true) var ( context = NewEVMBlockContext(header, p.bc, nil) diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index f9a776e245..b0a3d25f5a 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -1066,7 +1066,27 @@ func init() { } } -func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB) { +func HandleBuildInContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB, atBlockBegin bool) { + if atBlockBegin { + if !config.IsFeynman(blockNumber, lastBlockTime) { + // Handle upgrade build-in system contract code + upgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) + } + // TODO: `HandleBuildInContract` not suitable in a dir naming `systemcontracts`? + // HistoryStorageAddress is not a system contract and can't be upgraded + if config.IsOnPrague(blockNumber, lastBlockTime, blockTime) { + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.SetNonce(params.HistoryStorageAddress, 1) + log.Info("Apply upgrade prague", "blockNumber", blockNumber.Int64(), "blockTime", blockTime) + } + } else { + if config.IsFeynman(blockNumber, lastBlockTime) { + upgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) + } + } +} + +func upgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB) { if config == nil || blockNumber == nil || statedb == nil || reflect.ValueOf(statedb).IsNil() { return } diff --git a/core/systemcontracts/upgrade_test.go b/core/systemcontracts/upgrade_test.go index 3f88d7687b..8074579729 100644 --- a/core/systemcontracts/upgrade_test.go +++ b/core/systemcontracts/upgrade_test.go @@ -55,7 +55,7 @@ func TestUpgradeBuildInSystemContractNilInterface(t *testing.T) { GenesisHash = params.BSCGenesisHash - UpgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) + upgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) } func TestUpgradeBuildInSystemContractNilValue(t *testing.T) { @@ -69,5 +69,5 @@ func TestUpgradeBuildInSystemContractNilValue(t *testing.T) { GenesisHash = params.BSCGenesisHash - UpgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) + upgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index e2fee88546..eee6199001 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -242,9 +242,8 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, return nil, vm.BlockContext{}, nil, nil, err } // upgrade build-in system contract before normal txs if Feynman is not enabled - if !eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb, true) + // If prague hardfork, insert parent block hash in the state as per EIP-2935. if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) @@ -270,9 +269,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, statedb.AddBalance(block.Header().Coinbase, balance) } - if eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index dba7c4916c..edb99ec767 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -286,9 +286,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed task.statedb.AddBalance(blockCtx.Coinbase, balance) } - if api.backend.ChainConfig().IsFeynman(task.block.Number(), task.block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), task.block.Number(), task.parent.Time(), task.block.Time(), task.statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), task.block.Number(), task.parent.Time(), task.block.Time(), task.statedb, false) beforeSystemTx = false } } @@ -404,9 +402,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed } // upgrade build-in system contract before normal txs if Feynman is not enabled - if !api.backend.ChainConfig().IsFeynman(next.Number(), next.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), next.Number(), block.Time(), next.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), next.Number(), block.Time(), next.Time(), statedb, true) + // Insert parent hash in history contract. if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) @@ -556,9 +553,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config defer release() // upgrade build-in system contract before normal txs if Feynman is not enabled - if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) var ( roots []common.Hash @@ -581,16 +576,16 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) - if posa, ok := api.backend.Engine().(consensus.PoSA); ok { - if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { - balance := statedb.GetBalance(consensus.SystemAddress) - if balance.Cmp(common.U2560) > 0 { - statedb.SetBalance(consensus.SystemAddress, uint256.NewInt(0)) - statedb.AddBalance(vmctx.Coinbase, balance) - } + if beforeSystemTx { + if posa, ok := api.backend.Engine().(consensus.PoSA); ok { + if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { + balance := statedb.GetBalance(consensus.SystemAddress) + if balance.Cmp(common.U2560) > 0 { + statedb.SetBalance(consensus.SystemAddress, uint256.NewInt(0)) + statedb.AddBalance(vmctx.Coinbase, balance) + } - if beforeSystemTx && api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -650,9 +645,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac defer release() // upgrade build-in system contract before normal txs if Feynman is not enabled - if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) // JS tracers have high overhead. In this case run a parallel // process that generates states in one thread and traces txes @@ -688,9 +681,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac statedb.AddBalance(blockCtx.Coinbase, balance) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -780,9 +771,7 @@ txloop: statedb.AddBalance(block.Header().Coinbase, balance) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -848,9 +837,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block defer release() // upgrade build-in system contract before normal txs if Feynman is not enabled - if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) // Retrieve the tracing configurations, or use default values var ( @@ -897,9 +884,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block statedb.AddBalance(vmctx.Coinbase, balance) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -1071,9 +1056,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if err != nil { return nil, err } - if !api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.HandleBuildInContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) } vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) diff --git a/miner/worker.go b/miner/worker.go index 4ec1145e24..71f6312562 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1061,10 +1061,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { return nil, err } - if !w.chainConfig.IsFeynman(header.Number, header.Time) { - // Handle upgrade build-in system contract code - systemcontracts.UpgradeBuildInSystemContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state) - } + // Handle upgrade build-in system contract code + systemcontracts.HandleBuildInContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state, true) if header.ParentBeaconRoot != nil { context := core.NewEVMBlockContext(header, w.chain, nil) diff --git a/params/config.go b/params/config.go index 1c07b294cf..550ef60933 100644 --- a/params/config.go +++ b/params/config.go @@ -1018,6 +1018,15 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } +// IsOnPrague returns whether currentBlockTime is either equal to the Prague fork time or greater firstly. +func (c *ChainConfig) IsOnPrague(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.IsPrague(lastBlockNumber, lastBlockTime) && c.IsPrague(currentBlockNumber, currentBlockTime) +} + // IsVerkle returns whether num is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)