mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
core: refactor StateProcessor to accept ChainContext interface (#32739)
This pr implements https://github.com/ethereum/go-ethereum/issues/32733 to make StateProcessor more customisable. ## Compatibility notes This introduces a breaking change to users using geth EVM as a library. The `NewStateProcessor` function now takes one parameter which has the chainConfig embedded instead of 2 parameters.
This commit is contained in:
parent
f0dc47aae3
commit
fc8c8c1314
10 changed files with 76 additions and 21 deletions
|
|
@ -394,7 +394,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
|
||||||
bc.statedb = state.NewDatabase(bc.triedb, nil)
|
bc.statedb = state.NewDatabase(bc.triedb, nil)
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||||
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
bc.processor = NewStateProcessor(bc.hc)
|
||||||
|
|
||||||
genesisHeader := bc.GetHeaderByNumber(0)
|
genesisHeader := bc.GetHeaderByNumber(0)
|
||||||
if genesisHeader == nil {
|
if genesisHeader == nil {
|
||||||
|
|
|
||||||
|
|
@ -25,21 +25,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChainContext supports retrieving headers and consensus parameters from the
|
// ChainContext supports retrieving headers and consensus parameters from the
|
||||||
// current blockchain to be used during transaction processing.
|
// current blockchain to be used during transaction processing.
|
||||||
type ChainContext interface {
|
type ChainContext interface {
|
||||||
|
consensus.ChainHeaderReader
|
||||||
|
|
||||||
// Engine retrieves the chain's consensus engine.
|
// Engine retrieves the chain's consensus engine.
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
|
|
||||||
// GetHeader returns the header corresponding to the hash/number argument pair.
|
|
||||||
GetHeader(common.Hash, uint64) *types.Header
|
|
||||||
|
|
||||||
// Config returns the chain's configuration.
|
|
||||||
Config() *params.ChainConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEVMBlockContext creates a new context for use in the EVM.
|
// NewEVMBlockContext creates a new context for use in the EVM.
|
||||||
|
|
|
||||||
|
|
@ -35,18 +35,21 @@ import (
|
||||||
//
|
//
|
||||||
// StateProcessor implements Processor.
|
// StateProcessor implements Processor.
|
||||||
type StateProcessor struct {
|
type StateProcessor struct {
|
||||||
config *params.ChainConfig // Chain configuration options
|
chain ChainContext // Chain context interface
|
||||||
chain *HeaderChain // Canonical header chain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateProcessor initialises a new StateProcessor.
|
// NewStateProcessor initialises a new StateProcessor.
|
||||||
func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor {
|
func NewStateProcessor(chain ChainContext) *StateProcessor {
|
||||||
return &StateProcessor{
|
return &StateProcessor{
|
||||||
config: config,
|
chain: chain,
|
||||||
chain: chain,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chainConfig returns the chain configuration.
|
||||||
|
func (p *StateProcessor) chainConfig() *params.ChainConfig {
|
||||||
|
return p.chain.Config()
|
||||||
|
}
|
||||||
|
|
||||||
// Process processes the state changes according to the Ethereum rules by running
|
// Process processes the state changes according to the Ethereum rules by running
|
||||||
// the transaction messages using the statedb and applying any rewards to both
|
// the transaction messages using the statedb and applying any rewards to both
|
||||||
// the processor (coinbase) and any included uncles.
|
// the processor (coinbase) and any included uncles.
|
||||||
|
|
@ -56,6 +59,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro
|
||||||
// transactions failed to execute due to insufficient gas it will return an error.
|
// transactions failed to execute due to insufficient gas it will return an error.
|
||||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||||
var (
|
var (
|
||||||
|
config = p.chainConfig()
|
||||||
receipts types.Receipts
|
receipts types.Receipts
|
||||||
usedGas = new(uint64)
|
usedGas = new(uint64)
|
||||||
header = block.Header()
|
header = block.Header()
|
||||||
|
|
@ -66,12 +70,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mutate the block and state according to any hard-fork specs
|
// Mutate the block and state according to any hard-fork specs
|
||||||
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
misc.ApplyDAOHardFork(statedb)
|
misc.ApplyDAOHardFork(statedb)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
context vm.BlockContext
|
context vm.BlockContext
|
||||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
signer = types.MakeSigner(config, header.Number, header.Time)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Apply pre-execution system calls.
|
// Apply pre-execution system calls.
|
||||||
|
|
@ -80,12 +84,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
tracingStateDB = state.NewHookedState(statedb, hooks)
|
tracingStateDB = state.NewHookedState(statedb, hooks)
|
||||||
}
|
}
|
||||||
context = NewEVMBlockContext(header, p.chain, nil)
|
context = NewEVMBlockContext(header, p.chain, nil)
|
||||||
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
|
evm := vm.NewEVM(context, tracingStateDB, config, cfg)
|
||||||
|
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
ProcessBeaconBlockRoot(*beaconRoot, evm)
|
ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) {
|
if config.IsPrague(block.Number(), block.Time()) || config.IsVerkle(block.Number(), block.Time()) {
|
||||||
ProcessParentBlockHash(block.ParentHash(), evm)
|
ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,10 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
}
|
}
|
||||||
// Read requests if Prague is enabled.
|
// Read requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if p.config.IsPrague(block.Number(), block.Time()) {
|
if config.IsPrague(block.Number(), block.Time()) {
|
||||||
requests = [][]byte{}
|
requests = [][]byte{}
|
||||||
// EIP-6110
|
// EIP-6110
|
||||||
if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil {
|
if err := ParseDepositLogs(&requests, allLogs, config); err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse deposit logs: %w", err)
|
return nil, fmt.Errorf("failed to parse deposit logs: %w", err)
|
||||||
}
|
}
|
||||||
// EIP-7002
|
// EIP-7002
|
||||||
|
|
@ -123,7 +127,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||||
p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body())
|
p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body())
|
||||||
|
|
||||||
return &ProcessResult{
|
return &ProcessResult{
|
||||||
Receipts: receipts,
|
Receipts: receipts,
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *typ
|
||||||
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
||||||
engine: beacon.New(ethash.NewFaker()),
|
engine: beacon.New(ethash.NewFaker()),
|
||||||
}
|
}
|
||||||
processor := NewStateProcessor(config, chain)
|
processor := NewStateProcessor(chain)
|
||||||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
||||||
|
|
||||||
// Run the stateless blocks processing and self-validate certain fields
|
// Run the stateless blocks processing and self-validate certain fields
|
||||||
|
|
|
||||||
|
|
@ -312,6 +312,18 @@ func (d *dummyChain) Config() *params.ChainConfig {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dummyChain) CurrentHeader() *types.Header {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header {
|
||||||
|
return d.GetHeader(common.Hash{}, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
|
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
|
||||||
// requires access to a chain reader.
|
// requires access to a chain reader.
|
||||||
func TestBlockhash(t *testing.T) {
|
func TestBlockhash(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ type StateReleaseFunc func()
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
|
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
|
||||||
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
|
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
|
||||||
|
CurrentHeader() *types.Header
|
||||||
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
||||||
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
|
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
|
||||||
GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)
|
GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,10 @@ func (b *testBackend) ChainDb() ethdb.Database {
|
||||||
return b.chaindb
|
return b.chaindb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *testBackend) CurrentHeader() *types.Header {
|
||||||
|
return b.chain.CurrentHeader()
|
||||||
|
}
|
||||||
|
|
||||||
// teardown releases the associated resources.
|
// teardown releases the associated resources.
|
||||||
func (b *testBackend) teardown() {
|
func (b *testBackend) teardown() {
|
||||||
b.chain.Stop()
|
b.chain.Stop()
|
||||||
|
|
|
||||||
|
|
@ -636,6 +636,8 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
|
||||||
type ChainContextBackend interface {
|
type ChainContextBackend interface {
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
|
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
|
||||||
|
HeaderByHash(context.Context, common.Hash) (*types.Header, error)
|
||||||
|
CurrentHeader() *types.Header
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -669,6 +671,20 @@ func (context *ChainContext) Config() *params.ChainConfig {
|
||||||
return context.b.ChainConfig()
|
return context.b.ChainConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (context *ChainContext) CurrentHeader() *types.Header {
|
||||||
|
return context.b.CurrentHeader()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *ChainContext) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
|
header, _ := context.b.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *ChainContext) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||||
|
header, _ := context.b.HeaderByHash(context.ctx, hash)
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||||
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
||||||
if blockOverrides != nil {
|
if blockOverrides != nil {
|
||||||
|
|
|
||||||
|
|
@ -541,3 +541,23 @@ func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber)
|
||||||
func (b *simBackend) ChainConfig() *params.ChainConfig {
|
func (b *simBackend) ChainConfig() *params.ChainConfig {
|
||||||
return b.b.ChainConfig()
|
return b.b.ChainConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *simBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||||
|
if b.base.Hash() == hash {
|
||||||
|
return b.base, nil
|
||||||
|
}
|
||||||
|
if header, err := b.b.HeaderByHash(ctx, hash); err == nil {
|
||||||
|
return header, nil
|
||||||
|
}
|
||||||
|
// Check simulated headers
|
||||||
|
for _, header := range b.headers {
|
||||||
|
if header.Hash() == hash {
|
||||||
|
return header, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("header not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *simBackend) CurrentHeader() *types.Header {
|
||||||
|
return b.b.CurrentHeader()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -559,3 +559,6 @@ type dummyChain struct {
|
||||||
func (d *dummyChain) Engine() consensus.Engine { return nil }
|
func (d *dummyChain) Engine() consensus.Engine { return nil }
|
||||||
func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil }
|
func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil }
|
||||||
func (d *dummyChain) Config() *params.ChainConfig { return d.config }
|
func (d *dummyChain) Config() *params.ChainConfig { return d.config }
|
||||||
|
func (d *dummyChain) CurrentHeader() *types.Header { return nil }
|
||||||
|
func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header { return nil }
|
||||||
|
func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header { return nil }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue