fix a lot of tests

This commit is contained in:
Jared Wasinger 2025-10-01 12:37:51 +08:00
parent b2c4d19ca2
commit fe6bce3769
7 changed files with 101 additions and 106 deletions

View file

@ -1,7 +1,6 @@
package core package core
import ( import (
"fmt"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"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"
@ -27,10 +26,10 @@ type BlockAccessListTracer struct {
} }
// NewBlockAccessListTracer returns an BlockAccessListTracer and a set of hooks // NewBlockAccessListTracer returns an BlockAccessListTracer and a set of hooks
func NewBlockAccessListTracer() (*BlockAccessListTracer, *tracing.Hooks) { func NewBlockAccessListTracer(startIdx int) (*BlockAccessListTracer, *tracing.Hooks) {
balTracer := &BlockAccessListTracer{ balTracer := &BlockAccessListTracer{
callAccessLists: []*bal.ConstructionBlockAccessList{bal.NewConstructionBlockAccessList()}, callAccessLists: []*bal.ConstructionBlockAccessList{bal.NewConstructionBlockAccessList()},
txIdx: 0, txIdx: uint16(startIdx),
} }
hooks := &tracing.Hooks{ hooks := &tracing.Hooks{
OnTxEnd: balTracer.TxEndHook, OnTxEnd: balTracer.TxEndHook,
@ -52,11 +51,6 @@ func (a *BlockAccessListTracer) AccessList() *bal.ConstructionBlockAccessList {
return a.callAccessLists[0] return a.callAccessLists[0]
} }
// StateDiff returns a state diff at the current BAL index
func (a *BlockAccessListTracer) StateDiff() *bal.StateDiff {
return a.callAccessLists[0].
}
func (a *BlockAccessListTracer) TxEndHook(receipt *types.Receipt, err error) { func (a *BlockAccessListTracer) TxEndHook(receipt *types.Receipt, err error) {
a.txIdx++ a.txIdx++
} }
@ -80,11 +74,8 @@ func (a *BlockAccessListTracer) OnExit(depth int, output []byte, gasUsed uint64,
parentAccessList := a.callAccessLists[len(a.callAccessLists)-2] parentAccessList := a.callAccessLists[len(a.callAccessLists)-2]
scopeAccessList := a.callAccessLists[len(a.callAccessLists)-1] scopeAccessList := a.callAccessLists[len(a.callAccessLists)-1]
if reverted { if reverted {
fmt.Println("exit reverted")
parentAccessList.MergeReads(scopeAccessList) parentAccessList.MergeReads(scopeAccessList)
} else { } else {
fmt.Println("exit normal")
fmt.Printf("scope access list is\n%s\n", scopeAccessList.ToEncodingObj().String())
parentAccessList.Merge(scopeAccessList) parentAccessList.Merge(scopeAccessList)
} }
@ -112,7 +103,6 @@ func (a *BlockAccessListTracer) OnColdStorageRead(addr common.Address, key commo
} }
func (a *BlockAccessListTracer) OnColdAccountRead(addr common.Address) { func (a *BlockAccessListTracer) OnColdAccountRead(addr common.Address) {
fmt.Printf("cold account read %x\n", addr)
a.callAccessLists[len(a.callAccessLists)-1].AccountRead(addr) a.callAccessLists[len(a.callAccessLists)-1].AccountRead(addr)
} }

View file

@ -2062,11 +2062,6 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
}(time.Now(), throwaway, block) }(time.Now(), throwaway, block)
} }
// TODO: can remove validateBAL parameter and just look at whether the block has an access list?
if constructBALForTesting || validateBAL {
statedb.EnableStateDiffRecording()
}
// If we are past Byzantium, enable prefetching to pull in trie node paths // If we are past Byzantium, enable prefetching to pull in trie node paths
// while processing transactions. Before Byzantium the prefetcher is mostly // while processing transactions. Before Byzantium the prefetcher is mostly
// useless due to the intermediate root hashing after each transaction. // useless due to the intermediate root hashing after each transaction.
@ -2150,7 +2145,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
var balTracer *BlockAccessListTracer var balTracer *BlockAccessListTracer
// Process block using the parent state as reference point // Process block using the parent state as reference point
if constructBALForTesting { if constructBALForTesting {
balTracer, bc.cfg.VmConfig.Tracer = NewBlockAccessListTracer() balTracer, bc.cfg.VmConfig.Tracer = NewBlockAccessListTracer(0)
} }
// Process block using the parent state as reference point // Process block using the parent state as reference point
pstart := time.Now() pstart := time.Now()

