Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit f83437d

Browse files
authored
chore(core): split out code in state_processor.go and state_processor_test.go (#1442)
- Move our code from state_processor.go to state_processor_ext.go - Move our code from state_processor_test.go to state_procesor_ext_test.go - Slight modifications to state_processor.go to make it more alike geth master
1 parent 0d522e7 commit f83437d

File tree

4 files changed

+219
-190
lines changed

4 files changed

+219
-190
lines changed

core/state_processor.go

Lines changed: 4 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
package core
2828

2929
import (
30-
"encoding/json"
3130
"fmt"
3231
"math/big"
3332

@@ -36,13 +35,9 @@ import (
3635
"github.com/ava-labs/libevm/crypto"
3736
"github.com/ava-labs/libevm/log"
3837
"github.com/ava-labs/subnet-evm/consensus"
39-
"github.com/ava-labs/subnet-evm/core/extstate"
4038
"github.com/ava-labs/subnet-evm/core/state"
4139
"github.com/ava-labs/subnet-evm/core/types"
4240
"github.com/ava-labs/subnet-evm/params"
43-
"github.com/ava-labs/subnet-evm/precompile/contract"
44-
"github.com/ava-labs/subnet-evm/precompile/modules"
45-
"github.com/ava-labs/subnet-evm/stateupgrade"
4641
)
4742

4843
// StateProcessor is a basic Processor, which takes care of transitioning
@@ -97,6 +92,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state
9792
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
9893
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
9994
}
95+
10096
// Iterate over and process the individual transactions
10197
for i, tx := range block.Transactions() {
10298
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
@@ -129,7 +125,6 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
129125
if err != nil {
130126
return nil, err
131127
}
132-
133128
// Update the state with pending changes.
134129
var root []byte
135130
if config.IsByzantium(blockNumber) {
@@ -186,7 +181,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, blockContext
186181

187182
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
188183
// contract. This method is exported to be used in tests.
189-
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
184+
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM, statedb *state.StateDB) {
190185
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
191186
// the new root
192187
msg := &Message{
@@ -198,102 +193,8 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
198193
To: &params.BeaconRootsStorageAddress,
199194
Data: beaconRoot[:],
200195
}
201-
vmenv.Reset(NewEVMTxContext(msg), statedb)
196+
evm.Reset(NewEVMTxContext(msg), statedb)
202197
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
203-
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
198+
_, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
204199
statedb.Finalise(true)
205200
}
206-
207-
// ApplyPrecompileActivations checks if any of the precompiles specified by the chain config are enabled or disabled by the block
208-
// transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure]
209-
// to apply the necessary state transitions for the upgrade.
210-
// This function is called within genesis setup to configure the starting state for precompiles enabled at genesis.
211-
// In block processing and building, ApplyUpgrades is called instead which also applies state upgrades.
212-
func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
213-
blockTimestamp := blockContext.Timestamp()
214-
// Note: RegisteredModules returns precompiles sorted by module addresses.
215-
// This ensures that the order we call Configure for each precompile is consistent.
216-
// This ensures even if precompiles read/write state other than their own they will observe
217-
// an identical global state in a deterministic order when they are configured.
218-
extra := params.GetExtra(c)
219-
for _, module := range modules.RegisteredModules() {
220-
for _, activatingConfig := range extra.GetActivatingPrecompileConfigs(module.Address, parentTimestamp, blockTimestamp, extra.PrecompileUpgrades) {
221-
// If this transition activates the upgrade, configure the stateful precompile.
222-
// (or deconfigure it if it is being disabled.)
223-
if activatingConfig.IsDisabled() {
224-
log.Info("Disabling precompile", "name", module.ConfigKey)
225-
statedb.SelfDestruct(module.Address)
226-
// Calling Finalise here effectively commits Suicide call and wipes the contract state.
227-
// This enables re-configuration of the same contract state in the same block.
228-
// Without an immediate Finalise call after the Suicide, a reconfigured precompiled state can be wiped out
229-
// since Suicide will be committed after the reconfiguration.
230-
statedb.Finalise(true)
231-
} else {
232-
var printIntf interface{}
233-
marshalled, err := json.Marshal(activatingConfig)
234-
if err == nil {
235-
printIntf = string(marshalled)
236-
} else {
237-
printIntf = activatingConfig
238-
}
239-
240-
log.Info("Activating new precompile", "name", module.ConfigKey, "config", printIntf)
241-
// Set the nonce of the precompile's address (as is done when a contract is created) to ensure
242-
// that it is marked as non-empty and will not be cleaned up when the statedb is finalized.
243-
statedb.SetNonce(module.Address, 1)
244-
// Set the code of the precompile's address to a non-zero length byte slice to ensure that the precompile
245-
// can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure
246-
// that it does not attempt to invoke a non-existent contract.
247-
statedb.SetCode(module.Address, []byte{0x1})
248-
extstatedb := &extstate.StateDB{VmStateDB: statedb}
249-
if err := module.Configure(params.GetExtra(c), activatingConfig, extstatedb, blockContext); err != nil {
250-
return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err)
251-
}
252-
}
253-
}
254-
}
255-
return nil
256-
}
257-
258-
// applyStateUpgrades checks if any of the state upgrades specified by the chain config are activated by the block
259-
// transition from [parentTimestamp] to the timestamp set in [header]. If this is the case, it calls [Configure]
260-
// to apply the necessary state transitions for the upgrade.
261-
func applyStateUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
262-
// Apply state upgrades
263-
configExtra := params.GetExtra(c)
264-
for _, upgrade := range configExtra.GetActivatingStateUpgrades(parentTimestamp, blockContext.Timestamp(), configExtra.StateUpgrades) {
265-
log.Info("Applying state upgrade", "blockNumber", blockContext.Number(), "upgrade", upgrade)
266-
if err := stateupgrade.Configure(&upgrade, c, statedb, blockContext); err != nil {
267-
return fmt.Errorf("could not configure state upgrade: %w", err)
268-
}
269-
}
270-
return nil
271-
}
272-
273-
// ApplyUpgrades checks if any of the precompile or state upgrades specified by the chain config are activated by the block
274-
// transition from [parentTimestamp] to the timestamp set in [header]. If this is the case, it calls [Configure]
275-
// to apply the necessary state transitions for the upgrade.
276-
// This function is called:
277-
// - in block processing to update the state when processing a block.
278-
// - in the miner to apply the state upgrades when producing a block.
279-
func ApplyUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
280-
if err := ApplyPrecompileActivations(c, parentTimestamp, blockContext, statedb); err != nil {
281-
return err
282-
}
283-
return applyStateUpgrades(c, parentTimestamp, blockContext, statedb)
284-
}
285-
286-
type blockContext struct {
287-
number *big.Int
288-
timestamp uint64
289-
}
290-
291-
func NewBlockContext(number *big.Int, timestamp uint64) *blockContext {
292-
return &blockContext{
293-
number: number,
294-
timestamp: timestamp,
295-
}
296-
}
297-
298-
func (bc *blockContext) Number() *big.Int { return bc.number }
299-
func (bc *blockContext) Timestamp() uint64 { return bc.timestamp }

