Skip to content

Commit fc8c8c1

Browse files
authored
core: refactor StateProcessor to accept ChainContext interface (#32739)
This pr implements #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.
1 parent f0dc47a commit fc8c8c1

File tree

10 files changed

+76
-21
lines changed

10 files changed

+76
-21
lines changed

core/blockchain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
394394
bc.statedb = state.NewDatabase(bc.triedb, nil)
395395
bc.validator = NewBlockValidator(chainConfig, bc)
396396
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
397-
bc.processor = NewStateProcessor(chainConfig, bc.hc)
397+
bc.processor = NewStateProcessor(bc.hc)
398398

399399
genesisHeader := bc.GetHeaderByNumber(0)
400400
if genesisHeader == nil {

core/evm.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,16 @@ import (
2525
"github.com/ethereum/go-ethereum/core/tracing"
2626
"github.com/ethereum/go-ethereum/core/types"
2727
"github.com/ethereum/go-ethereum/core/vm"
28-
"github.com/ethereum/go-ethereum/params"
2928
"github.com/holiman/uint256"
3029
)
3130

3231
// ChainContext supports retrieving headers and consensus parameters from the
3332
// current blockchain to be used during transaction processing.
3433
type ChainContext interface {
34+
consensus.ChainHeaderReader
35+
3536
// Engine retrieves the chain's consensus engine.
3637
Engine() consensus.Engine
37-
38-
// GetHeader returns the header corresponding to the hash/number argument pair.
39-
GetHeader(common.Hash, uint64) *types.Header
40-
41-
// Config returns the chain's configuration.
42-
Config() *params.ChainConfig
4338
}
4439

4540
// NewEVMBlockContext creates a new context for use in the EVM.

core/state_processor.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,21 @@ import (
3535
//
3636
// StateProcessor implements Processor.
3737
type StateProcessor struct {
38-
config *params.ChainConfig // Chain configuration options
39-
chain *HeaderChain // Canonical header chain
38+
chain ChainContext // Chain context interface
4039
}
4140

4241
// NewStateProcessor initialises a new StateProcessor.
43-
func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor {
42+
func NewStateProcessor(chain ChainContext) *StateProcessor {
4443
return &StateProcessor{
45-
config: config,
46-
chain: chain,
44+
chain: chain,
4745
}
4846
}
4947

48+
// chainConfig returns the chain configuration.
49+
func (p *StateProcessor) chainConfig() *params.ChainConfig {
50+
return p.chain.Config()
51+
}
52+
5053
// Process processes the state changes according to the Ethereum rules by running
5154
// the transaction messages using the statedb and applying any rewards to both
5255
// the processor (coinbase) and any included uncles.
@@ -56,6 +59,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro
5659
// transactions failed to execute due to insufficient gas it will return an error.
5760
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
5861
var (
62+
config = p.chainConfig()
5963
receipts types.Receipts
6064
usedGas = new(uint64)
6165
header = block.Header()
@@ -66,12 +70,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
6670
)
6771

6872
// Mutate the block and state according to any hard-fork specs
69-
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
73+
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 {
7074
misc.ApplyDAOHardFork(statedb)
7175
}
7276
var (
7377
context vm.BlockContext
74-
signer = types.MakeSigner(p.config, header.Number, header.Time)
78+
signer = types.MakeSigner(config, header.Number, header.Time)
7579
)
7680

7781
// Apply pre-execution system calls.
@@ -80,12 +84,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
8084
tracingStateDB = state.NewHookedState(statedb, hooks)
8185
}
8286
context = NewEVMBlockContext(header, p.chain, nil)
83-
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
87+
evm := vm.NewEVM(context, tracingStateDB, config, cfg)
8488

8589
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
8690
ProcessBeaconBlockRoot(*beaconRoot, evm)
8791
}
88-
if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) {
92+
if config.IsPrague(block.Number(), block.Time()) || config.IsVerkle(block.Number(), block.Time()) {
8993
ProcessParentBlockHash(block.ParentHash(), evm)
9094
}
9195

@@ -106,10 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
106110
}
107111
// Read requests if Prague is enabled.
108112
var requests [][]byte
109-
if p.config.IsPrague(block.Number(), block.Time()) {
113+
if config.IsPrague(block.Number(), block.Time()) {
110114
requests = [][]byte{}
111115
// EIP-6110
112-
if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil {
116+
if err := ParseDepositLogs(&requests, allLogs, config); err != nil {
113117
return nil, fmt.Errorf("failed to parse deposit logs: %w", err)
114118
}
115119
// EIP-7002
@@ -123,7 +127,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
123127
}
124128

125129
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
126-
p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body())
130+
p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body())
127131

128132
return &ProcessResult{
129133
Receipts: receipts,

core/stateless.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *typ
6262
headerCache: lru.NewCache[common.Hash, *types.Header](256),
6363
engine: beacon.New(ethash.NewFaker()),
6464
}
65-
processor := NewStateProcessor(config, chain)
65+
processor := NewStateProcessor(chain)
6666
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
6767

6868
// Run the stateless blocks processing and self-validate certain fields

core/vm/runtime/runtime_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,18 @@ func (d *dummyChain) Config() *params.ChainConfig {
312312
return nil
313313
}
314314

315+
func (d *dummyChain) CurrentHeader() *types.Header {
316+
return nil
317+
}
318+
319+
func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header {
320+
return d.GetHeader(common.Hash{}, n)
321+
}
322+
323+
func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header {
324+
return nil
325+
}
326+
315327
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
316328
// requires access to a chain reader.
317329
func TestBlockhash(t *testing.T) {

eth/tracers/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ type StateReleaseFunc func()
8080
type Backend interface {
8181
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
8282
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
83+
CurrentHeader() *types.Header
8384
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
8485
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
8586
GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)

eth/tracers/api_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ func (b *testBackend) ChainDb() ethdb.Database {
142142
return b.chaindb
143143
}
144144

145+
func (b *testBackend) CurrentHeader() *types.Header {
146+
return b.chain.CurrentHeader()
147+
}
148+
145149
// teardown releases the associated resources.
146150
func (b *testBackend) teardown() {
147151
b.chain.Stop()

internal/ethapi/api.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
636636
type ChainContextBackend interface {
637637
Engine() consensus.Engine
638638
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
639+
HeaderByHash(context.Context, common.Hash) (*types.Header, error)
640+
CurrentHeader() *types.Header
639641
ChainConfig() *params.ChainConfig
640642
}
641643

@@ -669,6 +671,20 @@ func (context *ChainContext) Config() *params.ChainConfig {
669671
return context.b.ChainConfig()
670672
}
671673

674+
func (context *ChainContext) CurrentHeader() *types.Header {
675+
return context.b.CurrentHeader()
676+
}
677+
678+
func (context *ChainContext) GetHeaderByNumber(number uint64) *types.Header {
679+
header, _ := context.b.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
680+
return header
681+
}
682+
683+
func (context *ChainContext) GetHeaderByHash(hash common.Hash) *types.Header {
684+
header, _ := context.b.HeaderByHash(context.ctx, hash)
685+
return header
686+
}
687+
672688
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) {
673689
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
674690
if blockOverrides != nil {

internal/ethapi/simulate.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,23 @@ func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber)
541541
func (b *simBackend) ChainConfig() *params.ChainConfig {
542542
return b.b.ChainConfig()
543543
}
544+
545+
func (b *simBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
546+
if b.base.Hash() == hash {
547+
return b.base, nil
548+
}
549+
if header, err := b.b.HeaderByHash(ctx, hash); err == nil {
550+
return header, nil
551+
}
552+
// Check simulated headers
553+
for _, header := range b.headers {
554+
if header.Hash() == hash {
555+
return header, nil
556+
}
557+
}
558+
return nil, errors.New("header not found")
559+
}
560+
561+
func (b *simBackend) CurrentHeader() *types.Header {
562+
return b.b.CurrentHeader()
563+
}

tests/state_test_util.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,6 @@ type dummyChain struct {
559559
func (d *dummyChain) Engine() consensus.Engine { return nil }
560560
func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil }
561561
func (d *dummyChain) Config() *params.ChainConfig { return d.config }
562+
func (d *dummyChain) CurrentHeader() *types.Header { return nil }
563+
func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header { return nil }
564+
func (d *dummyChain) GetHeaderByHash(h common.Hash) *types.Header { return nil }

0 commit comments

Comments
 (0)