View file

@ -328,11 +328,11 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) {
blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase)
evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{})
// EIP-7002 // EIP-7002
if _, _, err := ProcessWithdrawalQueue(&requests, evm); err != nil { if err := ProcessWithdrawalQueue(&requests, evm); err != nil {
panic(fmt.Sprintf("could not process withdrawal requests: %v", err)) panic(fmt.Sprintf("could not process withdrawal requests: %v", err))
} }
// EIP-7251 // EIP-7251
if _, _, err := ProcessConsolidationQueue(&requests, evm); err != nil { if err := ProcessConsolidationQueue(&requests, evm); err != nil {
panic(fmt.Sprintf("could not process consolidation requests: %v", err)) panic(fmt.Sprintf("could not process consolidation requests: %v", err))
} }
} }

View file

@ -58,13 +58,20 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, allStateR
tPostprocessStart := time.Now() tPostprocessStart := time.Now()
header := block.Header() header := block.Header()
postTxState.SetAccessListIndex(len(block.Transactions()) + 1) balTracer, hooks := NewBlockAccessListTracer(len(block.Transactions()) + 1)
var tracingStateDB = vm.StateDB(postTxState) tracingStateDB := state.NewHookedState(postTxState, hooks)
if hooks := p.vmCfg.Tracer; hooks != nil {
tracingStateDB = state.NewHookedState(postTxState, hooks)
}
context := NewEVMBlockContext(header, p.chain, nil) context := NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(context, tracingStateDB, p.config, *p.vmCfg)
cfg := vm.Config{
Tracer: hooks,
NoBaseFee: p.vmCfg.NoBaseFee,
EnablePreimageRecording: p.vmCfg.EnablePreimageRecording,
ExtraEips: slices.Clone(p.vmCfg.ExtraEips),
StatelessSelfValidation: p.vmCfg.StatelessSelfValidation,
EnableWitnessStats: p.vmCfg.EnableWitnessStats,
}
cfg.Tracer = hooks
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
// 1. order the receipts by tx index // 1. order the receipts by tx index
// 2. correctly calculate the cumulative gas used per receipt, returning bad block error if it goes over the allowed // 2. correctly calculate the cumulative gas used per receipt, returning bad block error if it goes over the allowed
@ -85,9 +92,6 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, allStateR
allLogs = append(allLogs, receipt.Logs...) allLogs = append(allLogs, receipt.Logs...)
} }
computedDiff := &bal.StateDiff{make(map[common.Address]*bal.AccountState)}
computedAccesses := make(bal.StateAccesses)
// Read requests if Prague is enabled. // Read requests if Prague is enabled.
if p.config.IsPrague(block.Number(), block.Time()) { if p.config.IsPrague(block.Number(), block.Time()) {
requests = [][]byte{} requests = [][]byte{}
@ -99,38 +103,35 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, allStateR
} }
// EIP-7002 // EIP-7002
diff, accesses, err := ProcessWithdrawalQueue(&requests, evm) err := ProcessWithdrawalQueue(&requests, evm)
if err != nil { if err != nil {
return &ProcessResultWithMetrics{ return &ProcessResultWithMetrics{
ProcessResult: &ProcessResult{Error: err}, ProcessResult: &ProcessResult{Error: err},
} }
} }
computedDiff = diff
computedAccesses = *accesses
// EIP-7251 // EIP-7251
diff, accesses, err = ProcessConsolidationQueue(&requests, evm) err = ProcessConsolidationQueue(&requests, evm)
if err != nil { if err != nil {
return &ProcessResultWithMetrics{ return &ProcessResultWithMetrics{
ProcessResult: &ProcessResult{Error: err}, ProcessResult: &ProcessResult{Error: err},
} }
} }
computedDiff.Merge(diff)
computedAccesses.Merge(*accesses)
} }
// 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())
// invoke Finalise so that withdrawals are accounted for in the state diff // invoke Finalise so that withdrawals are accounted for in the state diff
postTxState.Finalise(true) postTxState.Finalise(true)
allStateReads.Merge(balTracer.AccessList().StateAccesses())
if err := postTxState.BlockAccessList().ValidateStateDiff(len(block.Transactions())+1, computedDiff); err != nil { balIdx := len(block.Transactions()) + 1
if err := postTxState.BlockAccessList().ValidateStateDiff(balIdx, balTracer.AccessList().DiffAt(balIdx)); err != nil {
return &ProcessResultWithMetrics{ return &ProcessResultWithMetrics{
ProcessResult: &ProcessResult{Error: err}, ProcessResult: &ProcessResult{Error: err},
} }
} }
allStateReads.Merge(computedAccesses)
if err := postTxState.BlockAccessList().ValidateStateReads(*allStateReads); err != nil { if err := postTxState.BlockAccessList().ValidateStateReads(*allStateReads); err != nil {
return &ProcessResultWithMetrics{ return &ProcessResultWithMetrics{
ProcessResult: &ProcessResult{Error: err}, ProcessResult: &ProcessResult{Error: err},
@ -156,13 +157,12 @@ type txExecResult struct {
receipt *types.Receipt receipt *types.Receipt
err error // non-EVM error which would render the block invalid err error // non-EVM error which would render the block invalid
mutations *bal.StateDiff accessList *bal.ConstructionBlockAccessList
stateReads *bal.StateAccesses
} }
// resultHandler polls until all transactions have finished executing and the // resultHandler polls until all transactions have finished executing and the
// state root calculation is complete. The result is emitted on resCh. // state root calculation is complete. The result is emitted on resCh.
func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxStateReads *bal.StateAccesses, postTxState *state.StateDB, tExecStart time.Time, txResCh <-chan txExecResult, stateRootCalcResCh <-chan stateRootCalculationResult, resCh chan *ProcessResultWithMetrics) { func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxStateReads bal.StateAccesses, postTxState *state.StateDB, tExecStart time.Time, txResCh <-chan txExecResult, stateRootCalcResCh <-chan stateRootCalculationResult, resCh chan *ProcessResultWithMetrics) {
// 1. if the block has transactions, receive the execution results from all of them and return an error on resCh if any txs err'd // 1. if the block has transactions, receive the execution results from all of them and return an error on resCh if any txs err'd
// 2. once all txs are executed, compute the post-tx state transition and produce the ProcessResult sending it on resCh (or an error if the post-tx state didn't match what is reported in the BAL) // 2. once all txs are executed, compute the post-tx state transition and produce the ProcessResult sending it on resCh (or an error if the post-tx state didn't match what is reported in the BAL)
var receipts []*types.Receipt var receipts []*types.Receipt
@ -172,7 +172,7 @@ func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxStateRea
var numTxComplete int var numTxComplete int
allReads := make(bal.StateAccesses) allReads := make(bal.StateAccesses)
allReads.Merge(*preTxStateReads) allReads.Merge(preTxStateReads)
if len(block.Transactions()) > 0 { if len(block.Transactions()) > 0 {
loop: loop:
for { for {
@ -186,7 +186,7 @@ func (p *ParallelStateProcessor) resultHandler(block *types.Block, preTxStateRea
execErr = err execErr = err
} else { } else {
receipts = append(receipts, res.receipt) receipts = append(receipts, res.receipt)
allReads.Merge(*res.stateReads) allReads.Merge(res.accessList.StateAccesses())
} }
} }
} }
@ -243,49 +243,51 @@ func (p *ParallelStateProcessor) calcAndVerifyRoot(preState *state.StateDB, bloc
} }
// execTx executes single transaction returning a result which includes state accessed/modified // execTx executes single transaction returning a result which includes state accessed/modified
func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transaction, idx int, db *state.StateDB, signer types.Signer) *txExecResult { func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transaction, txIdx int, db *state.StateDB, signer types.Signer) *txExecResult {
header := block.Header() header := block.Header()
balTracer, hooks := NewBlockAccessListTracer() balTracer, hooks := NewBlockAccessListTracer(txIdx + 1)
tracingStateDB := state.NewHookedState(db, hooks) tracingStateDB := state.NewHookedState(db, hooks)
context := NewEVMBlockContext(header, p.chain, nil) context := NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(context, tracingStateDB, p.config, *p.vmCfg)
cfg := vm.Config{
Tracer: hooks,
NoBaseFee: p.vmCfg.NoBaseFee,
EnablePreimageRecording: p.vmCfg.EnablePreimageRecording,
ExtraEips: slices.Clone(p.vmCfg.ExtraEips),
StatelessSelfValidation: p.vmCfg.StatelessSelfValidation,
EnableWitnessStats: p.vmCfg.EnableWitnessStats,
}
cfg.Tracer = hooks
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
msg, err := TransactionToMessage(tx, signer, header.BaseFee) msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil { if err != nil {
err = fmt.Errorf("could not apply tx %d [%v]: %w", idx, tx.Hash().Hex(), err) err = fmt.Errorf("could not apply tx %d [%v]: %w", txIdx, tx.Hash().Hex(), err)
return &txExecResult{err: err} return &txExecResult{err: err}
} }
sender, _ := types.Sender(signer, tx)
db.SetTxSender(sender)
db.SetTxContext(tx.Hash(), idx)
db.SetAccessListIndex(idx + 1)
evm.StateDB = db
gp := new(GasPool) gp := new(GasPool)
gp.SetGas(block.GasLimit()) gp.SetGas(block.GasLimit())
var gasUsed uint64 var gasUsed uint64
mutatedState, accessedState, receipt, err := ApplyTransactionWithEVM(msg, gp, db, block.Number(), block.Hash(), context.Time, tx, &gasUsed, evm) receipt, err := ApplyTransactionWithEVM(msg, gp, db, block.Number(), block.Hash(), context.Time, tx, &gasUsed, evm)
if err != nil { if err != nil {
err := fmt.Errorf("could not apply tx %d [%v]: %w", idx, tx.Hash().Hex(), err) err := fmt.Errorf("could not apply tx %d [%v]: %w", txIdx, tx.Hash().Hex(), err)
return &txExecResult{err: err} return &txExecResult{err: err}
} }
if err := db.BlockAccessList().ValidateStateDiff(idx+1, balTracer.AccessList().DiffAt(uint16(idx)+1)); err != nil { if err := db.BlockAccessList().ValidateStateDiff(txIdx+1, balTracer.AccessList().DiffAt(txIdx+1)); err != nil {
return &txExecResult{err: err} return &txExecResult{err: err}
} }
return &txExecResult{ return &txExecResult{
idx: idx, idx: txIdx,
receipt: receipt, receipt: receipt,
mutations: mutatedState, accessList: balTracer.AccessList(),
stateReads: accessedState,
} }
} }
// Process performs EVM execution and state root computation for a block which is known // Process performs EVM execution and state root computation for a block which is known
// to contain an access list. // to contain an access list.
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResultWithMetrics, error) { func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResultWithMetrics, error) {
fmt.Println("start ParallelProcess")
var ( var (
header = block.Header() header = block.Header()
resCh = make(chan *ProcessResultWithMetrics) resCh = make(chan *ProcessResultWithMetrics)
@ -310,30 +312,22 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
alReader := state.NewBALReader(block, statedb) alReader := state.NewBALReader(block, statedb)
statedb.SetBlockAccessList(alReader) statedb.SetBlockAccessList(alReader)
// Apply pre-execution system calls. balTracer, hooks := NewBlockAccessListTracer(0)
var tracingStateDB = vm.StateDB(statedb) tracingStateDB := state.NewHookedState(statedb, hooks)
if hooks := cfg.Tracer; hooks != nil { // TODO: figure out exactly why we need to set the hooks on the TracingStateDB and the vm.Config
tracingStateDB = state.NewHookedState(statedb, hooks) cfg.Tracer = 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, p.config, cfg)
// validate the correctness of pre-transaction execution state changes
computedPreTxDiff := &bal.StateDiff{make(map[common.Address]*bal.AccountState)}
preTxStateReads := make(bal.StateAccesses)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil { if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
diff, reads := ProcessBeaconBlockRoot(*beaconRoot, evm) ProcessBeaconBlockRoot(*beaconRoot, evm)
computedPreTxDiff.Merge(diff)
preTxStateReads.Merge(*reads)
} }
if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) { if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) {
diff, reads := ProcessParentBlockHash(block.ParentHash(), evm) ProcessParentBlockHash(block.ParentHash(), evm)
computedPreTxDiff.Merge(diff)
preTxStateReads.Merge(*reads)
} }
if err := statedb.BlockAccessList().ValidateStateDiff(0, computedPreTxDiff); err != nil { if err := statedb.BlockAccessList().ValidateStateDiff(0, balTracer.AccessList().DiffAt(0)); err != nil {
return nil, err return nil, err
} }
@ -345,8 +339,10 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
// execute transactions and state root calculation in parallel // execute transactions and state root calculation in parallel
// TODO: figure out how to funnel the state reads from the bal tracer through to the post-block-exec state/slot read
// validation
tExecStart = time.Now() tExecStart = time.Now()
go p.resultHandler(block, &preTxStateReads, postTxState, tExecStart, txResCh, rootCalcResultCh, resCh) go p.resultHandler(block, balTracer.AccessList().StateAccesses(), postTxState, tExecStart, txResCh, rootCalcResultCh, resCh)
var workers errgroup.Group var workers errgroup.Group
startingState := statedb.Copy() startingState := statedb.Copy()
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {

View file

@ -1085,13 +1085,6 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
s.balIndex = ti + 1 s.balIndex = ti + 1
} }
// SetAccessListIndex sets the current index that state mutations will
// be reported as in the BAL. It is only relevant if this StateDB instance
// is being used in the BAL construction path.
func (s *StateDB) SetAccessListIndex(idx int) {
s.balIndex = idx
}
// SetTxSender sets the sender of the currently-executing transaction. // SetTxSender sets the sender of the currently-executing transaction.
func (s *StateDB) SetTxSender(sender common.Address) { func (s *StateDB) SetTxSender(sender common.Address) {
s.sender = sender s.sender = sender

View file

@ -18,7 +18,6 @@ package core
import ( import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/core/types/bal"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -98,7 +97,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
_, _, receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm) receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, context.Time, tx, usedGas, evm)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
@ -115,11 +114,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
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
if _, _, err := ProcessWithdrawalQueue(&requests, evm); err != nil { if err := ProcessWithdrawalQueue(&requests, evm); err != nil {
return nil, err return nil, err
} }
// EIP-7251 // EIP-7251
if _, _, err := ProcessConsolidationQueue(&requests, evm); err != nil { if err := ProcessConsolidationQueue(&requests, evm); err != nil {
return nil, err return nil, err
} }
} }
@ -138,7 +137,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database // ApplyTransactionWithEVM attempts to apply a transaction to the given state database
// and uses the input parameters for its environment similar to ApplyTransaction. However, // and uses the input parameters for its environment similar to ApplyTransaction. However,
// this method takes an already created EVM instance as input. // this method takes an already created EVM instance as input.
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (mutatedState *bal.StateDiff, accessedState *bal.StateAccesses, receipt *types.Receipt, err error) { func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
if hooks := evm.Config.Tracer; hooks != nil { if hooks := evm.Config.Tracer; hooks != nil {
if hooks.OnTxStart != nil { if hooks.OnTxStart != nil {
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
@ -150,13 +149,13 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
// Apply the transaction to the current state (included in the env). // Apply the transaction to the current state (included in the env).
result, err := ApplyMessage(evm, msg, gp) result, err := ApplyMessage(evm, msg, gp)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, err
} }
// Update the state with pending changes. // Update the state with pending changes.
var root []byte var root []byte
if evm.ChainConfig().IsByzantium(blockNumber) { if evm.ChainConfig().IsByzantium(blockNumber) {
mutatedState, accessedState = evm.StateDB.Finalise(true) evm.StateDB.Finalise(true)
} else { } else {
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes() root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
} }
@ -167,7 +166,7 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
if statedb.Database().TrieDB().IsVerkle() { if statedb.Database().TrieDB().IsVerkle() {
statedb.AccessEvents().Merge(evm.AccessEvents) statedb.AccessEvents().Merge(evm.AccessEvents)
} }
return mutatedState, accessedState, MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), nil return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), nil
} }
// MakeReceipt generates the receipt object for a transaction given its execution result. // MakeReceipt generates the receipt object for a transaction given its execution result.
@ -212,13 +211,13 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *
return nil, err return nil, err
} }
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
_, _, receipts, err := ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, usedGas, evm) receipts, err := ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), header.Time, tx, usedGas, evm)
return receipts, err return receipts, err
} }
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests. // contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) (*bal.StateDiff, *bal.StateAccesses) { func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil { if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext()) onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil { if tracer.OnSystemCallEnd != nil {
@ -237,12 +236,12 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) (*bal.StateDiff
evm.SetTxContext(NewEVMTxContext(msg)) evm.SetTxContext(NewEVMTxContext(msg))
evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress) evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress)
_, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
return evm.StateDB.Finalise(true) evm.StateDB.Finalise(true)
} }
// ProcessParentBlockHash stores the parent block hash in the history storage contract // ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935/7709. // as per EIP-2935/7709.
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) (*bal.StateDiff, *bal.StateAccesses) { func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil { if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext()) onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil { if tracer.OnSystemCallEnd != nil {
@ -267,22 +266,22 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) (*bal.StateDiff,
if evm.StateDB.AccessEvents() != nil { if evm.StateDB.AccessEvents() != nil {
evm.StateDB.AccessEvents().Merge(evm.AccessEvents) evm.StateDB.AccessEvents().Merge(evm.AccessEvents)
} }
return evm.StateDB.Finalise(true) evm.StateDB.Finalise(true)
} }
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
// It returns the opaque request data returned by the contract. // It returns the opaque request data returned by the contract.
func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) (*bal.StateDiff, *bal.StateAccesses, error) { func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) error {
return processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress) return processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress)
} }
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract. // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
// It returns the opaque request data returned by the contract. // It returns the opaque request data returned by the contract.
func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) (*bal.StateDiff, *bal.StateAccesses, error) { func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error {
return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress)
} }
func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) (*bal.StateDiff, *bal.StateAccesses, error) { func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error {
if tracer := evm.Config.Tracer; tracer != nil { if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext()) onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil { if tracer.OnSystemCallEnd != nil {
@ -300,19 +299,19 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte
evm.SetTxContext(NewEVMTxContext(msg)) evm.SetTxContext(NewEVMTxContext(msg))
evm.StateDB.AddAddressToAccessList(addr) evm.StateDB.AddAddressToAccessList(addr)
ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
diff, accesses := evm.StateDB.Finalise(true) evm.StateDB.Finalise(true)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("system call failed to execute: %v", err) return fmt.Errorf("system call failed to execute: %v", err)
} }
if len(ret) == 0 { if len(ret) == 0 {
return diff, accesses, nil // skip empty output return nil // skip empty output
} }
// Append prefixed requestsData to the requests list. // Append prefixed requestsData to the requests list.
requestsData := make([]byte, len(ret)+1) requestsData := make([]byte, len(ret)+1)
requestsData[0] = requestType requestsData[0] = requestType
copy(requestsData[1:], ret) copy(requestsData[1:], ret)
*requests = append(*requests, requestsData) *requests = append(*requests, requestsData)
return diff, accesses, nil return nil
} }
var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5") var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5")

View file

@ -105,9 +105,11 @@ func NewConstructionBlockAccessList() *ConstructionBlockAccessList {
} }
} }
func (c *ConstructionBlockAccessList) DiffAt(idx uint16) *StateDiff { func (c *ConstructionBlockAccessList) DiffAt(i int) *StateDiff {
res := &StateDiff{make(map[common.Address]*AccountState)} res := &StateDiff{make(map[common.Address]*AccountState)}
idx := uint16(i)
for addr, account := range c.Accounts { for addr, account := range c.Accounts {
accountState := &AccountState{} accountState := &AccountState{}
if balance, ok := account.BalanceChanges[idx]; ok { if balance, ok := account.BalanceChanges[idx]; ok {
@ -127,10 +129,26 @@ func (c *ConstructionBlockAccessList) DiffAt(idx uint16) *StateDiff {
} }
} }
if len(storageWrites) > 0 { if len(storageWrites) > 0 {
accountState.StorageWrites = make(map[common.Hash]common.Hash) accountState.StorageWrites = storageWrites
} }
res.Mutations[addr] = accountState if !accountState.Empty() {
res.Mutations[addr] = accountState
}
}
return res
}
func (c *ConstructionBlockAccessList) StateAccesses() StateAccesses {
res := make(StateAccesses)
for addr, acct := range c.Accounts {
if len(acct.StorageReads) > 0 {
res[addr] = acct.StorageReads
continue
}
if len(acct.NonceChanges) == 0 && len(acct.BalanceChanges) == 0 && len(acct.StorageWrites) == 0 && len(acct.CodeChanges) == 0 {
res[addr] = make(map[common.Hash]struct{})
}
} }
return res return res
} }
@ -317,6 +335,10 @@ type AccountState struct {
StorageWrites map[common.Hash]common.Hash `json:"StorageWrites,omitempty"` StorageWrites map[common.Hash]common.Hash `json:"StorageWrites,omitempty"`
} }
func (a *AccountState) Empty() bool {
return a.Balance == nil && a.Nonce == nil && a.Code == nil && len(a.StorageWrites) == 0
}
func (a *AccountState) String() string { func (a *AccountState) String() string {
var res bytes.Buffer var res bytes.Buffer
enc := json.NewEncoder(&res) enc := json.NewEncoder(&res)