core/state_processor_ext.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// (c) 2025, Ava Labs, Inc.
2+
3+
package core
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
"math/big"
9+
10+
"github.com/ava-labs/libevm/log"
11+
"github.com/ava-labs/subnet-evm/core/extstate"
12+
"github.com/ava-labs/subnet-evm/core/state"
13+
"github.com/ava-labs/subnet-evm/params"
14+
"github.com/ava-labs/subnet-evm/precompile/contract"
15+
"github.com/ava-labs/subnet-evm/precompile/modules"
16+
"github.com/ava-labs/subnet-evm/stateupgrade"
17+
)
18+
19+
// ApplyPrecompileActivations checks if any of the precompiles specified by the chain config are enabled or disabled by the block
20+
// transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure]
21+
// to apply the necessary state transitions for the upgrade.
22+
// This function is called within genesis setup to configure the starting state for precompiles enabled at genesis.
23+
// In block processing and building, ApplyUpgrades is called instead which also applies state upgrades.
24+
func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
25+
blockTimestamp := blockContext.Timestamp()
26+
// Note: RegisteredModules returns precompiles sorted by module addresses.
27+
// This ensures that the order we call Configure for each precompile is consistent.
28+
// This ensures even if precompiles read/write state other than their own they will observe
29+
// an identical global state in a deterministic order when they are configured.
30+
extra := params.GetExtra(c)
31+
for _, module := range modules.RegisteredModules() {
32+
for _, activatingConfig := range extra.GetActivatingPrecompileConfigs(module.Address, parentTimestamp, blockTimestamp, extra.PrecompileUpgrades) {
33+
// If this transition activates the upgrade, configure the stateful precompile.
34+
// (or deconfigure it if it is being disabled.)
35+
if activatingConfig.IsDisabled() {
36+
log.Info("Disabling precompile", "name", module.ConfigKey)
37+
statedb.SelfDestruct(module.Address)
38+
// Calling Finalise here effectively commits Suicide call and wipes the contract state.
39+
// This enables re-configuration of the same contract state in the same block.
40+
// Without an immediate Finalise call after the Suicide, a reconfigured precompiled state can be wiped out
41+
// since Suicide will be committed after the reconfiguration.
42+
statedb.Finalise(true)
43+
} else {
44+
var printIntf interface{}
45+
marshalled, err := json.Marshal(activatingConfig)
46+
if err == nil {
47+
printIntf = string(marshalled)
48+
} else {
49+
printIntf = activatingConfig
50+
}
51+
52+
log.Info("Activating new precompile", "name", module.ConfigKey, "config", printIntf)
53+
// Set the nonce of the precompile's address (as is done when a contract is created) to ensure
54+
// that it is marked as non-empty and will not be cleaned up when the statedb is finalized.
55+
statedb.SetNonce(module.Address, 1)
56+
// Set the code of the precompile's address to a non-zero length byte slice to ensure that the precompile
57+
// can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure
58+
// that it does not attempt to invoke a non-existent contract.
59+
statedb.SetCode(module.Address, []byte{0x1})
60+
extstatedb := &extstate.StateDB{VmStateDB: statedb}
61+
if err := module.Configure(params.GetExtra(c), activatingConfig, extstatedb, blockContext); err != nil {
62+
return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err)
63+
}
64+
}
65+
}
66+
}
67+
return nil
68+
}
69+
70+
// applyStateUpgrades checks if any of the state upgrades specified by the chain config are activated by the block
71+
// transition from [parentTimestamp] to the timestamp set in [header]. If this is the case, it calls [Configure]
72+
// to apply the necessary state transitions for the upgrade.
73+
func applyStateUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
74+
// Apply state upgrades
75+
configExtra := params.GetExtra(c)
76+
for _, upgrade := range configExtra.GetActivatingStateUpgrades(parentTimestamp, blockContext.Timestamp(), configExtra.StateUpgrades) {
77+
log.Info("Applying state upgrade", "blockNumber", blockContext.Number(), "upgrade", upgrade)
78+
if err := stateupgrade.Configure(&upgrade, c, statedb, blockContext); err != nil {
79+
return fmt.Errorf("could not configure state upgrade: %w", err)
80+
}
81+
}
82+
return nil
83+
}
84+
85+
// ApplyUpgrades checks if any of the precompile or state upgrades specified by the chain config are activated by the block
86+
// transition from [parentTimestamp] to the timestamp set in [header]. If this is the case, it calls [Configure]
87+
// to apply the necessary state transitions for the upgrade.
88+
// This function is called:
89+
// - in block processing to update the state when processing a block.
90+
// - in the miner to apply the state upgrades when producing a block.
91+
func ApplyUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error {
92+
if err := ApplyPrecompileActivations(c, parentTimestamp, blockContext, statedb); err != nil {
93+
return err
94+
}
95+
return applyStateUpgrades(c, parentTimestamp, blockContext, statedb)
96+
}
97+
98+
type blockContext struct {
99+
number *big.Int
100+
timestamp uint64
101+
}
102+
103+
func NewBlockContext(number *big.Int, timestamp uint64) *blockContext {
104+
return &blockContext{
105+
number: number,
106+
timestamp: timestamp,
107+
}
108+
}
109+
110+
func (bc *blockContext) Number() *big.Int { return bc.number }
111+
func (bc *blockContext) Timestamp() uint64 { return bc.timestamp }

