mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
core/state: make inner statedb explicit, implement alternative logging burn
core/state, core/vm: refactor statedb hooking core/state: trace consensus finalize and system calls eth/tracers/internal/tracetest: fix tests after refactor core/state: some renaming and cleanup of statedb-hooking system core/state: remove unecessary methods, implement hooked subbalance, more testing
This commit is contained in:
parent
4de4fa4b60
commit
8ca0cd582d
15 changed files with 425 additions and 256 deletions
|
|
@ -1774,7 +1774,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
|||
if err != nil {
|
||||
return nil, it.index, err
|
||||
}
|
||||
statedb.SetLogger(bc.logger)
|
||||
|
||||
// If we are past Byzantium, enable prefetching to pull in trie node paths
|
||||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||
|
|
@ -1893,13 +1892,10 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
bc.logger.OnBlockEnd(blockEndErr)
|
||||
}()
|
||||
}
|
||||
var wStateDb = vm.StateDB(statedb)
|
||||
if w := statedb.Wrapped(); w != nil {
|
||||
wStateDb = w
|
||||
}
|
||||
|
||||
// Process block using the parent state as reference point
|
||||
pstart := time.Now()
|
||||
res, err := bc.processor.Process(block, wStateDb, bc.vmConfig)
|
||||
res, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||
if err != nil {
|
||||
bc.reportBlock(block, res, err)
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -81,11 +81,7 @@ type StateDB struct {
|
|||
db Database
|
||||
prefetcher *triePrefetcher
|
||||
trie Trie
|
||||
|
||||
onSelfDestructBurn func(common.Address, *uint256.Int)
|
||||
shim *stateDBLogger
|
||||
|
||||
reader Reader
|
||||
reader Reader
|
||||
|
||||
// originalRoot is the pre-state root, before any changes were made.
|
||||
// It will be updated when the Commit is called.
|
||||
|
|
@ -192,19 +188,6 @@ func New(root common.Hash, db Database) (*StateDB, error) {
|
|||
return sdb, nil
|
||||
}
|
||||
|
||||
func (s *StateDB) SetBurnCallback(fn func(common.Address, *uint256.Int)) {
|
||||
s.onSelfDestructBurn = fn
|
||||
}
|
||||
|
||||
// SetLogger sets the logger for account update hooks.
|
||||
func (s *StateDB) SetLogger(l *tracing.Hooks) {
|
||||
s.shim = newStateDBLogger(s, l)
|
||||
}
|
||||
|
||||
func (s *StateDB) Wrapped() *stateDBLogger {
|
||||
return s.shim
|
||||
}
|
||||
|
||||
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
|
||||
// state trie concurrently while the state is mutated so that when we reach the
|
||||
// commit phase, most of the needed data is already hot.
|
||||
|
|
@ -754,11 +737,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) {
|
||||
delete(s.stateObjects, obj.address)
|
||||
s.markDelete(addr)
|
||||
|
||||
// If ether was sent to account post-selfdestruct it is burnt.
|
||||
if bal := obj.Balance(); bal.Sign() != 0 && obj.selfDestructed && s.onSelfDestructBurn != nil {
|
||||
s.onSelfDestructBurn(obj.address, bal)
|
||||
}
|
||||
// We need to maintain account deletions explicitly (will remain
|
||||
// set indefinitely). Note only the first occurred self-destruct
|
||||
// event is tracked.
|
||||
|
|
|
|||
242
core/state/statedb_hooked.go
Normal file
242
core/state/statedb_hooked.go
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// hookedStateDB represents a statedb which emits calls to tracing-hooks
|
||||
// on state operations.
|
||||
type hookedStateDB struct {
|
||||
inner *StateDB
|
||||
hooks *tracing.Hooks
|
||||
}
|
||||
|
||||
// NewHookedState wraps the given stateDb with the given hooks
|
||||
func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB {
|
||||
s := &hookedStateDB{stateDb, hooks}
|
||||
if s.hooks == nil {
|
||||
s.hooks = new(tracing.Hooks)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) CreateAccount(addr common.Address) {
|
||||
s.inner.CreateAccount(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) CreateContract(addr common.Address) {
|
||||
s.inner.CreateContract(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetBalance(addr common.Address) *uint256.Int {
|
||||
return s.inner.GetBalance(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetNonce(addr common.Address) uint64 {
|
||||
return s.inner.GetNonce(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetCodeHash(addr common.Address) common.Hash {
|
||||
return s.inner.GetCodeHash(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetCode(addr common.Address) []byte {
|
||||
return s.inner.GetCode(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetCodeSize(addr common.Address) int {
|
||||
return s.inner.GetCodeSize(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddRefund(u uint64) {
|
||||
s.inner.AddRefund(u)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SubRefund(u uint64) {
|
||||
s.inner.SubRefund(u)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetRefund() uint64 {
|
||||
return s.inner.GetRefund()
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
||||
return s.inner.GetCommittedState(addr, hash)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
||||
return s.inner.GetState(addr, hash)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetStorageRoot(addr common.Address) common.Hash {
|
||||
return s.inner.GetStorageRoot(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
|
||||
return s.inner.GetTransientState(addr, key)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetTransientState(addr common.Address, key, value common.Hash) {
|
||||
s.inner.SetTransientState(addr, key, value)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) HasSelfDestructed(addr common.Address) bool {
|
||||
return s.inner.HasSelfDestructed(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Exist(addr common.Address) bool {
|
||||
return s.inner.Exist(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Empty(addr common.Address) bool {
|
||||
return s.inner.Empty(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddressInAccessList(addr common.Address) bool {
|
||||
return s.inner.AddressInAccessList(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) {
|
||||
return s.inner.SlotInAccessList(addr, slot)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddAddressToAccessList(addr common.Address) {
|
||||
s.inner.AddAddressToAccessList(addr)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
||||
s.inner.AddSlotToAccessList(addr, slot)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) PointCache() *utils.PointCache {
|
||||
return s.inner.PointCache()
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) {
|
||||
s.inner.Prepare(rules, sender, coinbase, dest, precompiles, txAccesses)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) RevertToSnapshot(i int) {
|
||||
s.inner.RevertToSnapshot(i)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Snapshot() int {
|
||||
return s.inner.Snapshot()
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddPreimage(hash common.Hash, bytes []byte) {
|
||||
s.inner.Snapshot()
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Witness() *stateless.Witness {
|
||||
return s.inner.Witness()
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
|
||||
prev := s.inner.SubBalance(addr, amount, reason)
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
newBalance := new(uint256.Int).Sub(&prev, amount)
|
||||
s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
|
||||
prev := s.inner.AddBalance(addr, amount, reason)
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
newBalance := new(uint256.Int).Add(&prev, amount)
|
||||
s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64) {
|
||||
s.inner.SetNonce(address, nonce)
|
||||
if s.hooks.OnNonceChange != nil {
|
||||
s.hooks.OnNonceChange(address, nonce-1, nonce)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetCode(address common.Address, code []byte) {
|
||||
s.inner.SetCode(address, code)
|
||||
if s.hooks.OnCodeChange != nil {
|
||||
s.hooks.OnCodeChange(address, types.EmptyCodeHash, nil, crypto.Keccak256Hash(code), code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetState(address common.Address, key common.Hash, value common.Hash) common.Hash {
|
||||
prev := s.inner.SetState(address, key, value)
|
||||
if s.hooks.OnStorageChange != nil && prev != value {
|
||||
s.hooks.OnStorageChange(address, key, prev, value)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int {
|
||||
prev := s.inner.SelfDestruct(address)
|
||||
if !prev.IsZero() {
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||
}
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Selfdestruct6780(address common.Address) uint256.Int {
|
||||
prev := s.inner.Selfdestruct6780(address)
|
||||
if !prev.IsZero() {
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||
}
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) AddLog(log *types.Log) {
|
||||
// The inner will modify the log (add fields), so invoke that first
|
||||
s.inner.AddLog(log)
|
||||
if s.hooks.OnLog != nil {
|
||||
s.hooks.OnLog(log)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) {
|
||||
defer s.inner.Finalise(deleteEmptyObjects)
|
||||
if s.hooks.OnBalanceChange == nil {
|
||||
return
|
||||
}
|
||||
for addr := range s.inner.journal.dirties {
|
||||
obj := s.inner.stateObjects[addr]
|
||||
if obj != nil && obj.selfDestructed {
|
||||
// If ether was sent to account post-selfdestruct it is burnt.
|
||||
if bal := obj.Balance(); bal.Sign() != 0 {
|
||||
s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
core/state/statedb_hooked_test.go
Normal file
130
core/state/statedb_hooked_test.go
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// This method tests that the 'burn' from sending-to-selfdestructed accounts
|
||||
// is accounted for.
|
||||
// (There is also a higher-level test in eth/tracers: TestSupplySelfDestruct )
|
||||
func TestBurn(t *testing.T) {
|
||||
// Note: burn can happen even after EIP-6780, if within one single transaction,
|
||||
// the following occur:
|
||||
// 1. contract B creates contract A
|
||||
// 2. contract A is destructed
|
||||
// 3. constract B sends ether to A
|
||||
|
||||
var burned = new(uint256.Int)
|
||||
s, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
hooked := NewHookedState(s, &tracing.Hooks{
|
||||
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||
if reason == tracing.BalanceDecreaseSelfdestructBurn {
|
||||
burned.Add(burned, uint256.MustFromBig(prev))
|
||||
}
|
||||
},
|
||||
})
|
||||
createAndDestroy := func(addr common.Address) {
|
||||
hooked.AddBalance(addr, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
|
||||
hooked.CreateContract(addr)
|
||||
hooked.SelfDestruct(addr)
|
||||
// sanity-check that balance is now 0
|
||||
if have, want := hooked.GetBalance(addr), new(uint256.Int); !have.Eq(want) {
|
||||
t.Fatalf("post-destruct balance wrong: have %v want %v", have, want)
|
||||
}
|
||||
}
|
||||
addA := common.Address{0xaa}
|
||||
addB := common.Address{0xbb}
|
||||
addC := common.Address{0xcc}
|
||||
|
||||
// Tx 1: create and destroy address A and B in one tx
|
||||
createAndDestroy(addA)
|
||||
createAndDestroy(addB)
|
||||
hooked.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
hooked.AddBalance(addB, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
hooked.Finalise(true)
|
||||
|
||||
// Tx 2: create and destroy address C, then commit
|
||||
createAndDestroy(addC)
|
||||
hooked.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
hooked.Finalise(true)
|
||||
|
||||
s.Commit(0, false)
|
||||
if have, want := burned, uint256.NewInt(600); !have.Eq(want) {
|
||||
t.Fatalf("burn-count wrong, have %v want %v", have, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHooks is a basic sanity-check of all hooks
|
||||
func TestHooks(t *testing.T) {
|
||||
inner, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
inner.SetTxContext(common.Hash{0x11}, 100) // For the log
|
||||
var result []string
|
||||
var wants = []string{
|
||||
"0xaa00000000000000000000000000000000000000.balance: 0->100 (BalanceChangeUnspecified)",
|
||||
"0xaa00000000000000000000000000000000000000.balance: 100->50 (BalanceChangeTransfer)",
|
||||
"0xaa00000000000000000000000000000000000000.nonce: 1336->1337",
|
||||
"0xaa00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728)",
|
||||
"0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000000 ->0x0000000000000000000000000000000000000000000000000000000000000011",
|
||||
"0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000011 ->0x0000000000000000000000000000000000000000000000000000000000000022",
|
||||
"log 100",
|
||||
}
|
||||
emitF := func(format string, a ...any) {
|
||||
result = append(result, fmt.Sprintf(format, a...))
|
||||
}
|
||||
sdb := NewHookedState(inner, &tracing.Hooks{
|
||||
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||
emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason)
|
||||
},
|
||||
OnNonceChange: func(addr common.Address, prev, new uint64) {
|
||||
emitF("%v.nonce: %v->%v", addr, prev, new)
|
||||
},
|
||||
OnCodeChange: func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) {
|
||||
emitF("%v.code: %#x (%v) ->%#x (%v)", addr, prevCode, prevCodeHash, code, codeHash)
|
||||
},
|
||||
OnStorageChange: func(addr common.Address, slot common.Hash, prev, new common.Hash) {
|
||||
emitF("%v.storage slot %v: %v ->%v", addr, slot, prev, new)
|
||||
},
|
||||
OnLog: func(log *types.Log) {
|
||||
emitF("log %v", log.TxIndex)
|
||||
},
|
||||
})
|
||||
sdb.AddBalance(common.Address{0xaa}, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
|
||||
sdb.SubBalance(common.Address{0xaa}, uint256.NewInt(50), tracing.BalanceChangeTransfer)
|
||||
sdb.SetNonce(common.Address{0xaa}, 1337)
|
||||
sdb.SetCode(common.Address{0xaa}, []byte{0x13, 37})
|
||||
sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x11"))
|
||||
sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x22"))
|
||||
sdb.SetTransientState(common.Address{0xaa}, common.HexToHash("0x02"), common.HexToHash("0x01"))
|
||||
sdb.SetTransientState(common.Address{0xaa}, common.HexToHash("0x02"), common.HexToHash("0x02"))
|
||||
sdb.AddLog(&types.Log{
|
||||
Address: common.Address{0xbb},
|
||||
})
|
||||
for i, want := range wants {
|
||||
if have := result[i]; have != want {
|
||||
t.Fatalf("error event %d, have\n%v\nwant%v\n", i, have, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type stateDBLogger struct {
|
||||
*StateDB
|
||||
hooks *tracing.Hooks
|
||||
}
|
||||
|
||||
func newStateDBLogger(db *StateDB, hooks *tracing.Hooks) *stateDBLogger {
|
||||
s := &stateDBLogger{db, hooks}
|
||||
if s.hooks == nil {
|
||||
s.hooks = new(tracing.Hooks)
|
||||
}
|
||||
db.SetBurnCallback(func(address common.Address, amount *uint256.Int) {
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
s.hooks.OnBalanceChange(address, amount.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
|
||||
}
|
||||
})
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) AddBalance(address common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
|
||||
prev := s.StateDB.AddBalance(address, amount, reason)
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
newBalance := new(uint256.Int).Add(&prev, amount)
|
||||
s.hooks.OnBalanceChange(address, prev.ToBig(), newBalance.ToBig(), reason)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) SetNonce(address common.Address, nonce uint64) {
|
||||
s.StateDB.SetNonce(address, nonce)
|
||||
if s.hooks.OnNonceChange != nil {
|
||||
s.hooks.OnNonceChange(address, nonce-1, nonce)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) SetCode(address common.Address, code []byte) {
|
||||
s.StateDB.SetCode(address, code)
|
||||
if s.hooks.OnCodeChange != nil {
|
||||
s.hooks.OnCodeChange(address, types.EmptyCodeHash, nil, crypto.Keccak256Hash(code), code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) SetState(address common.Address, key common.Hash, value common.Hash) common.Hash {
|
||||
prev := s.StateDB.SetState(address, key, value)
|
||||
if s.hooks.OnStorageChange != nil && prev != value {
|
||||
s.hooks.OnStorageChange(address, key, prev, value)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) SelfDestruct(address common.Address) uint256.Int {
|
||||
prev := s.StateDB.SelfDestruct(address)
|
||||
if !prev.IsZero() {
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||
}
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) Selfdestruct6780(address common.Address) uint256.Int {
|
||||
prev := s.StateDB.Selfdestruct6780(address)
|
||||
if !prev.IsZero() {
|
||||
if s.hooks.OnBalanceChange != nil {
|
||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||
}
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
func (s *stateDBLogger) AddLog(log *types.Log) {
|
||||
// The inner will modify the log (add fields), so invoke that first
|
||||
s.StateDB.AddLog(log)
|
||||
if s.hooks.OnLog != nil {
|
||||
s.hooks.OnLog(log)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
|
@ -1378,53 +1377,3 @@ func TestStorageDirtiness(t *testing.T) {
|
|||
state.RevertToSnapshot(snap)
|
||||
checkDirty(common.Hash{0x1}, common.Hash{0x1}, true)
|
||||
}
|
||||
|
||||
// This method tests that the 'burn' from sending-to-selfdestructed accounts
|
||||
// is accounted for.
|
||||
// (There is also a higher-level test in eth/tracers: TestSupplySelfDestruct )
|
||||
func TestBurn(t *testing.T) {
|
||||
// Note: burn can happen even after EIP-6780, if within one single transaction,
|
||||
// the following occur:
|
||||
// 1. contract B creates contract A
|
||||
// 2. contract A is destructed
|
||||
// 3. constract B sends ether to A
|
||||
|
||||
var burned = new(uint256.Int)
|
||||
s, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
sdblog := newStateDBLogger(s, &tracing.Hooks{
|
||||
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||
if reason == tracing.BalanceDecreaseSelfdestructBurn {
|
||||
burned.Add(burned, uint256.MustFromBig(prev))
|
||||
}
|
||||
},
|
||||
})
|
||||
createAndDestroy := func(addr common.Address) {
|
||||
sdblog.AddBalance(addr, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
|
||||
sdblog.CreateContract(addr)
|
||||
sdblog.SelfDestruct(addr)
|
||||
// sanity-check that balance is now 0
|
||||
if have, want := sdblog.GetBalance(addr), new(uint256.Int); !have.Eq(want) {
|
||||
t.Fatalf("post-destruct balance wrong: have %v want %v", have, want)
|
||||
}
|
||||
}
|
||||
addA := common.Address{0xaa}
|
||||
addB := common.Address{0xbb}
|
||||
addC := common.Address{0xcc}
|
||||
|
||||
// Tx 1: create and destroy address A and B in one tx
|
||||
createAndDestroy(addA)
|
||||
createAndDestroy(addB)
|
||||
sdblog.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
sdblog.AddBalance(addB, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
sdblog.Finalise(true)
|
||||
|
||||
// Tx 2: create and destroy address C, then commit
|
||||
createAndDestroy(addC)
|
||||
sdblog.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
|
||||
sdblog.Finalise(true)
|
||||
|
||||
s.Commit(0, false)
|
||||
if have, want := burned, uint256.NewInt(600); !have.Eq(want) {
|
||||
t.Fatalf("burn-count wrong, have %v want %v", have, want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -52,7 +53,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro
|
|||
// Process returns the receipts and logs accumulated during the process and
|
||||
// returns the amount of gas that was used in the process. If any of the
|
||||
// transactions failed to execute due to insufficient gas it will return an error.
|
||||
func (p *StateProcessor) Process(block *types.Block, statedb vm.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
var (
|
||||
receipts types.Receipts
|
||||
usedGas = new(uint64)
|
||||
|
|
@ -98,7 +99,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb vm.StateDB, cfg vm.
|
|||
receipts = append(receipts, receipt)
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
}
|
||||
|
||||
var tracingStateDB = vm.StateDB(statedb)
|
||||
if hooks := cfg.Tracer; hooks != nil {
|
||||
tracingStateDB = state.NewHookedState(statedb, hooks)
|
||||
}
|
||||
// Read requests if Prague is enabled.
|
||||
var requests [][]byte
|
||||
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||
|
|
@ -109,15 +113,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb vm.StateDB, cfg vm.
|
|||
}
|
||||
requests = append(requests, depositRequests)
|
||||
// EIP-7002 withdrawals
|
||||
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
|
||||
withdrawalRequests := ProcessWithdrawalQueue(vmenv, tracingStateDB)
|
||||
requests = append(requests, withdrawalRequests)
|
||||
// EIP-7251 consolidations
|
||||
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
|
||||
consolidationRequests := ProcessConsolidationQueue(vmenv, tracingStateDB)
|
||||
requests = append(requests, consolidationRequests)
|
||||
}
|
||||
|
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.chain.engine.Finalize(p.chain, header, statedb, block.Body())
|
||||
p.chain.engine.Finalize(p.chain, header, tracingStateDB, block.Body())
|
||||
|
||||
return &ProcessResult{
|
||||
Receipts: receipts,
|
||||
|
|
@ -130,19 +134,21 @@ func (p *StateProcessor) Process(block *types.Block, statedb vm.StateDB, cfg vm.
|
|||
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
||||
// this method takes an already created EVM instance as input.
|
||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb vm.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
|
||||
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
if evm.Config.Tracer.OnTxEnd != nil {
|
||||
defer func() {
|
||||
evm.Config.Tracer.OnTxEnd(receipt, err)
|
||||
}()
|
||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||
var tracingStateDB = vm.StateDB(statedb)
|
||||
if hooks := evm.Config.Tracer; hooks != nil {
|
||||
tracingStateDB = state.NewHookedState(statedb, hooks)
|
||||
if hooks.OnTxStart != nil {
|
||||
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
}
|
||||
if hooks.OnTxEnd != nil {
|
||||
defer func() { hooks.OnTxEnd(receipt, err) }()
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new context to be used in the EVM environment.
|
||||
txContext := NewEVMTxContext(msg)
|
||||
evm.Reset(txContext, statedb)
|
||||
evm.Reset(txContext, tracingStateDB)
|
||||
|
||||
// Apply the transaction to the current state (included in the env).
|
||||
result, err := ApplyMessage(evm, msg, gp)
|
||||
|
|
@ -153,7 +159,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||
// Update the state with pending changes.
|
||||
var root []byte
|
||||
if config.IsByzantium(blockNumber) {
|
||||
statedb.Finalise(true)
|
||||
tracingStateDB.Finalise(true)
|
||||
} else {
|
||||
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
|
||||
}
|
||||
|
|
@ -163,7 +169,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||
}
|
||||
|
||||
// MakeReceipt generates the receipt object for a transaction given its execution result.
|
||||
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb vm.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
|
||||
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
|
||||
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
||||
// by the tx.
|
||||
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
|
||||
|
|
@ -204,7 +210,7 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb vm.StateDB, block
|
|||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb vm.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ type Processor interface {
|
|||
// 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 processor (coinbase) and any included uncles.
|
||||
Process(block *types.Block, statedb vm.StateDB, cfg vm.Config) (*ProcessResult, error)
|
||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error)
|
||||
}
|
||||
|
||||
// ProcessResult contains the values computed by Process.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -91,32 +90,9 @@ type StateDB interface {
|
|||
AddPreimage(common.Hash, []byte)
|
||||
|
||||
Witness() *stateless.Witness
|
||||
|
||||
// Finalise must be invoked at the end of a transaction
|
||||
Finalise(bool)
|
||||
// IntermediateRoot computes the current root hash of the state trie.
|
||||
// It is called in
|
||||
// - between transactions (pre-byzantium)
|
||||
// - nowadays only after all transactions,
|
||||
// in order to obtain the state root hash .
|
||||
IntermediateRoot(deleteEmptyObjects bool) common.Hash
|
||||
|
||||
// GetLogs returns the logs matching the specified transaction hash, and annotates
|
||||
// them with the given blockNumber and blockHash.
|
||||
GetLogs(txHash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log
|
||||
// TxIndex returns the current transaction index set by SetTxContext.
|
||||
TxIndex() int
|
||||
|
||||
// SetTxContext sets the current transaction hash and index which are
|
||||
// used when the EVM emits new state logs. It should be invoked before
|
||||
// transaction execution.
|
||||
SetTxContext(txHash common.Hash, txIndex int)
|
||||
|
||||
// GetTrie returns the account trie. Verkle-related
|
||||
GetTrie() state.Trie
|
||||
// AccessEvents returns the access-events collected for verkle-witness processing.
|
||||
AccessEvents() *state.AccessEvents
|
||||
|
||||
// Error returns any memorized database failure occurred previously.
|
||||
Error() error
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
|||
}
|
||||
// The actual TxContext will be created as part of ApplyTransactionWithEVM.
|
||||
vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
||||
statedb.SetLogger(tracer.Hooks)
|
||||
|
||||
// Define a meaningful timeout of a single transaction trace
|
||||
if config.Timeout != nil {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -116,19 +117,17 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
var (
|
||||
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||
context = test.Context.toBlockContext(test.Genesis)
|
||||
state = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
|
||||
st = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
|
||||
)
|
||||
state.Close()
|
||||
st.Close()
|
||||
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
||||
state.StateDB.SetLogger(tracer.Hooks)
|
||||
logState := vm.StateDB(state.StateDB.Wrapped())
|
||||
if logState == nil {
|
||||
logState = state.StateDB
|
||||
logState := vm.StateDB(st.StateDB)
|
||||
if tracer.Hooks != nil {
|
||||
logState = state.NewHookedState(st.StateDB, tracer.Hooks)
|
||||
}
|
||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||
if err != nil {
|
||||
|
|
@ -353,7 +352,7 @@ func TestInternals(t *testing.T) {
|
|||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
state := tests.MakePreState(rawdb.NewMemoryDatabase(),
|
||||
st := tests.MakePreState(rawdb.NewMemoryDatabase(),
|
||||
types.GenesisAlloc{
|
||||
to: types.Account{
|
||||
Code: tc.code,
|
||||
|
|
@ -362,12 +361,11 @@ func TestInternals(t *testing.T) {
|
|||
Balance: big.NewInt(500000000000000),
|
||||
},
|
||||
}, false, rawdb.HashScheme)
|
||||
defer state.Close()
|
||||
state.StateDB.SetLogger(tc.tracer.Hooks)
|
||||
defer st.Close()
|
||||
|
||||
logState := vm.StateDB(state.StateDB.Wrapped())
|
||||
if logState == nil {
|
||||
logState = state.StateDB
|
||||
logState := vm.StateDB(st.StateDB)
|
||||
if hooks := tc.tracer.Hooks; hooks != nil {
|
||||
logState = state.NewHookedState(st.StateDB, hooks)
|
||||
}
|
||||
|
||||
tx, err := types.SignNewTx(key, signer, &types.LegacyTx{
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
|||
return fmt.Errorf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
||||
state.StateDB.SetLogger(tracer.Hooks)
|
||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
||||
state.StateDB.SetLogger(tracer.Hooks)
|
||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
|
|
|
|||
|
|
@ -1208,11 +1208,16 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s
|
|||
if precompiles != nil {
|
||||
evm.SetPrecompiles(precompiles)
|
||||
}
|
||||
|
||||
return applyMessageWithEVM(ctx, evm, msg, state, timeout, gp)
|
||||
res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
|
||||
// If an internal state error occurred, let that have precedence. Otherwise,
|
||||
// a "trie root missing" type of error will masquerade as e.g. "insufficient gas"
|
||||
if err := state.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, state vm.StateDB, timeout time.Duration, gp *core.GasPool) (*core.ExecutionResult, error) {
|
||||
func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, timeout time.Duration, gp *core.GasPool) (*core.ExecutionResult, error) {
|
||||
// Wait for the context to be done and cancel the evm. Even if the
|
||||
// EVM has finished, cancelling may be done (repeatedly)
|
||||
go func() {
|
||||
|
|
@ -1222,9 +1227,6 @@ func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, st
|
|||
|
||||
// Execute the message.
|
||||
result, err := core.ApplyMessage(evm, msg, gp)
|
||||
if err := state.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the timer caused an abort, return an appropriate error message
|
||||
if evm.Cancelled() {
|
||||
|
|
|
|||
|
|
@ -187,10 +187,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
|||
}
|
||||
evm = vm.NewEVM(blockContext, vm.TxContext{GasPrice: new(big.Int)}, sim.state, sim.chainConfig, *vmConfig)
|
||||
)
|
||||
sim.state.SetLogger(tracer.Hooks())
|
||||
logState := vm.StateDB(sim.state.Wrapped())
|
||||
if logState == nil {
|
||||
logState = vm.StateDB(sim.state)
|
||||
var tracingStateDB = vm.StateDB(sim.state)
|
||||
if hooks := tracer.Hooks(); hooks != nil {
|
||||
tracingStateDB = state.NewHookedState(sim.state, hooks)
|
||||
}
|
||||
// It is possible to override precompiles with EVM bytecode, or
|
||||
// move them to another address.
|
||||
|
|
@ -209,8 +208,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
|||
tracer.reset(tx.Hash(), uint(i))
|
||||
// EoA check is always skipped, even in validation mode.
|
||||
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
|
||||
evm.Reset(core.NewEVMTxContext(msg), logState)
|
||||
result, err := applyMessageWithEVM(ctx, evm, msg, logState, timeout, sim.gp)
|
||||
evm.Reset(core.NewEVMTxContext(msg), tracingStateDB)
|
||||
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
||||
if err != nil {
|
||||
txErr := txValidationError(err)
|
||||
return nil, nil, txErr
|
||||
|
|
@ -218,7 +217,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
|||
// Update the state with pending changes.
|
||||
var root []byte
|
||||
if sim.chainConfig.IsByzantium(blockContext.BlockNumber) {
|
||||
sim.state.Finalise(true)
|
||||
tracingStateDB.Finalise(true)
|
||||
} else {
|
||||
root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue