From 00875f43ceed12c4024b874098d2e9d92470b249 Mon Sep 17 00:00:00 2001 From: buddh0 Date: Tue, 24 Sep 2024 18:07:15 +0800 Subject: [PATCH] BEP-440: Implement EIP-2935: Serve historical block hashes from state --- 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 | 64 +++++++++++++--------------- miner/worker.go | 11 +++-- params/config.go | 11 ++++- 9 files changed, 76 insertions(+), 63 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 176c742b9a..fc3d75fe6f 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -1287,9 +1287,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.ModifyBuildInSystemContract(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) @@ -1374,9 +1372,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.ModifyBuildInSystemContract(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, &body.Transactions, &receipts, nil, &header.GasUsed, true) diff --git a/core/chain_makers.go b/core/chain_makers.go index 27bf4e02b3..048f86d89a 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -363,9 +363,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.ModifyBuildInSystemContract(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 1773e9d3c0..46d75ff745 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -76,10 +76,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if lastBlock == nil { return nil, 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.ModifyBuildInSystemContract(p.config, blockNumber, lastBlock.Time, block.Time(), statedb, true) var ( context vm.BlockContext diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index ac5bdfd2be..4599e46699 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -1050,7 +1050,25 @@ func init() { } } -func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB) { +func ModifyBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB, atBlockBegin bool) { + if atBlockBegin { + if !config.IsFeynman(blockNumber, lastBlockTime) { + upgradeBuildInSystemContract(config, blockNumber, lastBlockTime, blockTime, statedb) + } + // HistoryStorageAddress is a special system contract in bsc, which can't be upgraded + if config.IsOnPrague(blockNumber, lastBlockTime, blockTime) { + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.SetNonce(params.HistoryStorageAddress, 1) + log.Info("Set code for HistoryStorageAddress", "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 } @@ -1144,7 +1162,7 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb vm.StateDB, logger log.Logger) { if upgrade == nil { - logger.Info("Empty upgrade config", "height", blockNumber.String()) + logger.Info(fmt.Sprintf("Empty upgrade %s at height %d", upgrade.UpgradeName, blockNumber.Int64())) 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 43396867a9..4c54e651ff 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -242,15 +242,14 @@ 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.ModifyBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb, true) // Insert parent beacon block root in the state as per EIP-4788. if beaconRoot := block.BeaconRoot(); beaconRoot != nil { context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, 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) @@ -276,9 +275,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, statedb.AddBalance(block.Header().Coinbase, balance, tracing.BalanceChangeUnspecified) } - if eth.blockchain.Config().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(eth.blockchain.Config(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.ModifyBuildInSystemContract(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 8209033f58..579e45c30f 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -288,9 +288,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed task.statedb.AddBalance(blockCtx.Coinbase, balance, tracing.BalanceChangeUnspecified) } - 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.ModifyBuildInSystemContract(api.backend.ChainConfig(), task.block.Number(), task.parent.Time(), task.block.Time(), task.statedb, false) beforeSystemTx = false } } @@ -422,9 +420,19 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed 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) + systemcontracts.ModifyBuildInSystemContract(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) + 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() @@ -563,9 +571,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.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) var ( roots []common.Hash @@ -592,16 +598,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), tracing.BalanceChangeUnspecified) - statedb.AddBalance(vmctx.Coinbase, balance, tracing.BalanceChangeUnspecified) - } + 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), tracing.BalanceChangeUnspecified) + statedb.AddBalance(vmctx.Coinbase, balance, tracing.BalanceChangeUnspecified) + } - if beforeSystemTx && api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) + systemcontracts.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -661,9 +667,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.ModifyBuildInSystemContract(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 @@ -702,9 +706,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac statedb.AddBalance(blockCtx.Coinbase, balance, tracing.BalanceChangeUnspecified) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -795,9 +797,7 @@ txloop: statedb.AddBalance(block.Header().Coinbase, balance, tracing.BalanceChangeUnspecified) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -863,9 +863,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.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, true) // Retrieve the tracing configurations, or use default values var ( @@ -915,9 +913,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block statedb.AddBalance(vmctx.Coinbase, balance, tracing.BalanceChangeUnspecified) } - if api.backend.ChainConfig().IsFeynman(block.Number(), block.Time()) { - systemcontracts.UpgradeBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb) - } + systemcontracts.ModifyBuildInSystemContract(api.backend.ChainConfig(), block.Number(), parent.Time(), block.Time(), statedb, false) beforeSystemTx = false } } @@ -1099,9 +1095,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.ModifyBuildInSystemContract(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 d193ccca3c..116b1c8bb0 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1042,16 +1042,19 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm 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.ModifyBuildInSystemContract(w.chainConfig, header.Number, parent.Time, header.Time, env.state, true) if header.ParentBeaconRoot != nil { context := core.NewEVMBlockContext(header, w.chain, nil) 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) + } if w.chainConfig.IsPrague(header.Number, header.Time) { context := core.NewEVMBlockContext(header, w.chain, nil) diff --git a/params/config.go b/params/config.go index f26fa0790c..f8fdbb243d 100644 --- a/params/config.go +++ b/params/config.go @@ -1024,7 +1024,16 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } -// IsVerkle returns whether time is either equal to the Verkle fork time or greater. +// 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) }