core/state_processor_ext_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// (c) 2025, Ava Labs, Inc.
2+
3+
package core
4+
5+
import (
6+
"math/big"
7+
"testing"
8+
9+
"github.com/ava-labs/libevm/common"
10+
"github.com/ava-labs/libevm/core/vm"
11+
"github.com/ava-labs/libevm/crypto"
12+
"github.com/ava-labs/subnet-evm/consensus/dummy"
13+
"github.com/ava-labs/subnet-evm/core/rawdb"
14+
"github.com/ava-labs/subnet-evm/core/types"
15+
"github.com/ava-labs/subnet-evm/params"
16+
"github.com/ava-labs/subnet-evm/params/extras"
17+
"github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist"
18+
"github.com/ava-labs/subnet-evm/utils"
19+
)
20+
21+
// TestBadTxAllowListBlock tests the output generated when the
22+
// blockchain imports a bad block with a transaction from a
23+
// non-whitelisted TX Allow List address.
24+
func TestBadTxAllowListBlock(t *testing.T) {
25+
var (
26+
db = rawdb.NewMemoryDatabase()
27+
testAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
28+
29+
config = params.WithExtra(
30+
&params.ChainConfig{
31+
ChainID: big.NewInt(1),
32+
HomesteadBlock: big.NewInt(0),
33+
EIP150Block: big.NewInt(0),
34+
EIP155Block: big.NewInt(0),
35+
EIP158Block: big.NewInt(0),
36+
ByzantiumBlock: big.NewInt(0),
37+
ConstantinopleBlock: big.NewInt(0),
38+
PetersburgBlock: big.NewInt(0),
39+
IstanbulBlock: big.NewInt(0),
40+
MuirGlacierBlock: big.NewInt(0),
41+
BerlinBlock: big.NewInt(0),
42+
LondonBlock: big.NewInt(0),
43+
},
44+
&extras.ChainConfig{
45+
FeeConfig: params.DefaultFeeConfig,
46+
NetworkUpgrades: extras.NetworkUpgrades{
47+
SubnetEVMTimestamp: utils.NewUint64(0),
48+
},
49+
GenesisPrecompiles: extras.Precompiles{
50+
txallowlist.ConfigKey: txallowlist.NewConfig(utils.NewUint64(0), nil, nil, nil),
51+
},
52+
},
53+
)
54+
signer = types.LatestSigner(config)
55+
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
56+
57+
gspec = &Genesis{
58+
Config: config,
59+
Alloc: GenesisAlloc{
60+
testAddr: GenesisAccount{
61+
Balance: big.NewInt(1000000000000000000), // 1 ether
62+
Nonce: 0,
63+
},
64+
},
65+
GasLimit: params.GetExtra(config).FeeConfig.GasLimit.Uint64(),
66+
}
67+
blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{}, false)
68+
)
69+
defer blockchain.Stop()
70+
71+
mkDynamicTx := func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
72+
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
73+
Nonce: nonce,
74+
GasTipCap: gasTipCap,
75+
GasFeeCap: gasFeeCap,
76+
Gas: gasLimit,
77+
To: &to,
78+
Value: big.NewInt(0),
79+
}), signer, testKey)
80+
return tx
81+
}
82+
83+
defer blockchain.Stop()
84+
for i, tt := range []struct {
85+
txs []*types.Transaction
86+
want string
87+
}{
88+
{ // Nonwhitelisted address
89+
txs: []*types.Transaction{
90+
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(225000000000)),
91+
},
92+
want: "could not apply tx 0 [0xc5725e8baac950b2925dd4fea446ccddead1cc0affdae18b31a7d910629d9225]: cannot issue transaction from non-allow listed address: 0x71562b71999873DB5b286dF957af199Ec94617F7",
93+
},
94+
} {
95+
block := GenerateBadBlock(gspec.ToBlock(), dummy.NewCoinbaseFaker(), tt.txs, gspec.Config)
96+
_, err := blockchain.InsertChain(types.Blocks{block})
97+
if err == nil {
98+
t.Fatal("block imported without errors")
99+
}
100+
if have, want := err.Error(), tt.want; have != want {
101+
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)