From 318dc843145303db11f2631a8f9b281a26b77be8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 14 Feb 2024 16:52:10 +0100 Subject: [PATCH 01/33] add config for tracers --- cmd/geth/chaincmd.go | 1 + cmd/geth/config.go | 7 ++++++- cmd/geth/main.go | 1 + cmd/utils/flags.go | 13 +++++++++++-- eth/tracers/directory/live/dir.go | 7 ++++--- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 2627c6caf3..5c53bd2962 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -98,6 +98,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, utils.VMTraceFlag, + utils.VMTraceConfigFlag, utils.TransactionHistoryFlag, utils.StateHistoryFlag, }, utils.DatabaseFlags), diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 3f5303259b..95d59a04fa 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -18,6 +18,7 @@ package main import ( "bufio" + "encoding/json" "errors" "fmt" "os" @@ -182,7 +183,11 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if ctx.IsSet(utils.VMTraceFlag.Name) { if name := ctx.String(utils.VMTraceFlag.Name); name != "" { - t, err := live.Directory.New(name) + var config string + if ctx.IsSet(utils.VMTraceConfigFlag.Name) { + config = ctx.String(utils.VMTraceConfigFlag.Name) + } + t, err := live.Directory.New(name, json.RawMessage(config)) if err != nil { utils.Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 7aee35753d..bb3e49b2ed 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -138,6 +138,7 @@ var ( utils.DeveloperPeriodFlag, utils.VMEnableDebugFlag, utils.VMTraceFlag, + utils.VMTraceConfigFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, utils.NoCompactionFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 81f16458f8..2490e79fe5 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -21,6 +21,7 @@ import ( "context" "crypto/ecdsa" "encoding/hex" + "encoding/json" "errors" "fmt" "math" @@ -538,7 +539,11 @@ var ( Usage: "Name of tracer which should record internal VM operations (costly)", Category: flags.VMCategory, } - + VMTraceConfigFlag = &cli.StringFlag{ + Name: "vmtrace.config", + Usage: "Tracer configuration (JSON)", + Category: flags.VMCategory, + } // API options. RPCGlobalGasCapFlag = &cli.Uint64Flag{ Name: "rpc.gascap", @@ -2194,7 +2199,11 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { - t, err := live.Directory.New(name) + var config string + if ctx.IsSet(VMTraceConfigFlag.Name) { + config = ctx.String(VMTraceConfigFlag.Name) + } + t, err := live.Directory.New(name, json.RawMessage(config)) if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index 011d27f887..39d1e99caa 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -1,12 +1,13 @@ package live import ( + "encoding/json" "errors" "github.com/ethereum/go-ethereum/core" ) -type ctorFunc func() (core.BlockchainLogger, error) +type ctorFunc func(config json.RawMessage) (core.BlockchainLogger, error) // Directory is the collection of tracers which can be used // during normal block import operations. @@ -22,9 +23,9 @@ func (d *directory) Register(name string, f ctorFunc) { } // New instantiates a tracer by name. -func (d *directory) New(name string) (core.BlockchainLogger, error) { +func (d *directory) New(name string, config json.RawMessage) (core.BlockchainLogger, error) { if f, ok := d.elems[name]; ok { - return f() + return f(config) } return nil, errors.New("not found") } From d17940d2e73a72b82f67aeb4925fa3d0268d1ea5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 14 Feb 2024 16:54:51 +0100 Subject: [PATCH 02/33] minor fix --- eth/tracers/live/noop.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 4ff4153c60..cc597adfc5 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -1,6 +1,7 @@ package live import ( + "encoding/json" "math/big" "github.com/ethereum/go-ethereum/common" @@ -22,7 +23,7 @@ func init() { // as soon as we have a real live tracer. type noop struct{} -func newNoopTracer() (core.BlockchainLogger, error) { +func newNoopTracer(_ json.RawMessage) (core.BlockchainLogger, error) { return &noop{}, nil } From b210cc761dde5979ddf8d819bebd12bed7c0e5ab Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Feb 2024 16:05:55 +0100 Subject: [PATCH 03/33] remove onBeaconBlockRoot events --- core/blockchain.go | 2 -- core/state_processor.go | 6 ------ eth/tracers/live/noop.go | 3 --- 3 files changed, 11 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 33c9b0f7c9..74a226b78b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -200,8 +200,6 @@ type BlockchainLogger interface { OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, skip bool) OnBlockEnd(err error) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) - OnBeaconBlockRootStart(root common.Hash) - OnBeaconBlockRootEnd() } // BlockChain represents the canonical chain given a database with a genesis diff --git a/core/state_processor.go b/core/state_processor.go index 231f63f969..76dd0fdb1e 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -184,12 +184,6 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB, logger BlockchainLogger) { - if logger != nil { - logger.OnBeaconBlockRootStart(beaconRoot) - defer func() { - logger.OnBeaconBlockRootEnd() - }() - } // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index cc597adfc5..c565feced0 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -55,9 +55,6 @@ func (t *noop) CaptureEnter(typ vm.OpCode, from common.Address, to common.Addres func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (t *noop) OnBeaconBlockRootStart(root common.Hash) {} -func (t *noop) OnBeaconBlockRootEnd() {} - func (t *noop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { } From 8ec4560e1724e948729e137ef99c77ad0ebda848 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Feb 2024 16:22:59 +0100 Subject: [PATCH 04/33] refactor onBlockStart params, new skip method --- core/blockchain.go | 34 ++++++++++++++++++++++++++-------- eth/tracers/live/noop.go | 4 +++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 74a226b78b..e08c939f1e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -185,6 +185,15 @@ func DefaultCacheConfigWithScheme(scheme string) *CacheConfig { return &config } +// BlockEvent is emitted upon tracing an incoming block. +// It contains the block as well as consensus related information. +type BlockEvent struct { + Block *types.Block + TD *big.Int + Finalized *types.Header + Safe *types.Header +} + // BlockchainLogger is used to collect traces during chain processing. // Please make a copy of the referenced types if you intend to retain them. type BlockchainLogger interface { @@ -193,12 +202,12 @@ type BlockchainLogger interface { OnBlockchainInit(chainConfig *params.ChainConfig) // OnBlockStart is called before executing `block`. // `td` is the total difficulty prior to `block`. - // `skip` indicates processing of this previously known block - // will be skipped. OnBlockStart and OnBlockEnd will be emitted to - // convey how chain is progressing. E.g. known blocks will be skipped - // when node is started after a crash. - OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, skip bool) + OnBlockStart(event BlockEvent) OnBlockEnd(err error) + // OnSkippedBlock indicates a block was skipped during processing + // due to it being known previously. This can happen e.g. when recovering + // from a crash. + OnSkippedBlock(event BlockEvent) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) } @@ -1811,8 +1820,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } stats.processed++ if bc.logger != nil { - bc.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), true) - bc.logger.OnBlockEnd(nil) + bc.logger.OnSkippedBlock(BlockEvent{ + Block: block, + TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1), + Finalized: bc.CurrentFinalBlock(), + Safe: bc.CurrentSafeBlock(), + }) } // We can assume that logs are empty here, since the only way for consecutive @@ -1940,7 +1953,12 @@ type blockProcessingResult struct { func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) { if bc.logger != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), false) + bc.logger.OnBlockStart(BlockEvent{ + Block: block, + TD: td, + Finalized: bc.CurrentFinalBlock(), + Safe: bc.CurrentSafeBlock(), + }) defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index c565feced0..fe835e1d81 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -61,12 +61,14 @@ func (t *noop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Ad func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { } -func (t *noop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header, skip bool) { +func (t *noop) OnBlockStart(ev core.BlockEvent) { } func (t *noop) OnBlockEnd(err error) { } +func (t *noop) OnSkippedBlock(ev core.BlockEvent) {} + func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { } From 4df6904051eb7b0573174e7191f37b6b671f56f0 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 16 Feb 2024 11:20:56 +0100 Subject: [PATCH 05/33] use struct for tracing events # Conflicts: # core/blockchain.go # core/state/state_object.go # core/state/statedb.go --- cmd/geth/config.go | 3 ++- cmd/utils/flags.go | 3 ++- core/blockchain.go | 25 +++++++++------------ core/state/state_object.go | 8 +++---- core/state/statedb.go | 11 ++++----- core/vm/interpreter.go | 8 ++++--- eth/backend.go | 1 + eth/ethconfig/config.go | 4 +++- eth/tracers/directory/live/dir.go | 37 +++++++++++++++++++++++++++++-- eth/tracers/live/noop.go | 17 ++++++++++++-- 10 files changed, 83 insertions(+), 34 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 95d59a04fa..d6ab18d805 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -192,7 +192,8 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { utils.Fatalf("Failed to create tracer %q: %v", name, err) } - cfg.Eth.VMTracer = t + cfg.Eth.VMTracer = t.VMLogger + cfg.Eth.LiveLogger = t } } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 2490e79fe5..abff65a09f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2207,7 +2207,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } - vmcfg.Tracer = t + vmcfg.LiveLogger = t + vmcfg.Tracer = t.VMLogger } } // Disable transaction indexing/unindexing by default. diff --git a/core/blockchain.go b/core/blockchain.go index e08c939f1e..bb5a36ba44 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/syncx" @@ -284,7 +285,7 @@ type BlockChain struct { processor Processor // Block transaction processor interface forker *ForkChoice vmConfig vm.Config - logger BlockchainLogger + logger *live.LiveLogger } // NewBlockChain returns a fully initialised block chain using information @@ -296,15 +297,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Open trie database with provided config triedb := trie.NewDatabase(db, cacheConfig.triedbConfig()) - var logger BlockchainLogger - if vmConfig.Tracer != nil { - l, ok := vmConfig.Tracer.(BlockchainLogger) - if ok { - logger = l - } else { - log.Warn("only extended tracers are supported for live mode") - } - } + // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the // stored one from database. @@ -336,7 +329,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks), engine: engine, vmConfig: vmConfig, - logger: logger, + logger: vmConfig.LiveLogger, } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) @@ -463,7 +456,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } - if bc.logger != nil { + if bc.logger != nil && bc.logger.OnGenesisBlock != nil { if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { alloc, err := getGenesisState(bc.db, block.Hash()) if err != nil { @@ -514,7 +507,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } - if bc.logger != nil { + if bc.logger != nil && bc.logger.OnBlockchainInit != nil { bc.logger.OnBlockchainInit(chainConfig) } // Start tx indexer/unindexer if required. @@ -1819,7 +1812,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } stats.processed++ - if bc.logger != nil { + if bc.logger != nil && bc.logger.OnSkippedBlock != nil { bc.logger.OnSkippedBlock(BlockEvent{ Block: block, TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1), @@ -1951,7 +1944,7 @@ type blockProcessingResult struct { // processBlock executes and validates the given block. If there was no error // it writes the block and associated state to database. func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) { - if bc.logger != nil { + if bc.logger != nil && bc.logger.OnBlockStart != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) bc.logger.OnBlockStart(BlockEvent{ Block: block, @@ -1959,6 +1952,8 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s Finalized: bc.CurrentFinalBlock(), Safe: bc.CurrentSafeBlock(), }) + } + if bc.logger != nil && bc.logger.OnBlockEnd != nil { defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/core/state/state_object.go b/core/state/state_object.go index f9cc0109a2..b6decf7717 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -239,7 +239,7 @@ func (s *stateObject) SetState(key, value common.Hash) { key: key, prevalue: prev, }) - if s.db.logger != nil { + if s.db.logger != nil && s.db.logger.OnStorageChange != nil { s.db.logger.OnStorageChange(s.address, key, prev, value) } s.setState(key, value) @@ -430,7 +430,7 @@ func (s *stateObject) SetBalance(amount *big.Int, reason BalanceChangeReason) { account: &s.address, prev: new(big.Int).Set(s.data.Balance), }) - if s.db.logger != nil { + if s.db.logger != nil && s.db.logger.OnBalanceChange != nil { s.db.logger.OnBalanceChange(s.address, s.Balance(), amount, reason) } s.setBalance(amount) @@ -510,7 +510,7 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { prevhash: s.CodeHash(), prevcode: prevcode, }) - if s.db.logger != nil { + if s.db.logger != nil && s.db.logger.OnCodeChange != nil { s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code) } s.setCode(codeHash, code) @@ -527,7 +527,7 @@ func (s *stateObject) SetNonce(nonce uint64) { account: &s.address, prev: s.data.Nonce, }) - if s.db.logger != nil { + if s.db.logger != nil && s.db.logger.OnNonceChange != nil { s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce) } s.setNonce(nonce) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0c2a5b5aef..5eabbcaeb3 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" @@ -77,7 +78,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState - logger StateLogger + logger *live.LiveLogger snaps *snapshot.Tree // Nil if snapshot is not available snap snapshot.Snapshot // Nil if snapshot is not available @@ -188,7 +189,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) } // SetLogger sets the logger for account update hooks. -func (s *StateDB) SetLogger(l StateLogger) { +func (s *StateDB) SetLogger(l *live.LiveLogger) { s.logger = l } @@ -232,7 +233,7 @@ func (s *StateDB) AddLog(log *types.Log) { log.TxHash = s.thash log.TxIndex = uint(s.txIndex) log.Index = s.logSize - if s.logger != nil { + if s.logger != nil && s.logger.OnLog != nil { s.logger.OnLog(log) } s.logs[s.thash] = append(s.logs[s.thash], log) @@ -479,7 +480,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prev: stateObject.selfDestructed, prevbalance: new(big.Int).Set(stateObject.Balance()), }) - if s.logger != nil && prev.Sign() > 0 { + if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 { s.logger.OnBalanceChange(addr, prev, n, BalanceDecreaseSelfdestruct) } stateObject.markSelfdestructed() @@ -868,7 +869,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { obj.deleted = true // If ether was sent to account post-selfdestruct it is burnt. - if bal := obj.Balance(); s.logger != nil && obj.selfDestructed && bal.Sign() != 0 { + if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 { s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceDecreaseSelfdestructBurn) } // We need to maintain account deletions explicitly (will remain diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 3eff0d25db..7750517e06 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -20,15 +20,17 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" ) // Config are the configuration options for the Interpreter type Config struct { Tracer EVMLogger // Opcode logger - NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) - EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages - ExtraEips []int // Additional EIPS that are to be enabled + LiveLogger *live.LiveLogger + NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) + EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages + ExtraEips []int // Additional EIPS that are to be enabled } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/backend.go b/eth/backend.go index 1ba7552d76..abb6a7e7c2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -193,6 +193,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, Tracer: config.VMTracer, + LiveLogger: config.LiveLogger, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 3ff1ae0013..b5e2f2368c 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" @@ -153,7 +154,8 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTracer vm.EVMLogger + VMTracer vm.EVMLogger + LiveLogger *live.LiveLogger // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index 39d1e99caa..f6656ac79f 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -3,11 +3,44 @@ package live import ( "encoding/json" "errors" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "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/params" ) -type ctorFunc func(config json.RawMessage) (core.BlockchainLogger, error) +type LiveLogger struct { + VMLogger vm.EVMLogger + + /* + - Chain events - + */ + OnBlockchainInit func(chainConfig *params.ChainConfig) + // OnBlockStart is called before executing `block`. + // `td` is the total difficulty prior to `block`. + OnBlockStart func(event core.BlockEvent) + OnBlockEnd func(err error) + // OnSkippedBlock indicates a block was skipped during processing + // due to it being known previously. This can happen e.g. when recovering + // from a crash. + OnSkippedBlock func(event core.BlockEvent) + OnGenesisBlock func(genesis *types.Block, alloc core.GenesisAlloc) + + /* + - State events - + */ + OnBalanceChange func(addr common.Address, prev, new *big.Int, reason state.BalanceChangeReason) + OnNonceChange func(addr common.Address, prev, new uint64) + OnCodeChange func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) + OnStorageChange func(addr common.Address, slot common.Hash, prev, new common.Hash) + OnLog func(log *types.Log) +} + +type ctorFunc func(config json.RawMessage) (*LiveLogger, error) // Directory is the collection of tracers which can be used // during normal block import operations. @@ -23,7 +56,7 @@ func (d *directory) Register(name string, f ctorFunc) { } // New instantiates a tracer by name. -func (d *directory) New(name string, config json.RawMessage) (core.BlockchainLogger, error) { +func (d *directory) New(name string, config json.RawMessage) (*LiveLogger, error) { if f, ok := d.elems[name]; ok { return f(config) } diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index fe835e1d81..f9b8e19def 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -23,8 +23,21 @@ func init() { // as soon as we have a real live tracer. type noop struct{} -func newNoopTracer(_ json.RawMessage) (core.BlockchainLogger, error) { - return &noop{}, nil +func newNoopTracer(_ json.RawMessage) (*live.LiveLogger, error) { + t := &noop{} + return &live.LiveLogger{ + VMLogger: t, + OnBlockchainInit: t.OnBlockchainInit, + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnSkippedBlock: t.OnSkippedBlock, + OnGenesisBlock: t.OnGenesisBlock, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. From 4e43718bd0257180710223b4dd3e2462871a50d0 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 21 Feb 2024 18:47:59 +0100 Subject: [PATCH 06/33] full struct-based tracing infra # Conflicts: # consensus/beacon/consensus.go # consensus/ethash/consensus.go # consensus/misc/dao.go # core/blockchain.go # core/evm.go # core/genesis.go # core/state/dump.go # core/state/state_object.go # core/state/statedb.go # core/state_transition.go # core/vm/evm.go # core/vm/instructions.go # core/vm/interface.go # internal/ethapi/api.go --- cmd/geth/config.go | 3 +- cmd/utils/flags.go | 3 +- consensus/beacon/consensus.go | 3 +- consensus/ethash/consensus.go | 5 +- consensus/misc/dao.go | 5 +- core/blockchain.go | 35 ++------ core/chain_makers.go | 2 +- core/evm.go | 6 +- core/genesis.go | 7 +- core/state/dump.go | 17 ++-- core/state/metadata.go | 66 -------------- core/state/state_object.go | 9 +- core/state/statedb.go | 30 ++----- core/state_processor.go | 24 ++++-- core/state_transition.go | 24 +++--- core/vm/contract.go | 5 +- core/vm/contracts.go | 7 +- core/vm/evm.go | 62 +++++++++----- core/vm/instructions.go | 28 +++--- core/vm/interface.go | 6 +- core/vm/interpreter.go | 60 ++++++++++--- core/vm/logger.go | 70 +-------------- core/vm/operations_acl.go | 3 +- eth/backend.go | 1 - eth/ethconfig/config.go | 4 +- eth/tracers/api.go | 12 +-- eth/tracers/directory/live/dir.go | 83 ++++++++++++++++-- eth/tracers/directory/noop.go | 40 ++++++--- eth/tracers/directory/tracers.go | 18 ++-- eth/tracers/js/goja.go | 45 ++++++---- eth/tracers/live/noop.go | 52 +++++++----- eth/tracers/logger/access_list_tracer.go | 15 +++- eth/tracers/logger/logger.go | 60 ++++++++----- eth/tracers/logger/logger_json.go | 30 ++++--- eth/tracers/native/4byte.go | 22 +++-- eth/tracers/native/call.go | 32 +++++-- eth/tracers/native/call_flat.go | 35 +++++--- eth/tracers/native/mux.go | 104 +++++++++++++++++------ eth/tracers/native/prestate.go | 28 ++++-- internal/ethapi/api.go | 5 +- miner/worker.go | 2 +- 41 files changed, 604 insertions(+), 464 deletions(-) delete mode 100644 core/state/metadata.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d6ab18d805..95d59a04fa 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -192,8 +192,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { utils.Fatalf("Failed to create tracer %q: %v", name, err) } - cfg.Eth.VMTracer = t.VMLogger - cfg.Eth.LiveLogger = t + cfg.Eth.VMTracer = t } } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index abff65a09f..2490e79fe5 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2207,8 +2207,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } - vmcfg.LiveLogger = t - vmcfg.Tracer = t.VMLogger + vmcfg.Tracer = t } } // Disable transaction indexing/unindexing by default. diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 9ab9026fa8..42bf2bd7f9 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -357,7 +358,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(big.Int).SetUint64(w.Amount) amount = amount.Mul(amount, big.NewInt(params.GWei)) - stateDB.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) + stateDB.AddBalance(w.Address, amount, live.BalanceIncreaseWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 5c00e5c7bc..e09bfa10a0 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -564,10 +565,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, big8) - stateDB.AddBalance(uncle.Coinbase, r, state.BalanceIncreaseRewardMineUncle) + stateDB.AddBalance(uncle.Coinbase, r, live.BalanceIncreaseRewardMineUncle) r.Div(blockReward, big32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock) + stateDB.AddBalance(header.Coinbase, reward, live.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index bc393a9cbc..1f97527588 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -80,7 +81,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) { // Move every DAO account and extra-balance account funds into the refund contract for _, addr := range params.DAODrainList() { - statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceIncreaseDaoContract) - statedb.SetBalance(addr, new(big.Int), state.BalanceDecreaseDaoAccount) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), live.BalanceIncreaseDaoContract) + statedb.SetBalance(addr, new(big.Int), live.BalanceDecreaseDaoAccount) } } diff --git a/core/blockchain.go b/core/blockchain.go index bb5a36ba44..babfcaf8f2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -186,30 +186,11 @@ func DefaultCacheConfigWithScheme(scheme string) *CacheConfig { return &config } -// BlockEvent is emitted upon tracing an incoming block. -// It contains the block as well as consensus related information. -type BlockEvent struct { - Block *types.Block - TD *big.Int - Finalized *types.Header - Safe *types.Header -} - -// BlockchainLogger is used to collect traces during chain processing. -// Please make a copy of the referenced types if you intend to retain them. -type BlockchainLogger interface { - vm.EVMLogger - state.StateLogger - OnBlockchainInit(chainConfig *params.ChainConfig) - // OnBlockStart is called before executing `block`. - // `td` is the total difficulty prior to `block`. - OnBlockStart(event BlockEvent) - OnBlockEnd(err error) - // OnSkippedBlock indicates a block was skipped during processing - // due to it being known previously. This can happen e.g. when recovering - // from a crash. - OnSkippedBlock(event BlockEvent) - OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) +// txLookup is wrapper over transaction lookup along with the corresponding +// transaction object. +type txLookup struct { + lookup *rawdb.LegacyTxLookupEntry + transaction *types.Transaction } // BlockChain represents the canonical chain given a database with a genesis @@ -329,7 +310,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks), engine: engine, vmConfig: vmConfig, - logger: vmConfig.LiveLogger, + logger: vmConfig.Tracer, } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) @@ -1813,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } stats.processed++ if bc.logger != nil && bc.logger.OnSkippedBlock != nil { - bc.logger.OnSkippedBlock(BlockEvent{ + bc.logger.OnSkippedBlock(live.BlockEvent{ Block: block, TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1), Finalized: bc.CurrentFinalBlock(), @@ -1946,7 +1927,7 @@ type blockProcessingResult struct { func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) { if bc.logger != nil && bc.logger.OnBlockStart != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(BlockEvent{ + bc.logger.OnBlockStart(live.BlockEvent{ Block: block, TD: td, Finalized: bc.CurrentFinalBlock(), diff --git a/core/chain_makers.go b/core/chain_makers.go index 2949162bfe..dbaeb67f28 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -100,7 +100,7 @@ func (b *BlockGen) SetParentBeaconRoot(root common.Hash) { blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) vmenv = vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.cm.config, vm.Config{}) ) - ProcessBeaconBlockRoot(root, vmenv, b.statedb, nil) + ProcessBeaconBlockRoot(root, vmenv, b.statedb) } // addTx adds a transaction to the generated block. If no coinbase has diff --git a/core/evm.go b/core/evm.go index 8b724ac2cf..515f8d78a9 100644 --- a/core/evm.go +++ b/core/evm.go @@ -22,9 +22,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" - "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/eth/tracers/directory/live" ) // ChainContext supports retrieving headers and consensus parameters from the @@ -136,6 +136,6 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { // Transfer subtracts amount from sender and adds amount to recipient using the given Db func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { - db.SubBalance(sender, amount, state.BalanceChangeTransfer) - db.AddBalance(recipient, amount, state.BalanceChangeTransfer) + db.SubBalance(sender, amount, live.BalanceChangeTransfer) + db.AddBalance(recipient, amount, live.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index edd323f67d..8e58bb134e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -131,7 +132,7 @@ func (ga *GenesisAlloc) hash() (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, account.Balance, live.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -152,7 +153,9 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance) + // This is not actually logged via tracer because OnGenesisBlock + // already captures the allocations. + statedb.AddBalance(addr, account.Balance, live.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) diff --git a/core/state/dump.go b/core/state/dump.go index 9ce6cd394b..1840e5b220 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -49,15 +49,14 @@ type DumpCollector interface { // DumpAccount represents an account in the state. type DumpAccount struct { - Balance string `json:"balance"` - Nonce uint64 `json:"nonce"` - Root hexutil.Bytes `json:"root"` - CodeHash hexutil.Bytes `json:"codeHash"` - Code hexutil.Bytes `json:"code,omitempty"` - Storage map[common.Hash]string `json:"storage,omitempty"` - Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode - SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key - + Balance string `json:"balance"` + Nonce uint64 `json:"nonce"` + Root hexutil.Bytes `json:"root"` + CodeHash hexutil.Bytes `json:"codeHash"` + Code hexutil.Bytes `json:"code,omitempty"` + Storage map[common.Hash]string `json:"storage,omitempty"` + Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode + AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key } // Dump represents the full dump in a collected format, as one large map. diff --git a/core/state/metadata.go b/core/state/metadata.go deleted file mode 100644 index 6978e67075..0000000000 --- a/core/state/metadata.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023 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 . - -package state - -// BalanceChangeReason is used to indicate the reason for a balance change, useful -// for tracing and reporting. -type BalanceChangeReason byte - -const ( - BalanceChangeUnspecified BalanceChangeReason = 0 - - // Issuance - // BalanceIncreaseRewardMineUncle is a reward for mining an uncle block. - BalanceIncreaseRewardMineUncle BalanceChangeReason = 1 - // BalanceIncreaseRewardMineBlock is a reward for mining a block. - BalanceIncreaseRewardMineBlock BalanceChangeReason = 2 - // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain. - BalanceIncreaseWithdrawal BalanceChangeReason = 3 - // BalanceIncreaseGenesisBalance is ether allocated at the genesis block. - BalanceIncreaseGenesisBalance BalanceChangeReason = 4 - - // Transaction fees - // BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance. - BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5 - // BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction. - // Part of this gas will be burnt as per EIP-1559 rules. - BalanceDecreaseGasBuy BalanceChangeReason = 6 - // BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution. - BalanceIncreaseGasReturn BalanceChangeReason = 7 - - // DAO fork - // BalanceIncreaseDaoContract is ether sent to the DAO refund contract. - BalanceIncreaseDaoContract BalanceChangeReason = 8 - // BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract. - BalanceDecreaseDaoAccount BalanceChangeReason = 9 - - // BalanceChangeTransfer is ether transferred via a call. - // it is a decrease for the sender and an increase for the recipient. - BalanceChangeTransfer BalanceChangeReason = 10 - // BalanceChangeTouchAccount is a transfer of zero value. It is only there to - // touch-create an account. - BalanceChangeTouchAccount BalanceChangeReason = 11 - - // BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account. - BalanceIncreaseSelfdestruct BalanceChangeReason = 12 - // BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct. - BalanceDecreaseSelfdestruct BalanceChangeReason = 13 - // BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed - // account within the same tx (captured at end of tx). - // Note it doesn't account for a self-destruct which appoints itself as recipient. - BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14 -) diff --git a/core/state/state_object.go b/core/state/state_object.go index b6decf7717..2c7ffbf896 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" @@ -404,7 +405,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) { // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *big.Int, reason BalanceChangeReason) { +func (s *stateObject) AddBalance(amount *big.Int, reason live.BalanceChangeReason) { // EIP161: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.Sign() == 0 { @@ -418,14 +419,14 @@ func (s *stateObject) AddBalance(amount *big.Int, reason BalanceChangeReason) { // SubBalance removes amount from s's balance. // It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *big.Int, reason BalanceChangeReason) { - if amount.Sign() == 0 { +func (s *stateObject) SubBalance(amount *big.Int, reason live.BalanceChangeReason) { + if amount.IsZero() { return } s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason) } -func (s *stateObject) SetBalance(amount *big.Int, reason BalanceChangeReason) { +func (s *stateObject) SetBalance(amount *big.Int, reason live.BalanceChangeReason) { s.db.journal.append(balanceChange{ account: &s.address, prev: new(big.Int).Set(s.data.Balance), diff --git a/core/state/statedb.go b/core/state/statedb.go index 5eabbcaeb3..27bca3d2e8 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -48,20 +48,6 @@ type revision struct { journalIndex int } -// StateLogger is used to collect state update traces from EVM transaction -// execution. -// The following hooks are invoked post execution. I.e. looking up state -// after the hook should reflect the new value. -// Note that reference types are actual VM data structures; make copies -// if you need to retain them beyond the current call. -type StateLogger interface { - OnBalanceChange(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) - OnNonceChange(addr common.Address, prev, new uint64) - OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) - OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) - OnLog(log *types.Log) -} - // StateDB structs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -397,23 +383,23 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool { */ // AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { - stateObject := s.GetOrNewStateObject(addr) +func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { + stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount, reason) } } // SubBalance subtracts amount from the account associated with addr. -func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { - stateObject := s.GetOrNewStateObject(addr) +func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { + stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.SubBalance(amount, reason) } } -func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { - stateObject := s.GetOrNewStateObject(addr) +func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { + stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.SetBalance(amount, reason) } @@ -481,7 +467,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prevbalance: new(big.Int).Set(stateObject.Balance()), }) if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 { - s.logger.OnBalanceChange(addr, prev, n, BalanceDecreaseSelfdestruct) + s.logger.OnBalanceChange(addr, prev, n, live.BalanceDecreaseSelfdestruct) } stateObject.markSelfdestructed() stateObject.data.Balance = new(big.Int) @@ -870,7 +856,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // If ether was sent to account post-selfdestruct it is burnt. if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 { - s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceDecreaseSelfdestructBurn) + s.logger.OnBalanceChange(obj.address, bal, new(big.Int), live.BalanceDecreaseSelfdestructBurn) } // We need to maintain account deletions explicitly (will remain // set indefinitely). Note only the first occurred self-destruct diff --git a/core/state_processor.go b/core/state_processor.go index 76dd0fdb1e..776a104223 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -78,7 +79,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg signer = types.MakeSigner(p.config, header.Number, header.Time) ) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb, p.bc.logger) + ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { @@ -110,11 +111,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // 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 *state.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.CaptureTxStart(evm, tx, msg.From) - defer func() { - evm.Config.Tracer.CaptureTxEnd(receipt, err) - }() + if evm.Config.Tracer != nil && evm.Config.Tracer.CaptureTxStart != nil { + evm.Config.Tracer.CaptureTxStart(&live.VMContext{ + ChainConfig: evm.ChainConfig(), + StateDB: statedb, + BlockNumber: evm.Context.BlockNumber, + Time: evm.Context.Time, + Coinbase: evm.Context.Coinbase, + Random: evm.Context.Random, + }, tx, msg.From) + if evm.Config.Tracer.CaptureTxEnd != nil { + defer func() { + evm.Config.Tracer.CaptureTxEnd(receipt, err) + }() + } } // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) @@ -183,7 +193,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. -func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB, logger BlockchainLogger) { +func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ diff --git a/core/state_transition.go b/core/state_transition.go index d734467443..f149d2a3a1 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -24,9 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" cmath "github.com/ethereum/go-ethereum/common/math" - "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -262,14 +262,14 @@ func (st *StateTransition) buyGas() error { return err } - if st.evm.Config.Tracer != nil { - st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance) + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil { + st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, live.GasChangeTxInitialBalance) } st.gasRemaining += st.msg.GasLimit st.initialGas = st.msg.GasLimit - st.state.SubBalance(st.msg.From, mgval, state.BalanceDecreaseGasBuy) + st.state.SubBalance(st.msg.From, mgval, live.BalanceDecreaseGasBuy) return nil } @@ -392,8 +392,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if st.gasRemaining < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) } - if t := st.evm.Config.Tracer; t != nil { - t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, vm.GasChangeTxIntrinsicGas) + if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { + t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, live.GasChangeTxIntrinsicGas) } st.gasRemaining -= gas @@ -443,7 +443,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } else { fee := new(big.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTip) - st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceIncreaseRewardTransactionFee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, live.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -460,18 +460,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { refund = st.state.GetRefund() } - if st.evm.Config.Tracer != nil && refund > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, vm.GasChangeTxRefunds) + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, live.GasChangeTxRefunds) } st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) - st.state.AddBalance(st.msg.From, remaining, state.BalanceIncreaseGasReturn) + st.state.AddBalance(st.msg.From, remaining, live.BalanceIncreaseGasReturn) - if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, live.GasChangeTxLeftOverReturned) } // Also return remaining gas to the block gas counter so it is diff --git a/core/vm/contract.go b/core/vm/contract.go index f7dae713d1..fbfc3b125d 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/holiman/uint256" ) @@ -159,11 +160,11 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64, logger EVMLogger, reason GasChangeReason) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger *live.LiveLogger, reason live.GasChangeReason) (ok bool) { if c.Gas < gas { return false } - if logger != nil && reason != GasChangeIgnored { + if logger != nil && logger.OnGasChange != nil && reason != live.GasChangeIgnored { logger.OnGasChange(c.Gas, c.Gas-gas, reason) } c.Gas -= gas diff --git a/core/vm/contracts.go b/core/vm/contracts.go index bb5dc039f0..799665f0cb 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) @@ -168,13 +169,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger EVMLogger) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *live.LiveLogger) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } - if logger != nil { - logger.OnGasChange(suppliedGas, suppliedGas-gasCost, GasChangeCallPrecompiledContract) + if logger != nil && logger.OnGasChange != nil { + logger.OnGasChange(suppliedGas, suppliedGas-gasCost, live.GasChangeCallPrecompiledContract) } suppliedGas -= gasCost output, err := p.Run(input) diff --git a/core/vm/evm.go b/core/vm/evm.go index 4960d08c77..b291bcfbc6 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -22,9 +22,9 @@ import ( "sync/atomic" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -230,8 +230,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil { - evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) } gas = 0 @@ -286,8 +286,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil { - evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) } gas = 0 @@ -333,8 +333,8 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil { - evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) } gas = 0 } @@ -369,7 +369,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, // but is the correct thing to do and matters on other networks, in tests, and potential // future scenarios - evm.StateDB.AddBalance(addr, new(big.Int), state.BalanceChangeTouchAccount) + evm.StateDB.AddBalance(addr, new(big.Int), live.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) @@ -391,8 +391,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil { - evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) } gas = 0 @@ -442,8 +442,8 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Ensure there's no existing contract already at the designated address contractHash := evm.StateDB.GetCodeHash(address) if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { - if evm.Config.Tracer != nil { - evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) } return nil, common.Address{}, 0, ErrContractAddressCollision @@ -479,7 +479,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // by the error checking condition below. if err == nil { createDataGas := uint64(len(ret)) * params.CreateDataGas - if contract.UseGas(createDataGas, evm.Config.Tracer, GasChangeCallCodeStorage) { + if contract.UseGas(createDataGas, evm.Config.Tracer, live.GasChangeCallCodeStorage) { evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas @@ -492,7 +492,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - contract.UseGas(contract.Gas, evm.Config.Tracer, GasChangeCallFailedExecution) + contract.UseGas(contract.Gas, evm.Config.Tracer, live.GasChangeCallFailedExecution) } } @@ -522,19 +522,23 @@ func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to co tracer := evm.Config.Tracer if isRoot { - tracer.CaptureStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) - } else { - tracer.CaptureEnter(typ, from, to, input, startGas, value) + if tracer.CaptureStart != nil { + tracer.CaptureStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) + } + } else if tracer.CaptureEnter != nil { + tracer.CaptureEnter(live.OpCode(typ), from, to, input, startGas, value) } - tracer.OnGasChange(0, startGas, GasChangeCallInitialBalance) + if tracer.OnGasChange != nil { + tracer.OnGasChange(0, startGas, live.GasChangeCallInitialBalance) + } } func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas uint64, ret []byte, err error) { tracer := evm.Config.Tracer - if leftOverGas != 0 { - tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverReturned) + if leftOverGas != 0 && tracer.OnGasChange != nil { + tracer.OnGasChange(leftOverGas, 0, live.GasChangeCallLeftOverReturned) } var reverted bool if err != nil { @@ -544,8 +548,22 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas reverted = false } if isRoot { - tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) - } else { + if tracer.CaptureEnd != nil { + tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + } + } else if tracer.CaptureExit != nil { tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } } + +func (evm *EVM) GetVMContext() *live.VMContext { + return &live.VMContext{ + Coinbase: evm.Context.Coinbase, + BlockNumber: evm.Context.BlockNumber, + Time: evm.Context.Time, + Random: evm.Context.Random, + GasPrice: evm.TxContext.GasPrice, + ChainConfig: evm.ChainConfig(), + StateDB: evm.StateDB, + } +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index b9c5b153b7..31296aa1a5 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -18,9 +18,9 @@ package vm import ( "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -594,7 +594,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, live.GasChangeCallContractCreation) //TODO: use uint256.Int instead of converting with toBig() var bigVal = big0 if !value.IsZero() { @@ -616,7 +616,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b scope.Stack.push(&stackvalue) if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -642,7 +642,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] ) // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation2) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, live.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size //TODO: use uint256.Int instead of converting with toBig() @@ -661,7 +661,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] scope.Stack.push(&stackvalue) if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -711,7 +711,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -751,7 +751,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -784,7 +784,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -817,7 +817,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) } if interpreter.evm.Config.Tracer != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -855,10 +855,10 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureExit([]byte{}, 0, nil, false) } return nil, errStopToken @@ -870,11 +870,11 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceDecreaseSelfdestruct) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, live.BalanceDecreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureExit([]byte{}, 0, nil, false) } return nil, errStopToken diff --git a/core/vm/interface.go b/core/vm/interface.go index e96e4502fb..94aa015ed9 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,8 +20,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -29,8 +29,8 @@ import ( type StateDB interface { CreateAccount(common.Address) - SubBalance(common.Address, *big.Int, state.BalanceChangeReason) - AddBalance(common.Address, *big.Int, state.BalanceChangeReason) + SubBalance(common.Address, *big.Int, live.BalanceChangeReason) + AddBalance(common.Address, *big.Int, live.BalanceChangeReason) GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 7750517e06..5f86299637 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -22,12 +22,12 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" + "github.com/holiman/uint256" ) // Config are the configuration options for the Interpreter type Config struct { - Tracer EVMLogger // Opcode logger - LiveLogger *live.LiveLogger + Tracer *live.LiveLogger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled @@ -41,6 +41,30 @@ type ScopeContext struct { Contract *Contract } +func (ctx *ScopeContext) GetMemoryData() []byte { + return ctx.Memory.Data() +} + +func (ctx *ScopeContext) GetStackData() []uint256.Int { + return ctx.Stack.Data() +} + +func (ctx *ScopeContext) GetCaller() common.Address { + return ctx.Contract.Caller() +} + +func (ctx *ScopeContext) GetAddress() common.Address { + return ctx.Contract.Address() +} + +func (ctx *ScopeContext) GetCallValue() *uint256.Int { + return ctx.Contract.Value() +} + +func (ctx *ScopeContext) GetCallInput() []byte { + return ctx.Contract.Input +} + // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { evm *EVM @@ -160,9 +184,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( defer func() { if err != nil { if !logged { - in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - } else { - in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + if in.evm.Config.Tracer.CaptureState != nil { + in.evm.Config.Tracer.CaptureState(pcCopy, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + } + } else if in.evm.Config.Tracer.CaptureFault != nil { + in.evm.Config.Tracer.CaptureFault(pcCopy, live.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } } }() @@ -187,7 +213,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } else if sLen > operation.maxStack { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } - if !contract.UseGas(cost, in.evm.Config.Tracer, GasChangeIgnored) { + if !contract.UseGas(cost, in.evm.Config.Tracer, live.GasChangeIgnored) { return nil, ErrOutOfGas } @@ -214,23 +240,31 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing - if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, GasChangeIgnored) { + if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, live.GasChangeIgnored) { return nil, ErrOutOfGas } // Do tracing before memory expansion if debug { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, GasChangeCallOpCode) - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - logged = true + if in.evm.Config.Tracer.OnGasChange != nil { + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, live.GasChangeCallOpCode) + } + if in.evm.Config.Tracer.CaptureState != nil { + in.evm.Config.Tracer.CaptureState(pc, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + logged = true + } } if memorySize > 0 { mem.Resize(memorySize) } } else if debug { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, GasChangeCallOpCode) - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - logged = true + if in.evm.Config.Tracer.OnGasChange != nil { + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, live.GasChangeCallOpCode) + } + if in.evm.Config.Tracer.CaptureState != nil { + in.evm.Config.Tracer.CaptureState(pc, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + logged = true + } } // execute the operation diff --git a/core/vm/logger.go b/core/vm/logger.go index e86bb5d98e..269aed509c 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -16,19 +16,12 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - // EVMLogger is used to collect execution traces from an EVM transaction // execution. CaptureState is called for each step of the VM with the // current VM state. // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. -type EVMLogger interface { +/*type EVMLogger interface { // Transaction level // Call simulations don't come with a valid signature. `from` field // to be used for address of the caller. @@ -55,63 +48,4 @@ type EVMLogger interface { // Misc OnGasChange(old, new uint64, reason GasChangeReason) } - -// GasChangeReason is used to indicate the reason for a gas change, useful -// for tracing and reporting. -// -// There is essentially two types of gas changes, those that can be emitted once per transaction -// and those that can be emitted on a call basis, so possibly multiple times per transaction. -// -// They can be recognized easily by their name, those that start with `GasChangeTx` are emitted -// once per transaction, while those that start with `GasChangeCall` are emitted on a call basis. -type GasChangeReason byte - -const ( - GasChangeUnspecified GasChangeReason = iota - - // GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only - // one such gas change per transaction. - GasChangeTxInitialBalance - // GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is - // always exactly one of those per transaction. - GasChangeTxIntrinsicGas - // GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared) - // this generates an increase in gas. There is at most one of such gas change per transaction. - GasChangeTxRefunds - // GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned - // to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas - // left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller. - // There is at most one of such gas change per transaction. - GasChangeTxLeftOverReturned - - // GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only - // one such gas change per call. - GasChangeCallInitialBalance - // GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always - // be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even - // will be emitted. - GasChangeCallLeftOverReturned - // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it - // executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child. - // If there was no gas left to be refunded, no such even will be emitted. - GasChangeCallLeftOverRefunded - // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. - GasChangeCallContractCreation - // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. - GasChangeCallContractCreation2 - // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. - GasChangeCallCodeStorage - // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was - // performed can be check by `CaptureState` handling. - GasChangeCallOpCode - // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution. - GasChangeCallPrecompiledContract - // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules. - GasChangeCallStorageColdAccess - // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. - GasChangeCallFailedExecution - - // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as - // it will be "manually" tracked by a direct emit of the gas change event. - GasChangeIgnored GasChangeReason = 0xFF -) +*/ diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 55c9bf34b9..e9f26a88c1 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -169,7 +170,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc { evm.StateDB.AddAddressToAccessList(addr) // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, GasChangeCallStorageColdAccess) { + if !contract.UseGas(coldCost, evm.Config.Tracer, live.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } } diff --git a/eth/backend.go b/eth/backend.go index abb6a7e7c2..1ba7552d76 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -193,7 +193,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, Tracer: config.VMTracer, - LiveLogger: config.LiveLogger, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b5e2f2368c..11e43e41b1 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers/directory/live" @@ -154,8 +153,7 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTracer vm.EVMLogger - LiveLogger *live.LiveLogger + VMTracer *live.LiveLogger // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 30f0b23a56..422b672086 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -777,14 +777,14 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Swap out the noop logger to the standard tracer writer = bufio.NewWriter(dump) vmConf = vm.Config{ - Tracer: logger.NewJSONLogger(&logConfig, writer), + Tracer: logger.NewJSONLogger(&logConfig, writer).GetLogger(), EnablePreimageRecording: true, } } // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - vmConf.Tracer.CaptureTxStart(vmenv, tx, msg.From) + vmConf.Tracer.CaptureTxStart(vmenv.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) if writer != nil { @@ -922,7 +922,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // be tracer dependent. func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *directory.Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { var ( - tracer directory.Tracer + tracer *directory.Tracer err error timeout = defaultTraceTimeout ) @@ -930,15 +930,15 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *direc config = &TraceConfig{} } // Default tracer is the struct logger - tracer = logger.NewStructLogger(config.Config) + tracer = logger.NewStructLogger(config.Config).GetTracer() if config.Tracer != nil { tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } } - vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) - statedb.SetLogger(tracer) + vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.LiveLogger, NoBaseFee: true}) + statedb.SetLogger(tracer.LiveLogger) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index f6656ac79f..9e89c0f36c 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -6,15 +6,82 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "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/params" + "github.com/holiman/uint256" ) +type ScopeContext interface { + GetMemoryData() []byte + GetStackData() []uint256.Int + GetCaller() common.Address + GetAddress() common.Address + GetCallValue() *uint256.Int + GetCallInput() []byte +} + +type StateDB interface { + GetBalance(common.Address) *uint256.Int + GetNonce(common.Address) uint64 + GetCode(common.Address) []byte + GetState(common.Address, common.Hash) common.Hash + Exist(common.Address) bool + GetRefund() uint64 +} + +type VMContext struct { + Coinbase common.Address + BlockNumber *big.Int + Time uint64 + Random *common.Hash + // Effective tx gas price + GasPrice *big.Int + ChainConfig *params.ChainConfig + StateDB StateDB +} + +// BlockEvent is emitted upon tracing an incoming block. +// It contains the block as well as consensus related information. +type BlockEvent struct { + Block *types.Block + TD *big.Int + Finalized *types.Header + Safe *types.Header +} + +// OpCode is an EVM opcode +// TODO: provide utils for consumers +type OpCode byte + type LiveLogger struct { - VMLogger vm.EVMLogger + /* + - VM events - + */ + // Transaction level + // Call simulations don't come with a valid signature. `from` field + // to be used for address of the caller. + CaptureTxStart func(vm *VMContext, tx *types.Transaction, from common.Address) + CaptureTxEnd func(receipt *types.Receipt, err error) + // Top call frame + CaptureStart func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) + // CaptureEnd is invoked when the processing of the top call ends. + // See docs for `CaptureExit` for info on the `reverted` parameter. + CaptureEnd func(output []byte, gasUsed uint64, err error, reverted bool) + // Rest of call frames + CaptureEnter func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + // CaptureExit is invoked when the processing of a message ends. + // `revert` is true when there was an error during the execution. + // Exceptionally, before the homestead hardfork a contract creation that + // ran out of gas when attempting to persist the code to database did not + // count as a call failure and did not cause a revert of the call. This will + // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. + CaptureExit func(output []byte, gasUsed uint64, err error, reverted bool) + // Opcode level + CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, rData []byte, depth int, err error) + CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, depth int, err error) + CaptureKeccakPreimage func(hash common.Hash, data []byte) + // Misc + OnGasChange func(old, new uint64, reason GasChangeReason) /* - Chain events - @@ -22,18 +89,18 @@ type LiveLogger struct { OnBlockchainInit func(chainConfig *params.ChainConfig) // OnBlockStart is called before executing `block`. // `td` is the total difficulty prior to `block`. - OnBlockStart func(event core.BlockEvent) + OnBlockStart func(event BlockEvent) OnBlockEnd func(err error) // OnSkippedBlock indicates a block was skipped during processing // due to it being known previously. This can happen e.g. when recovering // from a crash. - OnSkippedBlock func(event core.BlockEvent) - OnGenesisBlock func(genesis *types.Block, alloc core.GenesisAlloc) + OnSkippedBlock func(event BlockEvent) + OnGenesisBlock func(genesis *types.Block, alloc types.GenesisAlloc) /* - State events - */ - OnBalanceChange func(addr common.Address, prev, new *big.Int, reason state.BalanceChangeReason) + OnBalanceChange func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) OnNonceChange func(addr common.Address, prev, new uint64) OnCodeChange func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) OnStorageChange func(addr common.Address, slot common.Hash, prev, new common.Hash) diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 5f6546cfbe..9c28770494 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -21,9 +21,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "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/eth/tracers/directory/live" ) func init() { @@ -35,8 +34,29 @@ func init() { type NoopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer(ctx *Context, _ json.RawMessage) (Tracer, error) { - return &NoopTracer{}, nil +func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { + t := &NoopTracer{} + return &Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureStart: t.CaptureStart, + CaptureEnd: t.CaptureEnd, + CaptureEnter: t.CaptureEnter, + CaptureExit: t.CaptureExit, + CaptureState: t.CaptureState, + CaptureFault: t.CaptureFault, + CaptureKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -48,21 +68,21 @@ func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *NoopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *NoopTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *NoopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *NoopTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, _ live.ScopeContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} // OnGasChange is called when gas is either consumed or refunded. -func (t *NoopTracer) OnGasChange(old, new uint64, reason vm.GasChangeReason) {} +func (t *NoopTracer) OnGasChange(old, new uint64, reason live.GasChangeReason) {} // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } // CaptureExit is called when EVM exits a scope, even if the scope didn't @@ -70,11 +90,11 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) {} +func (*NoopTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) {} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} -func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { } func (*NoopTracer) OnNonceChange(a common.Address, prev, new uint64) {} diff --git a/eth/tracers/directory/tracers.go b/eth/tracers/directory/tracers.go index b16d9d2fe6..4953c46c56 100644 --- a/eth/tracers/directory/tracers.go +++ b/eth/tracers/directory/tracers.go @@ -24,8 +24,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) // Context contains some contextual infos for a transaction execution that is not @@ -41,16 +40,15 @@ type Context struct { // for it to be available through the RPC interface. // This involves a method to retrieve results and one to // stop tracing. -type Tracer interface { - vm.EVMLogger - state.StateLogger - GetResult() (json.RawMessage, error) +type Tracer struct { + *live.LiveLogger + GetResult func() (json.RawMessage, error) // Stop terminates execution of the tracer at the first opportune moment. - Stop(err error) + Stop func(err error) } -type ctorFn func(*Context, json.RawMessage) (Tracer, error) -type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error) +type ctorFn func(*Context, json.RawMessage) (*Tracer, error) +type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error) type elem struct { ctor ctorFn @@ -83,7 +81,7 @@ func (d *directory) RegisterJSEval(f jsCtorFn) { // New returns a new instance of a tracer, by iterating through the // registered lookups. Name is either name of an existing tracer // or an arbitrary JS code. -func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) { +func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (*Tracer, error) { if elem, ok := d.elems[name]; ok { return elem.ctor(ctx, cfg) } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index c3a9508202..f6ed3ed229 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -25,6 +25,7 @@ import ( "github.com/dop251/goja" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -42,9 +43,9 @@ func init() { if err != nil { panic(err) } - type ctorFn = func(*directory.Context, json.RawMessage) (directory.Tracer, error) + type ctorFn = func(*directory.Context, json.RawMessage) (*directory.Tracer, error) lookup := func(code string) ctorFn { - return func(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { + return func(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { return newJsTracer(code, ctx, cfg) } } @@ -99,7 +100,7 @@ type jsTracer struct { directory.NoopTracer vm *goja.Runtime - env *vm.EVM + env *live.VMContext toBig toBigFn // Converts a hex string into a JS bigint toBuf toBufFn // Converts a []byte into a JS buffer fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte @@ -136,7 +137,7 @@ type jsTracer struct { // The methods `result` and `fault` are required to be present. // The methods `step`, `enter`, and `exit` are optional, but note that // `enter` and `exit` always go together. -func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { +func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { vm := goja.New() // By default field names are exported to JS as is, i.e. capitalized. vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) @@ -209,22 +210,36 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (dire t.frameValue = t.frame.setupObject() t.frameResultValue = t.frameResult.setupObject() t.logValue = t.log.setupObject() - return t, nil + + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureStart: t.CaptureStart, + CaptureEnd: t.CaptureEnd, + CaptureEnter: t.CaptureEnter, + CaptureExit: t.CaptureExit, + CaptureState: t.CaptureState, + CaptureFault: t.CaptureFault, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } // CaptureTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *jsTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { t.env = env // Need statedb access for db object db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} t.dbValue = db.setupObject() // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) - t.ctx["block"] = t.vm.ToValue(t.env.Context.BlockNumber.Uint64()) + t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) t.ctx["gas"] = t.vm.ToValue(tx.Gas()) - gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String()) + gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) if err != nil { t.err = err t.env.Cancel() @@ -284,7 +299,7 @@ func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create b } // CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *jsTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -293,7 +308,7 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } log := t.log - log.op.op = op + log.op.op = vm.OpCode(op) log.memory.memory = scope.Memory log.stack.stack = scope.Stack log.contract.contract = scope.Contract @@ -309,7 +324,7 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } // CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *jsTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { if t.err != nil { return } @@ -328,7 +343,7 @@ func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *jsTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { if !t.traceFrame { return } @@ -336,7 +351,7 @@ func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad return } - t.frame.typ = typ.String() + t.frame.typ = vm.OpCode(typ).String() t.frame.from = from t.frame.to = to t.frame.input = common.CopyBytes(input) @@ -681,7 +696,7 @@ func (s *stackObj) setupObject() *goja.Object { } type dbObj struct { - db vm.StateDB + db live.StateDB vm *goja.Runtime toBig toBigFn toBuf toBufFn diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index f9b8e19def..e099ef9ac5 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -5,10 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -26,17 +23,26 @@ type noop struct{} func newNoopTracer(_ json.RawMessage) (*live.LiveLogger, error) { t := &noop{} return &live.LiveLogger{ - VMLogger: t, - OnBlockchainInit: t.OnBlockchainInit, - OnBlockStart: t.OnBlockStart, - OnBlockEnd: t.OnBlockEnd, - OnSkippedBlock: t.OnSkippedBlock, - OnGenesisBlock: t.OnGenesisBlock, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureStart: t.CaptureStart, + CaptureEnd: t.CaptureEnd, + CaptureEnter: t.CaptureEnter, + CaptureExit: t.CaptureExit, + CaptureState: t.CaptureState, + CaptureFault: t.CaptureFault, + CaptureKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBlockchainInit: t.OnBlockchainInit, + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnSkippedBlock: t.OnSkippedBlock, + OnGenesisBlock: t.OnGenesisBlock, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, nil } @@ -49,18 +55,18 @@ func (t *noop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted boo } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noop) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *noop) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noop) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *noop) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, _ live.ScopeContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *noop) CaptureKeccakPreimage(hash common.Hash, data []byte) {} // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *noop) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *noop) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } // CaptureExit is called when EVM exits a scope, even if the scope didn't @@ -68,27 +74,27 @@ func (t *noop) CaptureEnter(typ vm.OpCode, from common.Address, to common.Addres func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (t *noop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *noop) CaptureTxStart(vm *live.VMContext, tx *types.Transaction, from common.Address) { } func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { } -func (t *noop) OnBlockStart(ev core.BlockEvent) { +func (t *noop) OnBlockStart(ev live.BlockEvent) { } func (t *noop) OnBlockEnd(err error) { } -func (t *noop) OnSkippedBlock(ev core.BlockEvent) {} +func (t *noop) OnSkippedBlock(ev live.BlockEvent) {} func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { } -func (t *noop) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +func (t *noop) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { } -func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { } func (t *noop) OnNonceChange(a common.Address, prev, new uint64) { @@ -104,5 +110,5 @@ func (t *noop) OnLog(l *types.Log) { } -func (t *noop) OnGasChange(old, new uint64, reason vm.GasChangeReason) { +func (t *noop) OnGasChange(old, new uint64, reason live.GasChangeReason) { } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 7df66066b5..fdc990dfee 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -132,14 +133,20 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } +func (a *AccessListTracer) GetLogger() *live.LiveLogger { + return &live.LiveLogger{ + CaptureState: a.CaptureState, + } +} + // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - stack := scope.Stack - stackData := stack.Data() +func (a *AccessListTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { + stackData := scope.GetStackData() stackLen := len(stackData) + op := vm.OpCode(opcode) if (op == vm.SLOAD || op == vm.SSTORE) && stackLen >= 1 { slot := common.Hash(stackData[stackLen-1].Bytes32()) - a.list.addSlot(scope.Contract.Address(), slot) + a.list.addSlot(scope.GetAddress(), slot) } if (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT) && stackLen >= 1 { addr := common.Address(stackData[stackLen-1].Bytes20()) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 3c22bd7886..3e8a68e6e5 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -109,7 +110,7 @@ func (s *StructLog) ErrorString() string { type StructLogger struct { directory.NoopTracer cfg Config - env *vm.EVM + env *live.VMContext storage map[common.Address]Storage logs []StructLog @@ -132,6 +133,19 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } +func (l *StructLogger) GetTracer() *directory.Tracer { + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: l.CaptureTxStart, + CaptureTxEnd: l.CaptureTxEnd, + CaptureEnd: l.CaptureEnd, + CaptureState: l.CaptureState, + }, + GetResult: l.GetResult, + Stop: l.Stop, + } +} + // Reset clears the data held by the logger. func (l *StructLogger) Reset() { l.storage = make(map[common.Address]Storage) @@ -143,7 +157,7 @@ func (l *StructLogger) Reset() { // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (l *StructLogger) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -153,49 +167,49 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s return } - memory := scope.Memory - stack := scope.Stack - contract := scope.Contract + op := vm.OpCode(opcode) + memory := scope.GetMemoryData() + stack := scope.GetStackData() // Copy a snapshot of the current memory state to a new buffer var mem []byte if l.cfg.EnableMemory { - mem = make([]byte, len(memory.Data())) - copy(mem, memory.Data()) + mem = make([]byte, len(memory)) + copy(mem, memory) } // Copy a snapshot of the current stack state to a new buffer var stck []uint256.Int if !l.cfg.DisableStack { - stck = make([]uint256.Int, len(stack.Data())) - for i, item := range stack.Data() { + stck = make([]uint256.Int, len(stack)) + for i, item := range stack { stck[i] = item } } - stackData := stack.Data() - stackLen := len(stackData) + contractAddr := scope.GetAddress() + stackLen := len(stack) // Copy a snapshot of the current storage to a new container var storage Storage if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) { // initialise new changed values storage container for this contract // if not present. - if l.storage[contract.Address()] == nil { - l.storage[contract.Address()] = make(Storage) + if l.storage[contractAddr] == nil { + l.storage[contractAddr] = make(Storage) } // capture SLOAD opcodes and record the read entry in the local storage if op == vm.SLOAD && stackLen >= 1 { var ( - address = common.Hash(stackData[stackLen-1].Bytes32()) - value = l.env.StateDB.GetState(contract.Address(), address) + address = common.Hash(stack[stackLen-1].Bytes32()) + value = l.env.StateDB.GetState(contractAddr, address) ) - l.storage[contract.Address()][address] = value - storage = l.storage[contract.Address()].Copy() + l.storage[contractAddr][address] = value + storage = l.storage[contractAddr].Copy() } else if op == vm.SSTORE && stackLen >= 2 { // capture SSTORE opcodes and record the written entry in the local storage. var ( - value = common.Hash(stackData[stackLen-2].Bytes32()) - address = common.Hash(stackData[stackLen-1].Bytes32()) + value = common.Hash(stack[stackLen-2].Bytes32()) + address = common.Hash(stack[stackLen-1].Bytes32()) ) - l.storage[contract.Address()][address] = value - storage = l.storage[contract.Address()].Copy() + l.storage[contractAddr][address] = value + storage = l.storage[contractAddr].Copy() } } var rdata []byte @@ -204,7 +218,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s copy(rdata, rData) } // create a new snapshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} + log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} l.logs = append(l.logs, log) } @@ -246,7 +260,7 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (l *StructLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { l.env = env } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 1bf88f8899..fecfa0cb73 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -25,13 +25,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) type JSONLogger struct { directory.NoopTracer encoder *json.Encoder cfg *Config - env *vm.EVM + env *live.VMContext } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects @@ -44,31 +45,40 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (l *JSONLogger) GetLogger() *live.LiveLogger { + return &live.LiveLogger{ + CaptureTxStart: l.CaptureTxStart, + CaptureEnd: l.CaptureEnd, + CaptureState: l.CaptureState, + CaptureFault: l.CaptureFault, + } +} + +func (l *JSONLogger) CaptureFault(pc uint64, op live.OpCode, gas uint64, cost uint64, scope live.ScopeContext, depth int, err error) { // TODO: Add rData to this interface as well l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - memory := scope.Memory - stack := scope.Stack +func (l *JSONLogger) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { + memory := scope.GetMemoryData() + stack := scope.GetStackData() log := StructLog{ Pc: pc, - Op: op, + Op: vm.OpCode(op), Gas: gas, GasCost: cost, - MemorySize: memory.Len(), + MemorySize: len(memory), Depth: depth, RefundCounter: l.env.StateDB.GetRefund(), Err: err, } if l.cfg.EnableMemory { - log.Memory = memory.Data() + log.Memory = memory } if !l.cfg.DisableStack { - log.Stack = stack.Data() + log.Stack = stack } if l.cfg.EnableReturnData { log.ReturnData = rData @@ -90,6 +100,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, revert l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (l *JSONLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { l.env = env } diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index c7c45cfaa4..aa2dbd906a 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func init() { @@ -48,7 +49,6 @@ func init() { // } type fourByteTracer struct { directory.NoopTracer - env *vm.EVM ids map[string]int // ids aggregates the 4byte ids found interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -57,11 +57,19 @@ type fourByteTracer struct { // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (directory.Tracer, error) { +func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } - return t, nil + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureStart: t.CaptureStart, + CaptureEnter: t.CaptureEnter, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } // isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go @@ -80,10 +88,9 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { - t.env = env +func (t *fourByteTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block - rules := t.env.ChainConfig().Rules(t.env.Context.BlockNumber, t.env.Context.Random != nil, t.env.Context.Time) + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) } @@ -96,7 +103,7 @@ func (t *fourByteTracer) CaptureStart(from common.Address, to common.Address, cr } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) CaptureEnter(opcode live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if t.interrupt.Load() { return @@ -104,6 +111,7 @@ func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to comm if len(input) < 4 { return } + op := vm.OpCode(opcode) // primarily we want to avoid CREATE/CREATE2/SELFDESTRUCT if op != vm.DELEGATECALL && op != vm.STATICCALL && op != vm.CALL && op != vm.CALLCODE { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 43bd0198da..74a13038d9 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go @@ -120,7 +121,28 @@ type callTracerConfig struct { // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { +func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { + t, err := newCallTracerObject(ctx, cfg) + if err != nil { + return nil, err + } + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureStart: t.CaptureStart, + CaptureEnd: t.CaptureEnd, + CaptureEnter: t.CaptureEnter, + CaptureExit: t.CaptureExit, + CaptureState: t.CaptureState, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil +} + +func newCallTracerObject(ctx *directory.Context, cfg json.RawMessage) (*callTracer, error) { var config callTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -154,11 +176,11 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *callTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *callTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.depth++ if t.config.OnlyTopCall { return @@ -170,7 +192,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. toCopy := to call := callFrame{ - Type: typ, + Type: vm.OpCode(typ), From: from, To: &toCopy, Input: common.CopyBytes(input), @@ -201,7 +223,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, rever t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *callTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { t.gasLimit = tx.Gas() } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 26f114f44f..4cd5308e40 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) //go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go @@ -123,7 +124,7 @@ type flatCallTracerConfig struct { } // newFlatCallTracer returns a new flatCallTracer. -func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { +func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { var config flatCallTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -133,16 +134,26 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (directory.T // Create inner call tracer with default configuration, don't forward // the OnlyTopCall or WithLog to inner for now - tracer, err := directory.DefaultDirectory.New("callTracer", ctx, nil) + t, err := newCallTracerObject(ctx, nil) if err != nil { return nil, err } - t, ok := tracer.(*callTracer) - if !ok { - return nil, errors.New("internal error: embedded tracer has wrong type") - } - return &flatCallTracer{tracer: t, ctx: ctx, config: config}, nil + ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: ft.CaptureTxStart, + CaptureTxEnd: ft.CaptureTxEnd, + CaptureStart: ft.CaptureStart, + CaptureEnd: ft.CaptureEnd, + CaptureEnter: ft.CaptureEnter, + CaptureExit: ft.CaptureExit, + CaptureState: ft.CaptureState, + CaptureFault: ft.CaptureFault, + }, + Stop: ft.Stop, + GetResult: ft.GetResult, + }, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -156,17 +167,17 @@ func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, re } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *flatCallTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *flatCallTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *flatCallTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.tracer.CaptureEnter(typ, from, to, input, gas, value) // Child calls must have a value, even if it's zero. @@ -200,10 +211,10 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, r } } -func (t *flatCallTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *flatCallTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { t.tracer.CaptureTxStart(env, tx, from) // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 70af63e752..501f598385 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -21,10 +21,9 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "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/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func init() { @@ -35,18 +34,18 @@ func init() { // runs multiple tracers in one go. type muxTracer struct { names []string - tracers []directory.Tracer + tracers []*directory.Tracer } // newMuxTracer returns a new mux tracer. -func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { +func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { var config map[string]json.RawMessage if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { return nil, err } } - objects := make([]directory.Tracer, 0, len(config)) + objects := make([]*directory.Tracer, 0, len(config)) names := make([]string, 0, len(config)) for k, v := range config { t, err := directory.DefaultDirectory.New(k, ctx, v) @@ -57,55 +56,90 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer names = append(names, k) } - return &muxTracer{names: names, tracers: objects}, nil + t := &muxTracer{names: names, tracers: objects} + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureStart: t.CaptureStart, + CaptureEnd: t.CaptureEnd, + CaptureEnter: t.CaptureEnter, + CaptureExit: t.CaptureExit, + CaptureState: t.CaptureState, + CaptureFault: t.CaptureFault, + CaptureKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + }, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { - t.CaptureStart(from, to, create, input, gas, value) + if t.CaptureStart != nil { + t.CaptureStart(from, to, create, input, gas, value) + } } } // CaptureEnd is called after the call finishes to finalize the tracing. func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - t.CaptureEnd(output, gasUsed, err, reverted) + if t.CaptureEnd != nil { + t.CaptureEnd(output, gasUsed, err, reverted) + } } } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *muxTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { for _, t := range t.tracers { - t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + if t.CaptureState != nil { + t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + } } } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *muxTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { for _, t := range t.tracers { - t.CaptureFault(pc, op, gas, cost, scope, depth, err) + if t.CaptureFault != nil { + t.CaptureFault(pc, op, gas, cost, scope, depth, err) + } } } // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { for _, t := range t.tracers { - t.CaptureKeccakPreimage(hash, data) + if t.CaptureKeccakPreimage != nil { + t.CaptureKeccakPreimage(hash, data) + } } } // CaptureGasConsumed is called when gas is consumed. -func (t *muxTracer) OnGasChange(old, new uint64, reason vm.GasChangeReason) { +func (t *muxTracer) OnGasChange(old, new uint64, reason live.GasChangeReason) { for _, t := range t.tracers { - t.OnGasChange(old, new, reason) + if t.OnGasChange != nil { + t.OnGasChange(old, new, reason) + } } } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { - t.CaptureEnter(typ, from, to, input, gas, value) + if t.CaptureEnter != nil { + t.CaptureEnter(typ, from, to, input, gas, value) + } } } @@ -113,49 +147,65 @@ func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.A // execute any code. func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - t.CaptureExit(output, gasUsed, err, reverted) + if t.CaptureExit != nil { + t.CaptureExit(output, gasUsed, err, reverted) + } } } -func (t *muxTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *muxTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { - t.CaptureTxStart(env, tx, from) + if t.CaptureTxStart != nil { + t.CaptureTxStart(env, tx, from) + } } } func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt, err error) { for _, t := range t.tracers { - t.CaptureTxEnd(receipt, err) + if t.CaptureTxEnd != nil { + t.CaptureTxEnd(receipt, err) + } } } -func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { for _, t := range t.tracers { - t.OnBalanceChange(a, prev, new, reason) + if t.OnBalanceChange != nil { + t.OnBalanceChange(a, prev, new, reason) + } } } func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) { for _, t := range t.tracers { - t.OnNonceChange(a, prev, new) + if t.OnNonceChange != nil { + t.OnNonceChange(a, prev, new) + } } } func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { for _, t := range t.tracers { - t.OnCodeChange(a, prevCodeHash, prev, codeHash, code) + if t.OnCodeChange != nil { + t.OnCodeChange(a, prevCodeHash, prev, codeHash, code) + } } } func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { for _, t := range t.tracers { - t.OnStorageChange(a, k, prev, new) + if t.OnStorageChange != nil { + t.OnStorageChange(a, k, prev, new) + } } } func (t *muxTracer) OnLog(log *types.Log) { for _, t := range t.tracers { - t.OnLog(log) + if t.OnLog != nil { + t.OnLog(log) + } } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 8608ab69dc..88cd0009fa 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" ) @@ -58,7 +59,7 @@ type accountMarshaling struct { type prestateTracer struct { directory.NoopTracer - env *vm.EVM + env *live.VMContext pre stateMap post stateMap to common.Address @@ -73,24 +74,33 @@ type prestateTracerConfig struct { DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications } -func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { +func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { var config prestateTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { return nil, err } } - return &prestateTracer{ + t := &prestateTracer{ pre: stateMap{}, post: stateMap{}, config: config, created: make(map[common.Address]bool), deleted: make(map[common.Address]bool), + } + return &directory.Tracer{ + LiveLogger: &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureTxEnd: t.CaptureTxEnd, + CaptureState: t.CaptureState, + }, + GetResult: t.GetResult, + Stop: t.Stop, }, nil } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *prestateTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { if err != nil { return } @@ -98,10 +108,10 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, if t.interrupt.Load() { return } - stack := scope.Stack - stackData := stack.Data() + op := vm.OpCode(opcode) + stackData := scope.GetStackData() stackLen := len(stackData) - caller := scope.Contract.Address() + caller := scope.GetAddress() switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) @@ -136,7 +146,7 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *prestateTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { t.env = env if tx.To() == nil { t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) @@ -147,7 +157,7 @@ func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from t.lookupAccount(from) t.lookupAccount(t.to) - t.lookupAccount(env.Context.Coinbase) + t.lookupAccount(env.Coinbase) } func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt, err error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4f792260ed..39d79413bd 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -960,7 +961,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { } // Override account balance. if account.Balance != nil { - statedb.SetBalance(addr, (*big.Int)(*account.Balance), state.BalanceChangeUnspecified) + statedb.SetBalance(addr, (*big.Int)(*account.Balance), live.BalanceChangeUnspecified) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) @@ -1639,7 +1640,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) - config := vm.Config{Tracer: tracer, NoBaseFee: true} + config := vm.Config{Tracer: tracer.GetLogger(), NoBaseFee: true} vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { diff --git a/miner/worker.go b/miner/worker.go index a5ea9571a9..95190d5c5d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -976,7 +976,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { if header.ParentBeaconRoot != nil { context := core.NewEVMBlockContext(header, w.chain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state, nil) + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } return env, nil } From e0b96540b7a3c7ad3d9040fc6665c18366eb84b6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 21 Feb 2024 18:54:15 +0100 Subject: [PATCH 07/33] Add canceler interface --- core/vm/evm.go | 1 + eth/tracers/directory/live/dir.go | 7 +++++++ eth/tracers/js/goja.go | 6 +++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index b291bcfbc6..a3fd2da531 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -565,5 +565,6 @@ func (evm *EVM) GetVMContext() *live.VMContext { GasPrice: evm.TxContext.GasPrice, ChainConfig: evm.ChainConfig(), StateDB: evm.StateDB, + VM: evm, } } diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index 9e89c0f36c..fca3654141 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -29,6 +29,12 @@ type StateDB interface { GetRefund() uint64 } +// Canceler is an interface that wraps the Cancel method. +// It allows loggers to cancel EVM processing. +type Canceler interface { + Cancel() +} + type VMContext struct { Coinbase common.Address BlockNumber *big.Int @@ -38,6 +44,7 @@ type VMContext struct { GasPrice *big.Int ChainConfig *params.ChainConfig StateDB StateDB + VM Canceler } // BlockEvent is emitted upon tracing an incoming block. diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index f6ed3ed229..3e0a4b592f 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -242,7 +242,7 @@ func (t *jsTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, fr gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) if err != nil { t.err = err - t.env.Cancel() + t.env.VM.Cancel() return } t.ctx["gasPrice"] = gasPriceBig @@ -265,7 +265,7 @@ func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) { func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { cancel := func(err error) { t.err = err - t.env.Cancel() + t.env.VM.Cancel() } if create { t.ctx["type"] = t.vm.ToValue("CREATE") @@ -408,7 +408,7 @@ func (t *jsTracer) onError(context string, err error) { t.err = wrapError(context, err) // `env` is set on CaptureStart which comes before any JS execution. // So it should be non-nil. - t.env.Cancel() + t.env.VM.Cancel() } func wrapError(context string, err error) error { From 6013241175129e75c3176af069904995f6533730 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 27 Feb 2024 16:32:21 +0100 Subject: [PATCH 08/33] fix memory copy util func --- eth/tracers/directory/util.go | 30 ++++++++++++++++++++++-------- eth/tracers/directory/util_test.go | 2 +- eth/tracers/native/prestate.go | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/eth/tracers/directory/util.go b/eth/tracers/directory/util.go index 92de735291..25f95642c8 100644 --- a/eth/tracers/directory/util.go +++ b/eth/tracers/directory/util.go @@ -18,8 +18,6 @@ package directory import ( "errors" "fmt" - - "github.com/ethereum/go-ethereum/core/vm" ) const ( @@ -28,20 +26,36 @@ const ( // GetMemoryCopyPadded returns offset + size as a new slice. // It zero-pads the slice if it extends beyond memory bounds. -func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { +func GetMemoryCopyPadded(m []byte, offset, size int64) ([]byte, error) { if offset < 0 || size < 0 { return nil, errors.New("offset or size must not be negative") } - if int(offset+size) < m.Len() { // slice fully inside memory - return m.GetCopy(offset, size), nil + length := int64(len(m)) + if offset+size < length { // slice fully inside memory + return memoryCopy(m, offset, size), nil } - paddingNeeded := int(offset+size) - m.Len() + paddingNeeded := offset + size - length if paddingNeeded > memoryPadLimit { return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) } cpy := make([]byte, size) - if overlap := int64(m.Len()) - offset; overlap > 0 { - copy(cpy, m.GetPtr(offset, overlap)) + if overlap := length - offset; overlap > 0 { + copy(cpy, m[offset:offset+overlap]) } return cpy, nil } + +func memoryCopy(m []byte, offset, size int64) (cpy []byte) { + if size == 0 { + return nil + } + + if len(m) > int(offset) { + cpy = make([]byte, size) + copy(cpy, m[offset:offset+size]) + + return + } + + return +} diff --git a/eth/tracers/directory/util_test.go b/eth/tracers/directory/util_test.go index c72096708d..904c749d06 100644 --- a/eth/tracers/directory/util_test.go +++ b/eth/tracers/directory/util_test.go @@ -40,7 +40,7 @@ func TestMemCopying(t *testing.T) { } { mem := vm.NewMemory() mem.Resize(uint64(tc.memsize)) - cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) + cpy, err := GetMemoryCopyPadded(mem.Data(), tc.offset, tc.size) if want := tc.wantErr; want != "" { if err == nil { t.Fatalf("test %d: want '%v' have no error", i, want) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 88cd0009fa..7ac77ffaa9 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -133,7 +133,7 @@ func (t *prestateTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost u case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] - init, err := directory.GetMemoryCopyPadded(scope.Memory, int64(offset.Uint64()), int64(size.Uint64())) + init, err := directory.GetMemoryCopyPadded(scope.GetMemoryData(), int64(offset.Uint64()), int64(size.Uint64())) if err != nil { log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size) return From f1027b7c0a5afae1c2ba04e3d3862a285ce593a9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 27 Feb 2024 16:51:47 +0100 Subject: [PATCH 09/33] fix goja scope object wrappers --- eth/tracers/directory/util.go | 21 ++++++++++++++++- eth/tracers/js/goja.go | 43 ++++++++++++++++++----------------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/eth/tracers/directory/util.go b/eth/tracers/directory/util.go index 25f95642c8..f5a2cd80d3 100644 --- a/eth/tracers/directory/util.go +++ b/eth/tracers/directory/util.go @@ -18,6 +18,8 @@ package directory import ( "errors" "fmt" + + "github.com/holiman/uint256" ) const ( @@ -40,7 +42,7 @@ func GetMemoryCopyPadded(m []byte, offset, size int64) ([]byte, error) { } cpy := make([]byte, size) if overlap := length - offset; overlap > 0 { - copy(cpy, m[offset:offset+overlap]) + copy(cpy, MemoryPtr(m, offset, overlap)) } return cpy, nil } @@ -59,3 +61,20 @@ func memoryCopy(m []byte, offset, size int64) (cpy []byte) { return } + +func MemoryPtr(m []byte, offset, size int64) []byte { + if size == 0 { + return nil + } + + if len(m) > int(offset) { + return m[offset : offset+size] + } + + return nil +} + +// Back returns the n'th item in stack +func StackBack(st []uint256.Int, n int) *uint256.Int { + return &st[len(st)-n-1] +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 3e0a4b592f..62115f40a2 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -309,9 +310,9 @@ func (t *jsTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, sco log := t.log log.op.op = vm.OpCode(op) - log.memory.memory = scope.Memory - log.stack.stack = scope.Stack - log.contract.contract = scope.Contract + log.memory.memory = scope.GetMemoryData() + log.stack.stack = scope.GetStackData() + log.contract.scope = scope log.pc = pc log.gas = gas log.cost = cost @@ -587,7 +588,7 @@ func (o *opObj) setupObject() *goja.Object { } type memoryObj struct { - memory *vm.Memory + memory []byte vm *goja.Runtime toBig toBigFn toBuf toBufFn @@ -638,14 +639,14 @@ func (mo *memoryObj) GetUint(addr int64) goja.Value { // getUint returns the 32 bytes at the specified address interpreted as a uint. func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { - if mo.memory.Len() < int(addr)+32 || addr < 0 { - return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) + if len(mo.memory) < int(addr)+32 || addr < 0 { + return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", len(mo.memory), addr, 32) } - return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil + return new(big.Int).SetBytes(directory.MemoryPtr(mo.memory, addr, 32)), nil } func (mo *memoryObj) Length() int { - return mo.memory.Len() + return len(mo.memory) } func (m *memoryObj) setupObject() *goja.Object { @@ -657,7 +658,7 @@ func (m *memoryObj) setupObject() *goja.Object { } type stackObj struct { - stack *vm.Stack + stack []uint256.Int vm *goja.Runtime toBig toBigFn } @@ -678,14 +679,14 @@ func (s *stackObj) Peek(idx int) goja.Value { // peek returns the nth-from-the-top element of the stack. func (s *stackObj) peek(idx int) (*big.Int, error) { - if len(s.stack.Data()) <= idx || idx < 0 { - return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) + if len(s.stack) <= idx || idx < 0 { + return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack), idx) } - return s.stack.Back(idx).ToBig(), nil + return directory.StackBack(s.stack, idx).ToBig(), nil } func (s *stackObj) Length() int { - return len(s.stack.Data()) + return len(s.stack) } func (s *stackObj) setupObject() *goja.Object { @@ -788,14 +789,14 @@ func (do *dbObj) setupObject() *goja.Object { } type contractObj struct { - contract *vm.Contract - vm *goja.Runtime - toBig toBigFn - toBuf toBufFn + scope live.ScopeContext + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn } func (co *contractObj) GetCaller() goja.Value { - caller := co.contract.Caller().Bytes() + caller := co.scope.GetCaller().Bytes() res, err := co.toBuf(co.vm, caller) if err != nil { co.vm.Interrupt(err) @@ -805,7 +806,7 @@ func (co *contractObj) GetCaller() goja.Value { } func (co *contractObj) GetAddress() goja.Value { - addr := co.contract.Address().Bytes() + addr := co.scope.GetAddress().Bytes() res, err := co.toBuf(co.vm, addr) if err != nil { co.vm.Interrupt(err) @@ -815,7 +816,7 @@ func (co *contractObj) GetAddress() goja.Value { } func (co *contractObj) GetValue() goja.Value { - value := co.contract.Value() + value := co.scope.GetCallValue() res, err := co.toBig(co.vm, value.String()) if err != nil { co.vm.Interrupt(err) @@ -825,7 +826,7 @@ func (co *contractObj) GetValue() goja.Value { } func (co *contractObj) GetInput() goja.Value { - input := common.CopyBytes(co.contract.Input) + input := common.CopyBytes(co.scope.GetCallInput()) res, err := co.toBuf(co.vm, input) if err != nil { co.vm.Interrupt(err) From 29ebfb30c371518acb4a0efe61a55dfb19be88ad Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 27 Feb 2024 20:31:01 +0100 Subject: [PATCH 10/33] fixes, rm t8ntool tracewriter # Conflicts: # cmd/evm/internal/t8ntool/execution.go # cmd/evm/internal/t8ntool/transition.go # core/vm/instructions.go # eth/tracers/internal/tracetest/calltrace_test.go # eth/tracers/internal/tracetest/flat_calltrace_test.go # eth/tracers/internal/tracetest/prestate_test.go # eth/tracers/js/tracer_test.go # eth/tracers/logger/logger_test.go # eth/tracers/tracers_test.go # tests/block_test_util.go # tests/state_test_util.go --- cmd/evm/blockrunner.go | 6 +- cmd/evm/internal/t8ntool/execution.go | 41 +++++++-- cmd/evm/internal/t8ntool/tracewriter.go | 92 ------------------- cmd/evm/internal/t8ntool/transition.go | 32 +++---- core/vm/instructions.go | 30 +++--- core/vm/interpreter.go | 6 ++ .../internal/tracetest/calltrace_test.go | 28 +++--- .../internal/tracetest/flat_calltrace_test.go | 13 +-- .../internal/tracetest/prestate_test.go | 16 ++-- eth/tracers/js/tracer_test.go | 17 ++-- eth/tracers/logger/logger_test.go | 4 +- eth/tracers/tracers_test.go | 4 +- tests/block_test_util.go | 3 +- tests/state_test_util.go | 5 +- 14 files changed, 115 insertions(+), 182 deletions(-) delete mode 100644 cmd/evm/internal/t8ntool/tracewriter.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index ff65574586..9c2f4578c8 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -25,7 +25,7 @@ import ( "sort" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" @@ -50,7 +50,7 @@ func blockTestCmd(ctx *cli.Context) error { return errors.New("path-to-test argument required") } - var tracer vm.EVMLogger + var tracer *live.LiveLogger // Configure the EVM logger if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(&logger.Config{ @@ -58,7 +58,7 @@ func blockTestCmd(ctx *cli.Context) error { DisableStack: ctx.Bool(DisableStackFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), - }, os.Stderr) + }, os.Stderr).GetLogger() } // Load the test content from the input file src, err := os.ReadFile(ctx.Args().First()) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5b9a2e417c..ea8069ba66 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -17,7 +17,9 @@ package t8ntool import ( + "encoding/json" "fmt" + "io" "math/big" "github.com/ethereum/go-ethereum/common" @@ -31,6 +33,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -117,7 +121,7 @@ type rejectedTx struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, []byte, error) { + getTracerFn func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -187,7 +191,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb, nil) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } var blobGasUsed uint64 @@ -220,11 +224,11 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } blobGasUsed += txBlobGas } - tracer, err := getTracerFn(txIndex, tx.Hash()) + tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash()) if err != nil { return nil, nil, nil, err } - vmConfig.Tracer = tracer + vmConfig.Tracer = tracer.LiveLogger statedb.SetTxContext(tx.Hash(), txIndex) var ( @@ -235,7 +239,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) if tracer != nil { - tracer.CaptureTxStart(evm, tx, msg.From) + tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) @@ -246,6 +250,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, gaspool.SetGas(prevGas) if tracer != nil { tracer.CaptureTxEnd(nil, err) + if err := writeTraceResult(tracer, traceOutput); err != nil { + log.Warn("Error writing tracer output", "err", err) + } } continue } @@ -289,7 +296,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) if tracer != nil { - tracer.CaptureTxEnd(receipt, nil) + tracer.LiveLogger.CaptureTxEnd(receipt, nil) + writeTraceResult(tracer, traceOutput) } } @@ -316,15 +324,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) - statedb.AddBalance(ommer.Address, reward, state.BalanceIncreaseRewardMineUncle) + statedb.AddBalance(ommer.Address, reward, live.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceIncreaseRewardMineBlock) + statedb.AddBalance(pre.Env.Coinbase, minerReward, live.BalanceIncreaseRewardMineBlock) } // Apply withdrawals for _, w := range pre.Env.Withdrawals { // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) - statedb.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) + statedb.AddBalance(w.Address, amount, live.BalanceIncreaseWithdrawal) } // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) @@ -367,7 +375,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, a.Balance, state.BalanceIncreaseGenesisBalance) + statedb.SetBalance(addr, a.Balance, live.BalanceIncreaseGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) } @@ -404,3 +412,16 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime } return ethash.CalcDifficulty(config, currentTime, parent) } + +func writeTraceResult(tracer *directory.Tracer, f io.WriteCloser) error { + defer f.Close() + result, err := tracer.GetResult() + if err != nil { + return err + } + err = json.NewEncoder(f).Encode(result) + if err != nil { + return err + } + return nil +} diff --git a/cmd/evm/internal/t8ntool/tracewriter.go b/cmd/evm/internal/t8ntool/tracewriter.go deleted file mode 100644 index 8a850f1d98..0000000000 --- a/cmd/evm/internal/t8ntool/tracewriter.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package t8ntool - -import ( - "encoding/json" - "io" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/log" -) - -// traceWriter is an vm.EVMLogger which also holds an inner logger/tracer. -// When the TxEnd event happens, the inner tracer result is written to the file, and -// the file is closed. -type traceWriter struct { - inner vm.EVMLogger - f io.WriteCloser -} - -// Compile-time interface check -var _ = vm.EVMLogger((*traceWriter)(nil)) - -func (t *traceWriter) CaptureTxEnd(receipt *types.Receipt, err error) { - t.inner.CaptureTxEnd(receipt, err) - defer t.f.Close() - - if tracer, ok := t.inner.(directory.Tracer); ok { - result, err := tracer.GetResult() - if err != nil { - log.Warn("Error in tracer", "err", err) - return - } - err = json.NewEncoder(t.f).Encode(result) - if err != nil { - log.Warn("Error writing tracer output", "err", err) - return - } - } -} - -func (t *traceWriter) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { - t.inner.CaptureTxStart(env, tx, from) -} -func (t *traceWriter) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.inner.CaptureStart(from, to, create, input, gas, value) -} - -func (t *traceWriter) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - t.inner.CaptureEnd(output, gasUsed, err, reverted) -} - -func (t *traceWriter) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - t.inner.CaptureEnter(typ, from, to, input, gas, value) -} - -func (t *traceWriter) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { - t.inner.CaptureExit(output, gasUsed, err, reverted) -} - -func (t *traceWriter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - t.inner.CaptureState(pc, op, gas, cost, scope, rData, depth, err) -} -func (t *traceWriter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - t.inner.CaptureFault(pc, op, gas, cost, scope, depth, err) -} - -func (t *traceWriter) CaptureKeccakPreimage(hash common.Hash, data []byte) { - t.inner.CaptureKeccakPreimage(hash, data) -} - -func (t *traceWriter) OnGasChange(old, new uint64, reason vm.GasChangeReason) { - t.inner.OnGasChange(old, new, reason) -} diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index e41ff313e0..135b89fc1b 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "math/big" "os" "path" @@ -86,12 +87,7 @@ func Transition(ctx *cli.Context) error { glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) log.Root().SetHandler(glogger) - var ( - err error - tracer vm.EVMLogger - ) - var getTracer func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) - + var getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { return nil, nil, nil } baseDir, err := createBasedir(ctx) if err != nil { return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) @@ -123,32 +119,36 @@ func Transition(ctx *cli.Context) error { prevFile.Close() } }() - getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { - if prevFile != nil { - prevFile.Close() - } + getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) if err != nil { - return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) + return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } prevFile = traceFile - return logger.NewJSONLogger(logConfig, traceFile), nil + logger := logger.NewJSONLogger(logConfig, traceFile).GetLogger() + tracer := &directory.Tracer{ + LiveLogger: logger, + // JSONLogger streams out result to file. + GetResult: func() (json.RawMessage, error) { return nil, nil }, + Stop: func(err error) {}, + } + return tracer, traceFile, nil } } else if ctx.IsSet(TraceTracerFlag.Name) { var config json.RawMessage if ctx.IsSet(TraceTracerConfigFlag.Name) { config = []byte(ctx.String(TraceTracerConfigFlag.Name)) } - getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { + getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) if err != nil { - return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) + return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } tracer, err := directory.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) if err != nil { - return nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) + return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) } - return &traceWriter{tracer, traceFile}, nil + return tracer, traceFile, nil } } // We need to load three things: alloc, env and transactions. May be either in diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 31296aa1a5..3a681775bb 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -248,7 +248,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if evm.Config.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - if interpreter.evm.Config.Tracer != nil { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.CaptureKeccakPreimage != nil { interpreter.evm.Config.Tracer.CaptureKeccakPreimage(common.BytesToHash(interpreter.hasherBuf[:]), data) } size.SetBytes(interpreter.hasherBuf[:]) @@ -615,7 +615,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } scope.Stack.push(&stackvalue) - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -660,7 +660,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] } scope.Stack.push(&stackvalue) - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -710,7 +710,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -750,7 +750,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -783,7 +783,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -816,7 +816,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) } @@ -858,8 +858,12 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - tracer.CaptureExit([]byte{}, 0, nil, false) + if tracer.CaptureEnter != nil { + tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + } + if tracer.CaptureExit != nil { + tracer.CaptureExit([]byte{}, 0, nil, false) + } } return nil, errStopToken } @@ -874,8 +878,12 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - tracer.CaptureExit([]byte{}, 0, nil, false) + if tracer.CaptureEnter != nil { + tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + } + if tracer.CaptureExit != nil { + tracer.CaptureExit([]byte{}, 0, nil, false) + } } return nil, errStopToken } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 5f86299637..6da530cd06 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -42,10 +42,16 @@ type ScopeContext struct { } func (ctx *ScopeContext) GetMemoryData() []byte { + if ctx.Memory == nil { + return nil + } return ctx.Memory.Data() } func (ctx *ScopeContext) GetStackData() []uint256.Int { + if ctx.Stack == nil { + return nil + } return ctx.Stack.Data() } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index e518874549..fcc56180d1 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -124,12 +124,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } // Configure a blockchain with the given prestate var ( - signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - origin, _ = signer.Sender(tx) - txContext = vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } + signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) context = vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -148,13 +143,14 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer) - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) + + statedb.SetLogger(tracer.LiveLogger) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) + tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) @@ -255,7 +251,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err != nil { b.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) snap := statedb.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -287,7 +283,7 @@ func TestInternals(t *testing.T) { BaseFee: new(big.Int), } ) - mkTracer := func(name string, cfg json.RawMessage) directory.Tracer { + mkTracer := func(name string, cfg json.RawMessage) *directory.Tracer { tr, err := directory.DefaultDirectory.New(name, nil, cfg) if err != nil { t.Fatalf("failed to create call tracer: %v", err) @@ -298,7 +294,7 @@ func TestInternals(t *testing.T) { for _, tc := range []struct { name string code []byte - tracer directory.Tracer + tracer *directory.Tracer want string }{ { @@ -383,7 +379,7 @@ func TestInternals(t *testing.T) { }, }, false, rawdb.HashScheme) defer triedb.Close() - statedb.SetLogger(tc.tracer) + statedb.SetLogger(tc.tracer.LiveLogger) tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ To: &to, Value: big.NewInt(0), @@ -397,12 +393,12 @@ func TestInternals(t *testing.T) { Origin: origin, GasPrice: tx.GasPrice(), } - evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer}) + evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer.LiveLogger}) msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) } - tc.tracer.CaptureTxStart(evm, tx, msg.From) + tc.tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 4b56dfd6b9..7ae99d2b9d 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -84,11 +84,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - origin, _ := signer.Sender(tx) - txContext := vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } context := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -106,14 +101,14 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer) - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) + statedb.SetLogger(tracer.LiveLogger) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) + tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return fmt.Errorf("failed to execute transaction: %v", err) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 9a9189e399..08e1eccc3c 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -92,12 +92,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } // Configure a blockchain with the given prestate var ( - signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - origin, _ = signer.Sender(tx) - txContext = vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } + signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) context = vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -116,13 +111,14 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer) - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) + + statedb.SetLogger(tracer.LiveLogger) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) + tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 11c44fbcc4..c5a3a7e2f8 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -61,9 +62,9 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer directory.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { +func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer}) + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.LiveLogger}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) @@ -74,7 +75,7 @@ func runTrace(tracer directory.Tracer, vmctx *vmContext, chaincfg *params.ChainC contract.Code = contractCode } - tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) tracer.CaptureStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, err, true) @@ -184,8 +185,8 @@ func TestHaltBetweenSteps(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) - tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.LiveLogger}) + tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") @@ -206,8 +207,8 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) - tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.LiveLogger}) + tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil, false) ret, err := tracer.GetResult() @@ -278,7 +279,7 @@ func TestEnterExit(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.CaptureEnter(live.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) tracer.CaptureExit([]byte{}, 400, nil, false) have, err := tracer.GetResult() diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index a244e3f9ca..cd70f1a970 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -55,12 +55,12 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.GetTracer().LiveLogger}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash - logger.CaptureTxStart(env, nil, common.Address{}) + logger.CaptureTxStart(env.GetVMContext(), nil, common.Address{}) logger.CaptureStart(common.Address{}, contract.Address(), false, nil, 0, nil) _, err := env.Interpreter().Run(contract, []byte{}, false) if err != nil { diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index ddfdb81ec6..e3ce396374 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -89,8 +89,8 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.GetTracer().LiveLogger}) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index ad1d34fb2b..5a021b245a 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -36,6 +36,7 @@ import ( "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -108,7 +109,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) error { +func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *live.LiveLogger) error { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index d959165e54..25b50a79e3 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -298,7 +299,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - the coinbase self-destructed, or // - there are only 'bad' transactions, which aren't executed. In those cases, // the coinbase gets no txfee, so isn't created, and thus needs to be touched - statedb.AddBalance(block.Coinbase(), new(big.Int), state.BalanceChangeUnspecified) + statedb.AddBalance(block.Coinbase(), new(big.Int), live.BalanceChangeUnspecified) // Commit state mutations into database. root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number())) @@ -322,7 +323,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, a.Balance, state.BalanceChangeUnspecified) + statedb.SetBalance(addr, a.Balance, live.BalanceChangeUnspecified) for k, v := range a.Storage { statedb.SetState(addr, k, v) } From e1c669b3aa22aa5271ce9af0b1b97ea8d3b117c3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Feb 2024 19:20:17 +0100 Subject: [PATCH 11/33] moaar fixes # Conflicts: # core/state/state_test.go # core/state/statedb_fuzz_test.go # core/state/statedb_test.go # core/state/sync_test.go # core/state/trie_prefetcher_test.go # core/txpool/blobpool/blobpool_test.go # core/txpool/legacypool/legacypool2_test.go # core/txpool/legacypool/legacypool_test.go # eth/api_debug_test.go --- cmd/evm/internal/t8ntool/execution.go | 4 +- cmd/evm/runner.go | 7 +-- cmd/evm/staterunner.go | 4 +- core/blockchain_test.go | 6 +-- core/state/state_test.go | 15 +++--- core/state/statedb_fuzz_test.go | 3 +- core/state/statedb_test.go | 55 +++++++++++----------- core/state/sync_test.go | 3 +- core/state/trie_prefetcher_test.go | 7 +-- core/txpool/blobpool/blobpool_test.go | 35 +++++++------- core/txpool/legacypool/legacypool2_test.go | 23 ++++++++- core/txpool/legacypool/legacypool_test.go | 13 ++--- core/vm/runtime/runtime.go | 6 +-- core/vm/runtime/runtime_test.go | 10 ++-- eth/api_debug_test.go | 3 +- eth/tracers/logger/logger.go | 22 ++++++--- tests/state_test.go | 2 +- 17 files changed, 130 insertions(+), 88 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index ea8069ba66..bfcd9fde7d 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -228,7 +228,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if err != nil { return nil, nil, nil, err } - vmConfig.Tracer = tracer.LiveLogger + if vmConfig.Tracer != nil { + vmConfig.Tracer = tracer.LiveLogger + } statedb.SetTxContext(tx.Hash(), txIndex) var ( diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 45fc985351..e247f11f18 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/params" @@ -116,7 +117,7 @@ func runCmd(ctx *cli.Context) error { } var ( - tracer vm.EVMLogger + tracer *live.LiveLogger debugLogger *logger.StructLogger statedb *state.StateDB chainConfig *params.ChainConfig @@ -127,10 +128,10 @@ func runCmd(ctx *cli.Context) error { blobBaseFee = new(big.Int) // TODO (MariusVanDerWijden) implement blob fee in state tests ) if ctx.Bool(MachineFlag.Name) { - tracer = logger.NewJSONLogger(logconfig, os.Stdout) + tracer = logger.NewJSONLogger(logconfig, os.Stdout).GetLogger() } else if ctx.Bool(DebugFlag.Name) { debugLogger = logger.NewStructLogger(logconfig) - tracer = debugLogger + tracer = debugLogger.GetTracer().LiveLogger } else { debugLogger = logger.NewStructLogger(logconfig) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 618ddf2ede..7d969ebad2 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -61,10 +61,10 @@ func stateTestCmd(ctx *cli.Context) error { var cfg vm.Config switch { case ctx.Bool(MachineFlag.Name): - cfg.Tracer = logger.NewJSONLogger(config, os.Stderr) + cfg.Tracer = logger.NewJSONLogger(config, os.Stderr).GetLogger() case ctx.Bool(DebugFlag.Name): - cfg.Tracer = logger.NewStructLogger(config) + cfg.Tracer = logger.NewStructLogger(config).GetTracer().LiveLogger } // Load the test content from the input file if len(ctx.Args().First()) != 0 { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index bc6f8112f0..aa41ddab8c 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3248,7 +3248,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout), + Tracer: logger.NewJSONLogger(nil, os.Stdout).GetLogger(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -3330,7 +3330,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout), + Tracer: logger.NewJSONLogger(nil, os.Stdout).GetLogger(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -4682,7 +4682,7 @@ func TestEIP3651(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Logger()}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 26a2838977..fe65b28bb4 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" ) @@ -49,11 +50,11 @@ func TestDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22), BalanceChangeUnspecified) + obj1.AddBalance(big.NewInt(22), live.BalanceChangeUnspecified) obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(big.NewInt(44), BalanceChangeUnspecified) + obj3.SetBalance(big.NewInt(44), live.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -103,13 +104,13 @@ func TestIterativeDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22), BalanceChangeUnspecified) + obj1.AddBalance(big.NewInt(22), live.BalanceChangeUnspecified) obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(big.NewInt(44), BalanceChangeUnspecified) + obj3.SetBalance(big.NewInt(44), live.BalanceChangeUnspecified) obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) - obj4.AddBalance(big.NewInt(1337), BalanceChangeUnspecified) + obj4.AddBalance(big.NewInt(1337), live.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -205,7 +206,7 @@ func TestSnapshot2(t *testing.T) { // db, trie are already non-empty values so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(big.NewInt(42), BalanceChangeUnspecified) + so0.SetBalance(big.NewInt(42), live.BalanceChangeUnspecified) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.selfDestructed = false @@ -217,7 +218,7 @@ func TestSnapshot2(t *testing.T) { // and one with deleted == true so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(big.NewInt(52), BalanceChangeUnspecified) + so1.SetBalance(big.NewInt(52), live.BalanceChangeUnspecified) so1.SetNonce(53) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.selfDestructed = true diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 592d34b466..5a6009103f 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/triedb/pathdb" @@ -60,7 +61,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, big.NewInt(a.args[0]), BalanceChangeUnspecified) + s.SetBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index f6074917e3..0824c2b07e 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/triedb/hashdb" @@ -56,7 +57,7 @@ func TestUpdateLeaks(t *testing.T) { // Update it with some accounts for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) - state.AddBalance(addr, big.NewInt(int64(11*i)), BalanceChangeUnspecified) + state.AddBalance(addr, big.NewInt(int64(11*i)), live.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i)) if i%2 == 0 { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) @@ -91,7 +92,7 @@ func TestIntermediateLeaks(t *testing.T) { finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { - state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), live.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i+tweak)) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) @@ -167,7 +168,7 @@ func TestCopy(t *testing.T) { for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) - obj.AddBalance(big.NewInt(int64(i)), BalanceChangeUnspecified) + obj.AddBalance(big.NewInt(int64(i)), live.BalanceChangeUnspecified) orig.updateStateObject(obj) } orig.Finalise(false) @@ -184,9 +185,9 @@ func TestCopy(t *testing.T) { copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) - origObj.AddBalance(big.NewInt(2*int64(i)), BalanceChangeUnspecified) - copyObj.AddBalance(big.NewInt(3*int64(i)), BalanceChangeUnspecified) - ccopyObj.AddBalance(big.NewInt(4*int64(i)), BalanceChangeUnspecified) + origObj.AddBalance(big.NewInt(2*int64(i)), live.BalanceChangeUnspecified) + copyObj.AddBalance(big.NewInt(3*int64(i)), live.BalanceChangeUnspecified) + ccopyObj.AddBalance(big.NewInt(4*int64(i)), live.BalanceChangeUnspecified) orig.updateStateObject(origObj) copy.updateStateObject(copyObj) @@ -266,14 +267,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, big.NewInt(a.args[0]), BalanceChangeUnspecified) + s.SetBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) }, args: make([]int64, 1), }, { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, big.NewInt(a.args[0]), BalanceChangeUnspecified) + s.AddBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) }, args: make([]int64, 1), }, @@ -538,7 +539,7 @@ func TestTouchDelete(t *testing.T) { s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() - s.state.AddBalance(common.Address{}, new(big.Int), BalanceChangeUnspecified) + s.state.AddBalance(common.Address{}, new(big.Int), live.BalanceChangeUnspecified) if len(s.state.journal.dirties) != 1 { t.Fatal("expected one dirty state object") @@ -554,7 +555,7 @@ func TestTouchDelete(t *testing.T) { func TestCopyOfCopy(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.HexToAddress("aaaa") - state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { t.Fatalf("1st copy fail, expected 42, got %v", got) @@ -577,9 +578,9 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -650,9 +651,9 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -719,9 +720,9 @@ func TestCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -768,7 +769,7 @@ func TestDeleteCreateRevert(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.BytesToAddress([]byte("so")) - state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) @@ -778,7 +779,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.Finalise(true) id := state.Snapshot() - state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state @@ -820,10 +821,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) { state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) { - state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) state.SetCode(addr, []byte{1, 2, 3}) a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, big.NewInt(100), BalanceChangeUnspecified) + state.SetBalance(a2, big.NewInt(100), live.BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}) root, _ = state.Commit(0, false) t.Logf("root: %x", root) @@ -848,7 +849,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { t.Errorf("expected %d, got %d", exp, got) } // Modify the state - state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) root, err := state.Commit(0, false) if err == nil { t.Fatalf("expected error, got root :%x", root) @@ -1116,13 +1117,13 @@ func TestResetObject(t *testing.T) { slotB = common.HexToHash("0x2") ) // Initialize account with balance and storage in first transaction. - state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) state.IntermediateRoot(true) // Reset account and mutate balance and storages state.CreateAccount(addr) - state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) root, _ := state.Commit(0, true) @@ -1148,7 +1149,7 @@ func TestDeleteStorage(t *testing.T) { addr = common.HexToAddress("0x1") ) // Initialize account and populate storage - state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) state.CreateAccount(addr) for i := 0; i < 1000; i++ { slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 9ccb1475ea..86c790a16a 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -60,7 +61,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) acc := &testAccount{address: common.BytesToAddress([]byte{i})} - obj.AddBalance(big.NewInt(int64(11*i)), BalanceChangeUnspecified) + obj.AddBalance(big.NewInt(int64(11*i)), live.BalanceChangeUnspecified) acc.balance = big.NewInt(int64(11 * i)) obj.SetNonce(uint64(42 * i)) diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index a376c790c3..2a1956392d 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func filledStateDB() *StateDB { @@ -34,9 +35,9 @@ func filledStateDB() *StateDB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie for i := 0; i < 100; i++ { sk := common.BigToHash(big.NewInt(int64(i))) state.SetState(addr, sk, sk) // Change the storage trie diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index da830c4a77..a5848fdf0b 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -512,17 +513,17 @@ func TestOpenDrops(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), live.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -637,7 +638,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -737,9 +738,9 @@ func TestOpenHeap(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -817,9 +818,9 @@ func TestOpenCap(t *testing.T) { for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1210,7 +1211,7 @@ func TestAdd(t *testing.T) { addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) // Seed the state database with this acocunt - statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), state.BalanceChangeUnspecified) + statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), live.BalanceChangeUnspecified) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index bf4f52b035..621987b384 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/event" ) @@ -49,7 +50,11 @@ func fillPool(t testing.TB, pool *LegacyPool) { nonExecutableTxs := types.Transactions{} for i := 0; i < 384; i++ { key, _ := crypto.GenerateKey() +<<<<<<< HEAD pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), state.BalanceChangeUnspecified) +======= + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000), live.BalanceChangeUnspecified) +>>>>>>> 8cc747f439 (moaar fixes) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -91,7 +96,11 @@ func TestTransactionFutureAttack(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() +<<<<<<< HEAD pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) +======= + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) +>>>>>>> 8cc747f439 (moaar fixes) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) @@ -128,7 +137,11 @@ func TestTransactionFuture1559(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() +<<<<<<< HEAD pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) +======= + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) +>>>>>>> 8cc747f439 (moaar fixes) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key)) @@ -182,7 +195,11 @@ func TestTransactionZAttack(t *testing.T) { for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() +<<<<<<< HEAD pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) +======= + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) +>>>>>>> 8cc747f439 (moaar fixes) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.addRemotesSync(futureTxs) } @@ -190,7 +207,11 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() +<<<<<<< HEAD pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) +======= + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) +>>>>>>> 8cc747f439 (moaar fixes) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -227,7 +248,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), core/state/state_test.go.BalanceChangeUnspecified) futureTxs := types.Transactions{} for n := 0; n < b.N; n++ { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index a175df0324..719b71bb34 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -255,7 +256,7 @@ func (c *testChain) State() (*state.StateDB, error) { c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) - c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), state.BalanceChangeUnspecified) + c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), core/state/state_test.go.BalanceChangeUnspecified) *c.trigger = false } return stdb, nil @@ -275,7 +276,7 @@ func TestStateChangeDuringReset(t *testing.T) { ) // setup pool with 2 transaction in it - statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), state.BalanceChangeUnspecified) + statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), core/state/state_test.go.BalanceChangeUnspecified) blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) @@ -309,7 +310,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, amount, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(addr, amount, core/state/state_test.go.BalanceChangeUnspecified) pool.mu.Unlock() } @@ -470,7 +471,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, big.NewInt(100000000000000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(100000000000000), core/state/state_test.go.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -499,7 +500,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, big.NewInt(100000000000000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(100000000000000), core/state/state_test.go.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2618,7 +2619,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) { for i := 0; i < b.N; i++ { key, _ := crypto.GenerateKey() account := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState.AddBalance(account, big.NewInt(1000000), state.BalanceChangeUnspecified) + pool.currentState.AddBalance(account, big.NewInt(1000000), live.BalanceChangeUnspecified) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 65fbd289df..aba137c50c 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -123,7 +123,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv, types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -159,7 +159,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv, types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -190,7 +190,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv, types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 6e244759b8..2997ca5351 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -335,7 +335,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode b.Fatal(err) } cfg.EVMConfig = vm.Config{ - Tracer: tracer, + Tracer: tracer.LiveLogger, } } var ( @@ -510,7 +510,7 @@ func TestEip2929Cases(t *testing.T) { code, ops) Execute(code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: logger.NewMarkdownLogger(nil, os.Stdout), + Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Logger(), ExtraEips: []int{2929}, }, }) @@ -663,7 +663,7 @@ func TestColdAccountAccessCost(t *testing.T) { tracer := logger.NewStructLogger(nil) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.GetTracer().LiveLogger, }, }) have := tracer.StructLogs()[tc.step].GasCost @@ -834,7 +834,7 @@ func TestRuntimeJSTracer(t *testing.T) { GasLimit: 1000000, State: statedb, EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.LiveLogger, }}) if err != nil { t.Fatal("didn't expect error", err) @@ -868,7 +868,7 @@ func TestJSTracerCreateTx(t *testing.T) { _, _, _, err = Create(code, &Config{ State: statedb, EVMConfig: vm.Config{ - Tracer: tracer, + Tracer: tracer.LiveLogger, }}) if err != nil { t.Fatal(err) diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index b93afbab06..f14b96b436 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/trie" "golang.org/x/exp/slices" ) @@ -72,7 +73,7 @@ func TestAccountRange(t *testing.T) { hash := common.HexToHash(fmt.Sprintf("%x", i)) addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes()) addrs[i] = addr - sdb.SetBalance(addrs[i], big.NewInt(1), state.BalanceChangeUnspecified) + sdb.SetBalance(addrs[i], big.NewInt(1), live.BalanceChangeUnspecified) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 3e8a68e6e5..d1db00f992 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -335,7 +335,7 @@ type mdLogger struct { directory.NoopTracer out io.Writer cfg *Config - env *vm.EVM + env *live.VMContext } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -348,7 +348,17 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *mdLogger) Logger() *live.LiveLogger { + return &live.LiveLogger{ + CaptureTxStart: t.CaptureTxStart, + CaptureStart: t.CaptureStart, + CaptureState: t.CaptureState, + CaptureFault: t.CaptureFault, + CaptureEnd: t.CaptureEnd, + } +} + +func (t *mdLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { t.env = env } @@ -370,14 +380,14 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b } // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - stack := scope.Stack +func (t *mdLogger) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { + stack := scope.GetStackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) if !t.cfg.DisableStack { // format stack var a []string - for _, elem := range stack.Data() { + for _, elem := range stack { a = append(a, elem.Hex()) } b := fmt.Sprintf("[%v]", strings.Join(a, ",")) @@ -390,7 +400,7 @@ func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } } -func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *mdLogger) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/tests/state_test.go b/tests/state_test.go index 094dafcafd..05e7543bff 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -152,7 +152,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - config.Tracer = logger.NewJSONLogger(&logger.Config{}, w) + config.Tracer = logger.NewJSONLogger(&logger.Config{}, w).GetLogger() err2 := test(config) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) From b202e8ab746d51f1248ebf7ed6df08cf7083a10f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Feb 2024 19:27:39 +0100 Subject: [PATCH 12/33] renaming GetLogger # Conflicts: # cmd/evm/internal/t8ntool/transition.go # eth/tracers/logger/logger_test.go # eth/tracers/tracers_test.go --- cmd/evm/blockrunner.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 3 +-- cmd/evm/runner.go | 4 ++-- cmd/evm/staterunner.go | 4 ++-- core/blockchain_test.go | 4 ++-- eth/tracers/api.go | 4 ++-- eth/tracers/logger/logger.go | 22 +++++++++++++--------- eth/tracers/logger/logger_json.go | 2 +- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- tests/state_test.go | 2 +- 11 files changed, 27 insertions(+), 24 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 9c2f4578c8..8e34deb7f2 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -58,7 +58,7 @@ func blockTestCmd(ctx *cli.Context) error { DisableStack: ctx.Bool(DisableStackFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), - }, os.Stderr).GetLogger() + }, os.Stderr).Logger() } // Load the test content from the input file src, err := os.ReadFile(ctx.Args().First()) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 135b89fc1b..20b5eee1b1 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -124,8 +124,7 @@ func Transition(ctx *cli.Context) error { if err != nil { return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - prevFile = traceFile - logger := logger.NewJSONLogger(logConfig, traceFile).GetLogger() + logger := logger.NewJSONLogger(logConfig, traceFile).Logger() tracer := &directory.Tracer{ LiveLogger: logger, // JSONLogger streams out result to file. diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index e247f11f18..53532aa763 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -128,10 +128,10 @@ func runCmd(ctx *cli.Context) error { blobBaseFee = new(big.Int) // TODO (MariusVanDerWijden) implement blob fee in state tests ) if ctx.Bool(MachineFlag.Name) { - tracer = logger.NewJSONLogger(logconfig, os.Stdout).GetLogger() + tracer = logger.NewJSONLogger(logconfig, os.Stdout).Logger() } else if ctx.Bool(DebugFlag.Name) { debugLogger = logger.NewStructLogger(logconfig) - tracer = debugLogger.GetTracer().LiveLogger + tracer = debugLogger.Logger() } else { debugLogger = logger.NewStructLogger(logconfig) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 7d969ebad2..5e26ff2ee6 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -61,10 +61,10 @@ func stateTestCmd(ctx *cli.Context) error { var cfg vm.Config switch { case ctx.Bool(MachineFlag.Name): - cfg.Tracer = logger.NewJSONLogger(config, os.Stderr).GetLogger() + cfg.Tracer = logger.NewJSONLogger(config, os.Stderr).Logger() case ctx.Bool(DebugFlag.Name): - cfg.Tracer = logger.NewStructLogger(config).GetTracer().LiveLogger + cfg.Tracer = logger.NewStructLogger(config).Logger() } // Load the test content from the input file if len(ctx.Args().First()) != 0 { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index aa41ddab8c..c3f77d70da 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3248,7 +3248,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout).GetLogger(), + Tracer: logger.NewJSONLogger(nil, os.Stdout).Logger(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -3330,7 +3330,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout).GetLogger(), + Tracer: logger.NewJSONLogger(nil, os.Stdout).Logger(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 422b672086..0fb13696c3 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -777,7 +777,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Swap out the noop logger to the standard tracer writer = bufio.NewWriter(dump) vmConf = vm.Config{ - Tracer: logger.NewJSONLogger(&logConfig, writer).GetLogger(), + Tracer: logger.NewJSONLogger(&logConfig, writer).Logger(), EnablePreimageRecording: true, } } @@ -930,7 +930,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *direc config = &TraceConfig{} } // Default tracer is the struct logger - tracer = logger.NewStructLogger(config.Config).GetTracer() + tracer = logger.NewStructLogger(config.Config).Tracer() if config.Tracer != nil { tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index d1db00f992..143db5752d 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -133,16 +133,20 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } -func (l *StructLogger) GetTracer() *directory.Tracer { +func (l *StructLogger) Logger() *live.LiveLogger { + return &live.LiveLogger{ + CaptureTxStart: l.CaptureTxStart, + CaptureTxEnd: l.CaptureTxEnd, + CaptureEnd: l.CaptureEnd, + CaptureState: l.CaptureState, + } +} + +func (l *StructLogger) Tracer() *directory.Tracer { return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ - CaptureTxStart: l.CaptureTxStart, - CaptureTxEnd: l.CaptureTxEnd, - CaptureEnd: l.CaptureEnd, - CaptureState: l.CaptureState, - }, - GetResult: l.GetResult, - Stop: l.Stop, + LiveLogger: l.Logger(), + GetResult: l.GetResult, + Stop: l.Stop, } } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index fecfa0cb73..43ba082beb 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -45,7 +45,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) GetLogger() *live.LiveLogger { +func (l *JSONLogger) Logger() *live.LiveLogger { return &live.LiveLogger{ CaptureTxStart: l.CaptureTxStart, CaptureEnd: l.CaptureEnd, diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index cd70f1a970..ddb558832d 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -55,7 +55,7 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.GetTracer().LiveLogger}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Logger()}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index e3ce396374..7f509b8ae6 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -89,7 +89,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.GetTracer().LiveLogger}) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Logger()}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/tests/state_test.go b/tests/state_test.go index 05e7543bff..9759f9cb7a 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -152,7 +152,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - config.Tracer = logger.NewJSONLogger(&logger.Config{}, w).GetLogger() + config.Tracer = logger.NewJSONLogger(&logger.Config{}, w).Logger() err2 := test(config) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) From 39fc9dcafb4c4c01132471c4871ccfa983de3c51 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Feb 2024 19:34:49 +0100 Subject: [PATCH 13/33] move logger interface to core/tracing # Conflicts: # cmd/evm/internal/t8ntool/execution.go # consensus/beacon/consensus.go # consensus/ethash/consensus.go # consensus/misc/dao.go # core/evm.go # core/genesis.go # core/state/state_object.go # core/state/state_test.go # core/state/statedb.go # core/state/statedb_fuzz_test.go # core/state/statedb_test.go # core/state/sync_test.go # core/state/trie_prefetcher_test.go # core/state_transition.go # core/txpool/blobpool/blobpool_test.go # core/txpool/legacypool/legacypool2_test.go # core/txpool/legacypool/legacypool_test.go # core/vm/evm.go # core/vm/instructions.go # core/vm/interface.go # eth/api_debug_test.go # internal/ethapi/api.go # tests/block_test_util.go # tests/state_test_util.go --- cmd/evm/blockrunner.go | 4 +- cmd/evm/internal/t8ntool/execution.go | 10 +- cmd/evm/runner.go | 4 +- consensus/beacon/consensus.go | 4 +- consensus/ethash/consensus.go | 6 +- consensus/misc/dao.go | 6 +- core/blockchain.go | 8 +- core/evm.go | 6 +- core/genesis.go | 6 +- core/state/state_object.go | 8 +- core/state/state_test.go | 16 +- core/state/statedb.go | 16 +- core/state/statedb_fuzz_test.go | 4 +- core/state/statedb_test.go | 56 ++--- core/state/sync_test.go | 4 +- core/state/trie_prefetcher_test.go | 8 +- core/state_processor.go | 4 +- core/state_transition.go | 16 +- core/tracing/hooks.go | 238 +++++++++++++++++++++ core/txpool/blobpool/blobpool_test.go | 36 ++-- core/txpool/legacypool/legacypool2_test.go | 34 +-- core/txpool/legacypool/legacypool_test.go | 14 +- core/vm/contract.go | 6 +- core/vm/contracts.go | 6 +- core/vm/evm.go | 28 +-- core/vm/instructions.go | 28 +-- core/vm/interface.go | 6 +- core/vm/interpreter.go | 20 +- core/vm/operations_acl.go | 4 +- eth/api_debug_test.go | 4 +- eth/ethconfig/config.go | 4 +- eth/tracers/directory/live/dir.go | 113 +--------- eth/tracers/directory/noop.go | 17 +- eth/tracers/directory/tracers.go | 4 +- eth/tracers/js/goja.go | 18 +- eth/tracers/js/tracer_test.go | 4 +- eth/tracers/live/noop.go | 21 +- eth/tracers/logger/access_list_tracer.go | 8 +- eth/tracers/logger/logger.go | 24 +-- eth/tracers/logger/logger_json.go | 14 +- eth/tracers/native/4byte.go | 8 +- eth/tracers/native/call.go | 10 +- eth/tracers/native/call_flat.go | 12 +- eth/tracers/native/mux.go | 16 +- eth/tracers/native/prestate.go | 10 +- internal/ethapi/api.go | 4 +- tests/block_test_util.go | 4 +- tests/state_test_util.go | 6 +- 48 files changed, 510 insertions(+), 397 deletions(-) create mode 100644 core/tracing/hooks.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 8e34deb7f2..ed439b6fb2 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -25,7 +25,7 @@ import ( "sort" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" @@ -50,7 +50,7 @@ func blockTestCmd(ctx *cli.Context) error { return errors.New("path-to-test argument required") } - var tracer *live.LiveLogger + var tracer *tracing.LiveLogger // Configure the EVM logger if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(&logger.Config{ diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index bfcd9fde7d..7129ba88de 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -30,11 +30,11 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -326,15 +326,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) - statedb.AddBalance(ommer.Address, reward, live.BalanceIncreaseRewardMineUncle) + statedb.AddBalance(ommer.Address, reward, tracing.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, minerReward, live.BalanceIncreaseRewardMineBlock) + statedb.AddBalance(pre.Env.Coinbase, minerReward, tracing.BalanceIncreaseRewardMineBlock) } // Apply withdrawals for _, w := range pre.Env.Withdrawals { // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) - statedb.AddBalance(w.Address, amount, live.BalanceIncreaseWithdrawal) + statedb.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) } // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) @@ -377,7 +377,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, a.Balance, live.BalanceIncreaseGenesisBalance) + statedb.SetBalance(addr, a.Balance, tracing.BalanceIncreaseGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 53532aa763..259ea5220e 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -33,9 +33,9 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/params" @@ -117,7 +117,7 @@ func runCmd(ctx *cli.Context) error { } var ( - tracer *live.LiveLogger + tracer *tracing.LiveLogger debugLogger *logger.StructLogger statedb *state.StateDB chainConfig *params.ChainConfig diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 42bf2bd7f9..9f677cf861 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -26,8 +26,8 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -358,7 +358,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(big.Int).SetUint64(w.Amount) amount = amount.Mul(amount, big.NewInt(params.GWei)) - stateDB.AddBalance(w.Address, amount, live.BalanceIncreaseWithdrawal) + stateDB.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index e09bfa10a0..a31d9c0f1c 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -29,8 +29,8 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -565,10 +565,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, big8) - stateDB.AddBalance(uncle.Coinbase, r, live.BalanceIncreaseRewardMineUncle) + stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle) r.Div(blockReward, big32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward, live.BalanceIncreaseRewardMineBlock) + stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index 1f97527588..17e1b799d1 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -22,8 +22,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -81,7 +81,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) { // Move every DAO account and extra-balance account funds into the refund contract for _, addr := range params.DAODrainList() { - statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), live.BalanceIncreaseDaoContract) - statedb.SetBalance(addr, new(big.Int), live.BalanceDecreaseDaoAccount) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract) + statedb.SetBalance(addr, new(big.Int), tracing.BalanceDecreaseDaoAccount) } } diff --git a/core/blockchain.go b/core/blockchain.go index babfcaf8f2..b3f72bd213 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -37,9 +37,9 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/syncx" @@ -266,7 +266,7 @@ type BlockChain struct { processor Processor // Block transaction processor interface forker *ForkChoice vmConfig vm.Config - logger *live.LiveLogger + logger *tracing.LiveLogger } // NewBlockChain returns a fully initialised block chain using information @@ -1794,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } stats.processed++ if bc.logger != nil && bc.logger.OnSkippedBlock != nil { - bc.logger.OnSkippedBlock(live.BlockEvent{ + bc.logger.OnSkippedBlock(tracing.BlockEvent{ Block: block, TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1), Finalized: bc.CurrentFinalBlock(), @@ -1927,7 +1927,7 @@ type blockProcessingResult struct { func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) { if bc.logger != nil && bc.logger.OnBlockStart != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(live.BlockEvent{ + bc.logger.OnBlockStart(tracing.BlockEvent{ Block: block, TD: td, Finalized: bc.CurrentFinalBlock(), diff --git a/core/evm.go b/core/evm.go index 515f8d78a9..52f8b0febf 100644 --- a/core/evm.go +++ b/core/evm.go @@ -22,9 +22,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) // ChainContext supports retrieving headers and consensus parameters from the @@ -136,6 +136,6 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { // Transfer subtracts amount from sender and adds amount to recipient using the given Db func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { - db.SubBalance(sender, amount, live.BalanceChangeTransfer) - db.AddBalance(recipient, amount, live.BalanceChangeTransfer) + db.SubBalance(sender, amount, tracing.BalanceChangeTransfer) + db.AddBalance(recipient, amount, tracing.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index 8e58bb134e..16f8ec83a1 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -30,9 +30,9 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -132,7 +132,7 @@ func (ga *GenesisAlloc) hash() (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, account.Balance, live.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, account.Balance, tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -155,7 +155,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas if account.Balance != nil { // This is not actually logged via tracer because OnGenesisBlock // already captures the allocations. - statedb.AddBalance(addr, account.Balance, live.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, account.Balance, tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) diff --git a/core/state/state_object.go b/core/state/state_object.go index 2c7ffbf896..cd718ae058 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -24,9 +24,9 @@ import ( "time" "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/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" @@ -405,7 +405,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) { // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *big.Int, reason live.BalanceChangeReason) { +func (s *stateObject) AddBalance(amount *big.Int, reason tracing.BalanceChangeReason) { // EIP161: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.Sign() == 0 { @@ -419,14 +419,14 @@ func (s *stateObject) AddBalance(amount *big.Int, reason live.BalanceChangeReaso // SubBalance removes amount from s's balance. // It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *big.Int, reason live.BalanceChangeReason) { +func (s *stateObject) SubBalance(amount *big.Int, reason tracing.BalanceChangeReason) { if amount.IsZero() { return } s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason) } -func (s *stateObject) SetBalance(amount *big.Int, reason live.BalanceChangeReason) { +func (s *stateObject) SetBalance(amount *big.Int, reason tracing.BalanceChangeReason) { s.db.journal.append(balanceChange{ account: &s.address, prev: new(big.Int).Set(s.data.Balance), diff --git a/core/state/state_test.go b/core/state/state_test.go index fe65b28bb4..d749e3219d 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -24,9 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" ) @@ -50,11 +50,11 @@ func TestDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22), live.BalanceChangeUnspecified) + obj1.AddBalance(big.NewInt(22), tracing.BalanceChangeUnspecified) obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(big.NewInt(44), live.BalanceChangeUnspecified) + obj3.SetBalance(big.NewInt(44), tracing.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -104,13 +104,13 @@ func TestIterativeDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22), live.BalanceChangeUnspecified) + obj1.AddBalance(big.NewInt(22), tracing.BalanceChangeUnspecified) obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(big.NewInt(44), live.BalanceChangeUnspecified) + obj3.SetBalance(big.NewInt(44), tracing.BalanceChangeUnspecified) obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) - obj4.AddBalance(big.NewInt(1337), live.BalanceChangeUnspecified) + obj4.AddBalance(big.NewInt(1337), tracing.BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -206,7 +206,7 @@ func TestSnapshot2(t *testing.T) { // db, trie are already non-empty values so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(big.NewInt(42), live.BalanceChangeUnspecified) + so0.SetBalance(big.NewInt(42), tracing.BalanceChangeUnspecified) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.selfDestructed = false @@ -218,7 +218,7 @@ func TestSnapshot2(t *testing.T) { // and one with deleted == true so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(big.NewInt(52), live.BalanceChangeUnspecified) + so1.SetBalance(big.NewInt(52), tracing.BalanceChangeUnspecified) so1.SetNonce(53) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.selfDestructed = true diff --git a/core/state/statedb.go b/core/state/statedb.go index 27bca3d2e8..0047a9c8e1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -26,9 +26,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" @@ -64,7 +64,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState - logger *live.LiveLogger + logger *tracing.LiveLogger snaps *snapshot.Tree // Nil if snapshot is not available snap snapshot.Snapshot // Nil if snapshot is not available @@ -175,7 +175,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) } // SetLogger sets the logger for account update hooks. -func (s *StateDB) SetLogger(l *live.LiveLogger) { +func (s *StateDB) SetLogger(l *tracing.LiveLogger) { s.logger = l } @@ -383,7 +383,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool { */ // AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { +func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount, reason) @@ -391,14 +391,14 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason live.B } // SubBalance subtracts amount from the account associated with addr. -func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { +func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.SubBalance(amount, reason) } } -func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason live.BalanceChangeReason) { +func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.SetBalance(amount, reason) @@ -467,7 +467,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prevbalance: new(big.Int).Set(stateObject.Balance()), }) if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 { - s.logger.OnBalanceChange(addr, prev, n, live.BalanceDecreaseSelfdestruct) + s.logger.OnBalanceChange(addr, prev, n, tracing.BalanceDecreaseSelfdestruct) } stateObject.markSelfdestructed() stateObject.data.Balance = new(big.Int) @@ -856,7 +856,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // If ether was sent to account post-selfdestruct it is burnt. if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 { - s.logger.OnBalanceChange(obj.address, bal, new(big.Int), live.BalanceDecreaseSelfdestructBurn) + s.logger.OnBalanceChange(obj.address, bal, new(big.Int), tracing.BalanceDecreaseSelfdestructBurn) } // We need to maintain account deletions explicitly (will remain // set indefinitely). Note only the first occurred self-destruct diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 5a6009103f..b4b09a5cf7 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -32,9 +32,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/triedb/pathdb" @@ -61,7 +61,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) + s.SetBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 0824c2b07e..28e850ba86 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -33,9 +33,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/triedb/hashdb" @@ -57,7 +57,7 @@ func TestUpdateLeaks(t *testing.T) { // Update it with some accounts for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) - state.AddBalance(addr, big.NewInt(int64(11*i)), live.BalanceChangeUnspecified) + state.AddBalance(addr, big.NewInt(int64(11*i)), tracing.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i)) if i%2 == 0 { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) @@ -92,7 +92,7 @@ func TestIntermediateLeaks(t *testing.T) { finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { - state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), tracing.BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i+tweak)) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) @@ -168,7 +168,7 @@ func TestCopy(t *testing.T) { for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) - obj.AddBalance(big.NewInt(int64(i)), live.BalanceChangeUnspecified) + obj.AddBalance(big.NewInt(int64(i)), tracing.BalanceChangeUnspecified) orig.updateStateObject(obj) } orig.Finalise(false) @@ -185,9 +185,9 @@ func TestCopy(t *testing.T) { copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) - origObj.AddBalance(big.NewInt(2*int64(i)), live.BalanceChangeUnspecified) - copyObj.AddBalance(big.NewInt(3*int64(i)), live.BalanceChangeUnspecified) - ccopyObj.AddBalance(big.NewInt(4*int64(i)), live.BalanceChangeUnspecified) + origObj.AddBalance(big.NewInt(2*int64(i)), tracing.BalanceChangeUnspecified) + copyObj.AddBalance(big.NewInt(3*int64(i)), tracing.BalanceChangeUnspecified) + ccopyObj.AddBalance(big.NewInt(4*int64(i)), tracing.BalanceChangeUnspecified) orig.updateStateObject(origObj) copy.updateStateObject(copyObj) @@ -267,14 +267,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "SetBalance", fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) + s.SetBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, big.NewInt(a.args[0]), live.BalanceChangeUnspecified) + s.AddBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified) }, args: make([]int64, 1), }, @@ -539,7 +539,7 @@ func TestTouchDelete(t *testing.T) { s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() - s.state.AddBalance(common.Address{}, new(big.Int), live.BalanceChangeUnspecified) + s.state.AddBalance(common.Address{}, new(big.Int), tracing.BalanceChangeUnspecified) if len(s.state.journal.dirties) != 1 { t.Fatal("expected one dirty state object") @@ -555,7 +555,7 @@ func TestTouchDelete(t *testing.T) { func TestCopyOfCopy(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.HexToAddress("aaaa") - state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { t.Fatalf("1st copy fail, expected 42, got %v", got) @@ -578,9 +578,9 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -651,9 +651,9 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -720,9 +720,9 @@ func TestCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) @@ -769,7 +769,7 @@ func TestDeleteCreateRevert(t *testing.T) { state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) addr := common.BytesToAddress([]byte("so")) - state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified) root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) @@ -779,7 +779,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.Finalise(true) id := state.Snapshot() - state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), tracing.BalanceChangeUnspecified) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state @@ -821,10 +821,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) { state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) { - state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified) state.SetCode(addr, []byte{1, 2, 3}) a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, big.NewInt(100), live.BalanceChangeUnspecified) + state.SetBalance(a2, big.NewInt(100), tracing.BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}) root, _ = state.Commit(0, false) t.Logf("root: %x", root) @@ -849,7 +849,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { t.Errorf("expected %d, got %d", exp, got) } // Modify the state - state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), tracing.BalanceChangeUnspecified) root, err := state.Commit(0, false) if err == nil { t.Fatalf("expected error, got root :%x", root) @@ -1117,13 +1117,13 @@ func TestResetObject(t *testing.T) { slotB = common.HexToHash("0x2") ) // Initialize account with balance and storage in first transaction. - state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified) state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) state.IntermediateRoot(true) // Reset account and mutate balance and storages state.CreateAccount(addr) - state.SetBalance(addr, big.NewInt(2), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(2), tracing.BalanceChangeUnspecified) state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) root, _ := state.Commit(0, true) @@ -1149,7 +1149,7 @@ func TestDeleteStorage(t *testing.T) { addr = common.HexToAddress("0x1") ) // Initialize account and populate storage - state.SetBalance(addr, big.NewInt(1), live.BalanceChangeUnspecified) + state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified) state.CreateAccount(addr) for i := 0; i < 1000; i++ { slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 86c790a16a..9ee0010730 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -23,9 +23,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -61,7 +61,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) acc := &testAccount{address: common.BytesToAddress([]byte{i})} - obj.AddBalance(big.NewInt(int64(11*i)), live.BalanceChangeUnspecified) + obj.AddBalance(big.NewInt(int64(11*i)), tracing.BalanceChangeUnspecified) acc.balance = big.NewInt(int64(11 * i)) obj.SetNonce(uint64(42 * i)) diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 2a1956392d..a4abe18cc4 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -23,8 +23,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func filledStateDB() *StateDB { @@ -35,9 +35,9 @@ func filledStateDB() *StateDB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), live.BalanceChangeUnspecified) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie + state.SetCode(addr, []byte("hello")) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie for i := 0; i < 100; i++ { sk := common.BigToHash(big.NewInt(int64(i))) state.SetState(addr, sk, sk) // Change the storage trie diff --git a/core/state_processor.go b/core/state_processor.go index 776a104223..d3ca3dde34 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -25,10 +25,10 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -112,7 +112,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // this method takes an already created EVM instance as input. 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) { if evm.Config.Tracer != nil && evm.Config.Tracer.CaptureTxStart != nil { - evm.Config.Tracer.CaptureTxStart(&live.VMContext{ + evm.Config.Tracer.CaptureTxStart(&tracing.VMContext{ ChainConfig: evm.ChainConfig(), StateDB: statedb, BlockNumber: evm.Context.BlockNumber, diff --git a/core/state_transition.go b/core/state_transition.go index f149d2a3a1..b908adeb4c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -24,9 +24,9 @@ import ( "github.com/ethereum/go-ethereum/common" cmath "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -263,13 +263,13 @@ func (st *StateTransition) buyGas() error { } if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil { - st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, live.GasChangeTxInitialBalance) + st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance) } st.gasRemaining += st.msg.GasLimit st.initialGas = st.msg.GasLimit - st.state.SubBalance(st.msg.From, mgval, live.BalanceDecreaseGasBuy) + st.state.SubBalance(st.msg.From, mgval, tracing.BalanceDecreaseGasBuy) return nil } @@ -393,7 +393,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) } if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { - t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, live.GasChangeTxIntrinsicGas) + t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) } st.gasRemaining -= gas @@ -443,7 +443,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } else { fee := new(big.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTip) - st.state.AddBalance(st.evm.Context.Coinbase, fee, live.BalanceIncreaseRewardTransactionFee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -461,17 +461,17 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { } if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, live.GasChangeTxRefunds) + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds) } st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) - st.state.AddBalance(st.msg.From, remaining, live.BalanceIncreaseGasReturn) + st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, live.GasChangeTxLeftOverReturned) + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned) } // Also return remaining gas to the block gas counter so it is diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go new file mode 100644 index 0000000000..6f9795af3b --- /dev/null +++ b/core/tracing/hooks.go @@ -0,0 +1,238 @@ +// 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 . + +package tracing + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +type ScopeContext interface { + GetMemoryData() []byte + GetStackData() []uint256.Int + GetCaller() common.Address + GetAddress() common.Address + GetCallValue() *uint256.Int + GetCallInput() []byte +} + +type StateDB interface { + GetBalance(common.Address) *uint256.Int + GetNonce(common.Address) uint64 + GetCode(common.Address) []byte + GetState(common.Address, common.Hash) common.Hash + Exist(common.Address) bool + GetRefund() uint64 +} + +// Canceler is an interface that wraps the Cancel method. +// It allows loggers to cancel EVM processing. +type Canceler interface { + Cancel() +} + +type VMContext struct { + Coinbase common.Address + BlockNumber *big.Int + Time uint64 + Random *common.Hash + // Effective tx gas price + GasPrice *big.Int + ChainConfig *params.ChainConfig + StateDB StateDB + VM Canceler +} + +// BlockEvent is emitted upon tracing an incoming block. +// It contains the block as well as consensus related information. +type BlockEvent struct { + Block *types.Block + TD *big.Int + Finalized *types.Header + Safe *types.Header +} + +// OpCode is an EVM opcode +// TODO: provide utils for consumers +type OpCode byte + +type LiveLogger struct { + /* + - VM events - + */ + // Transaction level + // Call simulations don't come with a valid signature. `from` field + // to be used for address of the caller. + CaptureTxStart func(vm *VMContext, tx *types.Transaction, from common.Address) + CaptureTxEnd func(receipt *types.Receipt, err error) + // Top call frame + CaptureStart func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) + // CaptureEnd is invoked when the processing of the top call ends. + // See docs for `CaptureExit` for info on the `reverted` parameter. + CaptureEnd func(output []byte, gasUsed uint64, err error, reverted bool) + // Rest of call frames + CaptureEnter func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + // CaptureExit is invoked when the processing of a message ends. + // `revert` is true when there was an error during the execution. + // Exceptionally, before the homestead hardfork a contract creation that + // ran out of gas when attempting to persist the code to database did not + // count as a call failure and did not cause a revert of the call. This will + // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. + CaptureExit func(output []byte, gasUsed uint64, err error, reverted bool) + // Opcode level + CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, rData []byte, depth int, err error) + CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, depth int, err error) + CaptureKeccakPreimage func(hash common.Hash, data []byte) + // Misc + OnGasChange func(old, new uint64, reason GasChangeReason) + + /* + - Chain events - + */ + OnBlockchainInit func(chainConfig *params.ChainConfig) + // OnBlockStart is called before executing `block`. + // `td` is the total difficulty prior to `block`. + OnBlockStart func(event BlockEvent) + OnBlockEnd func(err error) + // OnSkippedBlock indicates a block was skipped during processing + // due to it being known previously. This can happen e.g. when recovering + // from a crash. + OnSkippedBlock func(event BlockEvent) + OnGenesisBlock func(genesis *types.Block, alloc types.GenesisAlloc) + + /* + - State events - + */ + OnBalanceChange func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) + OnNonceChange func(addr common.Address, prev, new uint64) + OnCodeChange func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) + OnStorageChange func(addr common.Address, slot common.Hash, prev, new common.Hash) + OnLog func(log *types.Log) +} + +// BalanceChangeReason is used to indicate the reason for a balance change, useful +// for tracing and reporting. +type BalanceChangeReason byte + +const ( + BalanceChangeUnspecified BalanceChangeReason = 0 + + // Issuance + // BalanceIncreaseRewardMineUncle is a reward for mining an uncle block. + BalanceIncreaseRewardMineUncle BalanceChangeReason = 1 + // BalanceIncreaseRewardMineBlock is a reward for mining a block. + BalanceIncreaseRewardMineBlock BalanceChangeReason = 2 + // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain. + BalanceIncreaseWithdrawal BalanceChangeReason = 3 + // BalanceIncreaseGenesisBalance is ether allocated at the genesis block. + BalanceIncreaseGenesisBalance BalanceChangeReason = 4 + + // Transaction fees + // BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance. + BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5 + // BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction. + // Part of this gas will be burnt as per EIP-1559 rules. + BalanceDecreaseGasBuy BalanceChangeReason = 6 + // BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution. + BalanceIncreaseGasReturn BalanceChangeReason = 7 + + // DAO fork + // BalanceIncreaseDaoContract is ether sent to the DAO refund contract. + BalanceIncreaseDaoContract BalanceChangeReason = 8 + // BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract. + BalanceDecreaseDaoAccount BalanceChangeReason = 9 + + // BalanceChangeTransfer is ether transferred via a call. + // it is a decrease for the sender and an increase for the recipient. + BalanceChangeTransfer BalanceChangeReason = 10 + // BalanceChangeTouchAccount is a transfer of zero value. It is only there to + // touch-create an account. + BalanceChangeTouchAccount BalanceChangeReason = 11 + + // BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account. + BalanceIncreaseSelfdestruct BalanceChangeReason = 12 + // BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct. + BalanceDecreaseSelfdestruct BalanceChangeReason = 13 + // BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed + // account within the same tx (captured at end of tx). + // Note it doesn't account for a self-destruct which appoints itself as recipient. + BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14 +) + +// GasChangeReason is used to indicate the reason for a gas change, useful +// for tracing and reporting. +// +// There is essentially two types of gas changes, those that can be emitted once per transaction +// and those that can be emitted on a call basis, so possibly multiple times per transaction. +// +// They can be recognized easily by their name, those that start with `GasChangeTx` are emitted +// once per transaction, while those that start with `GasChangeCall` are emitted on a call basis. +type GasChangeReason byte + +const ( + GasChangeUnspecified GasChangeReason = iota + + // GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only + // one such gas change per transaction. + GasChangeTxInitialBalance + // GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is + // always exactly one of those per transaction. + GasChangeTxIntrinsicGas + // GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared) + // this generates an increase in gas. There is at most one of such gas change per transaction. + GasChangeTxRefunds + // GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned + // to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas + // left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller. + // There is at most one of such gas change per transaction. + GasChangeTxLeftOverReturned + + // GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only + // one such gas change per call. + GasChangeCallInitialBalance + // GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always + // be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even + // will be emitted. + GasChangeCallLeftOverReturned + // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it + // executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child. + // If there was no gas left to be refunded, no such even will be emitted. + GasChangeCallLeftOverRefunded + // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. + GasChangeCallContractCreation + // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. + GasChangeCallContractCreation2 + // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. + GasChangeCallCodeStorage + // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was + // performed can be check by `CaptureState` handling. + GasChangeCallOpCode + // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution. + GasChangeCallPrecompiledContract + // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules. + GasChangeCallStorageColdAccess + // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. + GasChangeCallFailedExecution + + // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as + // it will be "manually" tracked by a direct emit of the gas change event. + GasChangeIgnored GasChangeReason = 0xFF +) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index a5848fdf0b..e18b1c4caa 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -35,11 +35,11 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -513,17 +513,17 @@ func TestOpenDrops(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), live.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), live.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -638,7 +638,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -738,9 +738,9 @@ func TestOpenHeap(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -818,9 +818,9 @@ func TestOpenCap(t *testing.T) { for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), live.BalanceChangeUnspecified) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1211,7 +1211,7 @@ func TestAdd(t *testing.T) { addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) // Seed the state database with this acocunt - statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), live.BalanceChangeUnspecified) + statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 621987b384..dc62822c9f 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -23,9 +23,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/event" ) @@ -50,11 +50,7 @@ func fillPool(t testing.TB, pool *LegacyPool) { nonExecutableTxs := types.Transactions{} for i := 0; i < 384; i++ { key, _ := crypto.GenerateKey() -<<<<<<< HEAD - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), state.BalanceChangeUnspecified) -======= - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000), live.BalanceChangeUnspecified) ->>>>>>> 8cc747f439 (moaar fixes) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), tracing.BalanceChangeUnspecified) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -96,11 +92,7 @@ func TestTransactionFutureAttack(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() -<<<<<<< HEAD - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) -======= - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) ->>>>>>> 8cc747f439 (moaar fixes) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) @@ -137,11 +129,7 @@ func TestTransactionFuture1559(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() -<<<<<<< HEAD - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) -======= - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) ->>>>>>> 8cc747f439 (moaar fixes) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key)) @@ -195,11 +183,7 @@ func TestTransactionZAttack(t *testing.T) { for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() -<<<<<<< HEAD - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) -======= - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) ->>>>>>> 8cc747f439 (moaar fixes) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.addRemotesSync(futureTxs) } @@ -207,11 +191,7 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() -<<<<<<< HEAD - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), state.BalanceChangeUnspecified) -======= - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), live.BalanceChangeUnspecified) ->>>>>>> 8cc747f439 (moaar fixes) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -248,7 +228,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), core/state/state_test.go.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified) futureTxs := types.Transactions{} for n := 0; n < b.N; n++ { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 719b71bb34..12b759490e 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -33,10 +33,10 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -256,7 +256,7 @@ func (c *testChain) State() (*state.StateDB, error) { c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) - c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), core/state/state_test.go.BalanceChangeUnspecified) + c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) *c.trigger = false } return stdb, nil @@ -276,7 +276,7 @@ func TestStateChangeDuringReset(t *testing.T) { ) // setup pool with 2 transaction in it - statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), core/state/state_test.go.BalanceChangeUnspecified) + statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) @@ -310,7 +310,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, amount, core/state/state_test.go.BalanceChangeUnspecified) + pool.currentState.AddBalance(addr, amount, tracing.BalanceChangeUnspecified) pool.mu.Unlock() } @@ -471,7 +471,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, big.NewInt(100000000000000), core/state/state_test.go.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -500,7 +500,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, big.NewInt(100000000000000), core/state/state_test.go.BalanceChangeUnspecified) + statedb.AddBalance(addr, big.NewInt(100000000000000), tracing.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2619,7 +2619,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) { for i := 0; i < b.N; i++ { key, _ := crypto.GenerateKey() account := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState.AddBalance(account, big.NewInt(1000000), live.BalanceChangeUnspecified) + pool.currentState.AddBalance(account, big.NewInt(1000000), tracing.BalanceChangeUnspecified) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/contract.go b/core/vm/contract.go index fbfc3b125d..291a426b3b 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -20,7 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/holiman/uint256" ) @@ -160,11 +160,11 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64, logger *live.LiveLogger, reason live.GasChangeReason) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger *tracing.LiveLogger, reason tracing.GasChangeReason) (ok bool) { if c.Gas < gas { return false } - if logger != nil && logger.OnGasChange != nil && reason != live.GasChangeIgnored { + if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { logger.OnGasChange(c.Gas, c.Gas-gas, reason) } c.Gas -= gas diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 799665f0cb..6b2512570a 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -25,12 +25,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/blake2b" "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) @@ -169,13 +169,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *live.LiveLogger) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.LiveLogger) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } if logger != nil && logger.OnGasChange != nil { - logger.OnGasChange(suppliedGas, suppliedGas-gasCost, live.GasChangeCallPrecompiledContract) + logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) } suppliedGas -= gasCost output, err := p.Run(input) diff --git a/core/vm/evm.go b/core/vm/evm.go index a3fd2da531..8064de4a86 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -22,9 +22,9 @@ import ( "sync/atomic" "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/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -231,7 +231,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 @@ -287,7 +287,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 @@ -334,7 +334,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 } @@ -369,7 +369,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, // but is the correct thing to do and matters on other networks, in tests, and potential // future scenarios - evm.StateDB.AddBalance(addr, new(big.Int), live.BalanceChangeTouchAccount) + evm.StateDB.AddBalance(addr, new(big.Int), tracing.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) @@ -392,7 +392,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 @@ -443,7 +443,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contractHash := evm.StateDB.GetCodeHash(address) if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, live.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } return nil, common.Address{}, 0, ErrContractAddressCollision @@ -479,7 +479,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // by the error checking condition below. if err == nil { createDataGas := uint64(len(ret)) * params.CreateDataGas - if contract.UseGas(createDataGas, evm.Config.Tracer, live.GasChangeCallCodeStorage) { + if contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas @@ -492,7 +492,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - contract.UseGas(contract.Gas, evm.Config.Tracer, live.GasChangeCallFailedExecution) + contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) } } @@ -526,11 +526,11 @@ func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to co tracer.CaptureStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) } } else if tracer.CaptureEnter != nil { - tracer.CaptureEnter(live.OpCode(typ), from, to, input, startGas, value) + tracer.CaptureEnter(tracing.OpCode(typ), from, to, input, startGas, value) } if tracer.OnGasChange != nil { - tracer.OnGasChange(0, startGas, live.GasChangeCallInitialBalance) + tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) } } @@ -538,7 +538,7 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas tracer := evm.Config.Tracer if leftOverGas != 0 && tracer.OnGasChange != nil { - tracer.OnGasChange(leftOverGas, 0, live.GasChangeCallLeftOverReturned) + tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) } var reverted bool if err != nil { @@ -556,8 +556,8 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas } } -func (evm *EVM) GetVMContext() *live.VMContext { - return &live.VMContext{ +func (evm *EVM) GetVMContext() *tracing.VMContext { + return &tracing.VMContext{ Coinbase: evm.Context.Coinbase, BlockNumber: evm.Context.BlockNumber, Time: evm.Context.Time, diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 3a681775bb..d06b59b121 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -18,9 +18,9 @@ package vm import ( "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/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -594,7 +594,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, live.GasChangeCallContractCreation) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) //TODO: use uint256.Int instead of converting with toBig() var bigVal = big0 if !value.IsZero() { @@ -616,7 +616,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b scope.Stack.push(&stackvalue) if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -642,7 +642,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] ) // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, live.GasChangeCallContractCreation2) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size //TODO: use uint256.Int instead of converting with toBig() @@ -661,7 +661,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] scope.Stack.push(&stackvalue) if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -711,7 +711,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -751,7 +751,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -784,7 +784,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -817,7 +817,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) } if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, live.GasChangeCallLeftOverRefunded) + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) } scope.Contract.Gas += returnGas @@ -855,11 +855,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer.CaptureEnter != nil { - tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.CaptureExit != nil { tracer.CaptureExit([]byte{}, 0, nil, false) @@ -874,12 +874,12 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, live.BalanceDecreaseSelfdestruct) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, live.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer.CaptureEnter != nil { - tracer.CaptureEnter(live.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.CaptureExit != nil { tracer.CaptureExit([]byte{}, 0, nil, false) diff --git a/core/vm/interface.go b/core/vm/interface.go index 94aa015ed9..f6d9cb30ad 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,8 +20,8 @@ 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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -29,8 +29,8 @@ import ( type StateDB interface { CreateAccount(common.Address) - SubBalance(common.Address, *big.Int, live.BalanceChangeReason) - AddBalance(common.Address, *big.Int, live.BalanceChangeReason) + SubBalance(common.Address, *big.Int, tracing.BalanceChangeReason) + AddBalance(common.Address, *big.Int, tracing.BalanceChangeReason) GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 6da530cd06..99d95f0160 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -19,15 +19,15 @@ package vm import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) // Config are the configuration options for the Interpreter type Config struct { - Tracer *live.LiveLogger + Tracer *tracing.LiveLogger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled @@ -191,10 +191,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if err != nil { if !logged { if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pcCopy, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.CaptureState(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) } } else if in.evm.Config.Tracer.CaptureFault != nil { - in.evm.Config.Tracer.CaptureFault(pcCopy, live.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.CaptureFault(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } } }() @@ -219,7 +219,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } else if sLen > operation.maxStack { return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } - if !contract.UseGas(cost, in.evm.Config.Tracer, live.GasChangeIgnored) { + if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } @@ -246,17 +246,17 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( var dynamicCost uint64 dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) cost += dynamicCost // for tracing - if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, live.GasChangeIgnored) { + if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) { return nil, ErrOutOfGas } // Do tracing before memory expansion if debug { if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, live.GasChangeCallOpCode) + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pc, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.CaptureState(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } @@ -265,10 +265,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } } else if debug { if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, live.GasChangeCallOpCode) + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pc, live.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.CaptureState(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index e9f26a88c1..5986de2e7e 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -21,7 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/params" ) @@ -170,7 +170,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc { evm.StateDB.AddAddressToAccessList(addr) // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, live.GasChangeCallStorageColdAccess) { + if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } } diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index f14b96b436..4a5ecf3b7b 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -27,9 +27,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/trie" "golang.org/x/exp/slices" ) @@ -73,7 +73,7 @@ func TestAccountRange(t *testing.T) { hash := common.HexToHash(fmt.Sprintf("%x", i)) addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes()) addrs[i] = addr - sdb.SetBalance(addrs[i], big.NewInt(1), live.BalanceChangeUnspecified) + sdb.SetBalance(addrs[i], big.NewInt(1), tracing.BalanceChangeUnspecified) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 11e43e41b1..7abac3bec5 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -27,11 +27,11 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" @@ -153,7 +153,7 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTracer *live.LiveLogger + VMTracer *tracing.LiveLogger // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index fca3654141..a097754310 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -3,118 +3,11 @@ package live import ( "encoding/json" "errors" - "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" - "github.com/holiman/uint256" + "github.com/ethereum/go-ethereum/core/tracing" ) -type ScopeContext interface { - GetMemoryData() []byte - GetStackData() []uint256.Int - GetCaller() common.Address - GetAddress() common.Address - GetCallValue() *uint256.Int - GetCallInput() []byte -} - -type StateDB interface { - GetBalance(common.Address) *uint256.Int - GetNonce(common.Address) uint64 - GetCode(common.Address) []byte - GetState(common.Address, common.Hash) common.Hash - Exist(common.Address) bool - GetRefund() uint64 -} - -// Canceler is an interface that wraps the Cancel method. -// It allows loggers to cancel EVM processing. -type Canceler interface { - Cancel() -} - -type VMContext struct { - Coinbase common.Address - BlockNumber *big.Int - Time uint64 - Random *common.Hash - // Effective tx gas price - GasPrice *big.Int - ChainConfig *params.ChainConfig - StateDB StateDB - VM Canceler -} - -// BlockEvent is emitted upon tracing an incoming block. -// It contains the block as well as consensus related information. -type BlockEvent struct { - Block *types.Block - TD *big.Int - Finalized *types.Header - Safe *types.Header -} - -// OpCode is an EVM opcode -// TODO: provide utils for consumers -type OpCode byte - -type LiveLogger struct { - /* - - VM events - - */ - // Transaction level - // Call simulations don't come with a valid signature. `from` field - // to be used for address of the caller. - CaptureTxStart func(vm *VMContext, tx *types.Transaction, from common.Address) - CaptureTxEnd func(receipt *types.Receipt, err error) - // Top call frame - CaptureStart func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - // CaptureEnd is invoked when the processing of the top call ends. - // See docs for `CaptureExit` for info on the `reverted` parameter. - CaptureEnd func(output []byte, gasUsed uint64, err error, reverted bool) - // Rest of call frames - CaptureEnter func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) - // CaptureExit is invoked when the processing of a message ends. - // `revert` is true when there was an error during the execution. - // Exceptionally, before the homestead hardfork a contract creation that - // ran out of gas when attempting to persist the code to database did not - // count as a call failure and did not cause a revert of the call. This will - // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. - CaptureExit func(output []byte, gasUsed uint64, err error, reverted bool) - // Opcode level - CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, rData []byte, depth int, err error) - CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, depth int, err error) - CaptureKeccakPreimage func(hash common.Hash, data []byte) - // Misc - OnGasChange func(old, new uint64, reason GasChangeReason) - - /* - - Chain events - - */ - OnBlockchainInit func(chainConfig *params.ChainConfig) - // OnBlockStart is called before executing `block`. - // `td` is the total difficulty prior to `block`. - OnBlockStart func(event BlockEvent) - OnBlockEnd func(err error) - // OnSkippedBlock indicates a block was skipped during processing - // due to it being known previously. This can happen e.g. when recovering - // from a crash. - OnSkippedBlock func(event BlockEvent) - OnGenesisBlock func(genesis *types.Block, alloc types.GenesisAlloc) - - /* - - State events - - */ - OnBalanceChange func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) - OnNonceChange func(addr common.Address, prev, new uint64) - OnCodeChange func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) - OnStorageChange func(addr common.Address, slot common.Hash, prev, new common.Hash) - OnLog func(log *types.Log) -} - -type ctorFunc func(config json.RawMessage) (*LiveLogger, error) +type ctorFunc func(config json.RawMessage) (*tracing.LiveLogger, error) // Directory is the collection of tracers which can be used // during normal block import operations. @@ -130,7 +23,7 @@ func (d *directory) Register(name string, f ctorFunc) { } // New instantiates a tracer by name. -func (d *directory) New(name string, config json.RawMessage) (*LiveLogger, error) { +func (d *directory) New(name string, config json.RawMessage) (*tracing.LiveLogger, error) { if f, ok := d.elems[name]; ok { return f(config) } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 9c28770494..a6bb457d2f 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -21,8 +21,8 @@ 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/eth/tracers/directory/live" ) func init() { @@ -37,7 +37,7 @@ type NoopTracer struct{} func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { t := &NoopTracer{} return &Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureStart: t.CaptureStart, @@ -68,21 +68,21 @@ func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *NoopTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *NoopTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *NoopTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, _ live.ScopeContext, depth int, err error) { +func (t *NoopTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.ScopeContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} // OnGasChange is called when gas is either consumed or refunded. -func (t *NoopTracer) OnGasChange(old, new uint64, reason live.GasChangeReason) {} +func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *NoopTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } // CaptureExit is called when EVM exits a scope, even if the scope didn't @@ -90,11 +90,12 @@ func (t *NoopTracer) CaptureEnter(typ live.OpCode, from common.Address, to commo func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (*NoopTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) {} +func (*NoopTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} -func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { +func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { } func (*NoopTracer) OnNonceChange(a common.Address, prev, new uint64) {} diff --git a/eth/tracers/directory/tracers.go b/eth/tracers/directory/tracers.go index 4953c46c56..78dc9ae6e7 100644 --- a/eth/tracers/directory/tracers.go +++ b/eth/tracers/directory/tracers.go @@ -24,7 +24,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/core/tracing" ) // Context contains some contextual infos for a transaction execution that is not @@ -41,7 +41,7 @@ type Context struct { // This involves a method to retrieve results and one to // stop tracing. type Tracer struct { - *live.LiveLogger + *tracing.LiveLogger GetResult func() (json.RawMessage, error) // Stop terminates execution of the tracer at the first opportune moment. Stop func(err error) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 62115f40a2..578b1a10af 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -23,9 +23,9 @@ import ( "math/big" "github.com/dop251/goja" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" @@ -101,7 +101,7 @@ type jsTracer struct { directory.NoopTracer vm *goja.Runtime - env *live.VMContext + env *tracing.VMContext toBig toBigFn // Converts a hex string into a JS bigint toBuf toBufFn // Converts a []byte into a JS buffer fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte @@ -213,7 +213,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir t.logValue = t.log.setupObject() return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureStart: t.CaptureStart, @@ -230,7 +230,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir // CaptureTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *jsTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env // Need statedb access for db object db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} @@ -300,7 +300,7 @@ func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create b } // CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -325,7 +325,7 @@ func (t *jsTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, sco } // CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { +func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { if t.err != nil { return } @@ -344,7 +344,7 @@ func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *jsTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *jsTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { if !t.traceFrame { return } @@ -697,7 +697,7 @@ func (s *stackObj) setupObject() *goja.Object { } type dbObj struct { - db live.StateDB + db tracing.StateDB vm *goja.Runtime toBig toBigFn toBuf toBufFn @@ -789,7 +789,7 @@ func (do *dbObj) setupObject() *goja.Object { } type contractObj struct { - scope live.ScopeContext + scope tracing.ScopeContext vm *goja.Runtime toBig toBigFn toBuf toBufFn diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index c5a3a7e2f8..ac8fbe23fc 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -26,10 +26,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) @@ -279,7 +279,7 @@ func TestEnterExit(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - tracer.CaptureEnter(live.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.CaptureEnter(tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) tracer.CaptureExit([]byte{}, 400, nil, false) have, err := tracer.GetResult() diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index e099ef9ac5..ea843a38e7 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -5,6 +5,7 @@ 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/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" @@ -20,9 +21,9 @@ func init() { // as soon as we have a real live tracer. type noop struct{} -func newNoopTracer(_ json.RawMessage) (*live.LiveLogger, error) { +func newNoopTracer(_ json.RawMessage) (*tracing.LiveLogger, error) { t := &noop{} - return &live.LiveLogger{ + return &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureStart: t.CaptureStart, @@ -55,18 +56,18 @@ func (t *noop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted boo } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noop) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *noop) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noop) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, _ live.ScopeContext, depth int, err error) { +func (t *noop) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.ScopeContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *noop) CaptureKeccakPreimage(hash common.Hash, data []byte) {} // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *noop) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *noop) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } // CaptureExit is called when EVM exits a scope, even if the scope didn't @@ -74,19 +75,19 @@ func (t *noop) CaptureEnter(typ live.OpCode, from common.Address, to common.Addr func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (t *noop) CaptureTxStart(vm *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *noop) CaptureTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { } func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { } -func (t *noop) OnBlockStart(ev live.BlockEvent) { +func (t *noop) OnBlockStart(ev tracing.BlockEvent) { } func (t *noop) OnBlockEnd(err error) { } -func (t *noop) OnSkippedBlock(ev live.BlockEvent) {} +func (t *noop) OnSkippedBlock(ev tracing.BlockEvent) {} func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { } @@ -94,7 +95,7 @@ func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { func (t *noop) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { } -func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { +func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { } func (t *noop) OnNonceChange(a common.Address, prev, new uint64) { @@ -110,5 +111,5 @@ func (t *noop) OnLog(l *types.Log) { } -func (t *noop) OnGasChange(old, new uint64, reason live.GasChangeReason) { +func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index fdc990dfee..51e03ba25d 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -18,10 +18,10 @@ package logger import ( "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/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -133,14 +133,14 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) GetLogger() *live.LiveLogger { - return &live.LiveLogger{ +func (a *AccessListTracer) GetLogger() *tracing.LiveLogger { + return &tracing.LiveLogger{ CaptureState: a.CaptureState, } } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (a *AccessListTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { stackData := scope.GetStackData() stackLen := len(stackData) op := vm.OpCode(opcode) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 143db5752d..8165ce5087 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -28,10 +28,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -110,7 +110,7 @@ func (s *StructLog) ErrorString() string { type StructLogger struct { directory.NoopTracer cfg Config - env *live.VMContext + env *tracing.VMContext storage map[common.Address]Storage logs []StructLog @@ -133,8 +133,8 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } -func (l *StructLogger) Logger() *live.LiveLogger { - return &live.LiveLogger{ +func (l *StructLogger) Logger() *tracing.LiveLogger { + return &tracing.LiveLogger{ CaptureTxStart: l.CaptureTxStart, CaptureTxEnd: l.CaptureTxEnd, CaptureEnd: l.CaptureEnd, @@ -161,7 +161,7 @@ func (l *StructLogger) Reset() { // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -264,7 +264,7 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (l *StructLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } @@ -339,7 +339,7 @@ type mdLogger struct { directory.NoopTracer out io.Writer cfg *Config - env *live.VMContext + env *tracing.VMContext } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -352,8 +352,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) Logger() *live.LiveLogger { - return &live.LiveLogger{ +func (t *mdLogger) Logger() *tracing.LiveLogger { + return &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureStart: t.CaptureStart, CaptureState: t.CaptureState, @@ -362,7 +362,7 @@ func (t *mdLogger) Logger() *live.LiveLogger { } } -func (t *mdLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *mdLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env } @@ -384,7 +384,7 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b } // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { stack := scope.GetStackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) @@ -404,7 +404,7 @@ func (t *mdLogger) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, sco } } -func (t *mdLogger) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { +func (t *mdLogger) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 43ba082beb..76278c2bca 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -22,17 +22,17 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) type JSONLogger struct { directory.NoopTracer encoder *json.Encoder cfg *Config - env *live.VMContext + env *tracing.VMContext } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects @@ -45,8 +45,8 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) Logger() *live.LiveLogger { - return &live.LiveLogger{ +func (l *JSONLogger) Logger() *tracing.LiveLogger { + return &tracing.LiveLogger{ CaptureTxStart: l.CaptureTxStart, CaptureEnd: l.CaptureEnd, CaptureState: l.CaptureState, @@ -54,13 +54,13 @@ func (l *JSONLogger) Logger() *live.LiveLogger { } } -func (l *JSONLogger) CaptureFault(pc uint64, op live.OpCode, gas uint64, cost uint64, scope live.ScopeContext, depth int, err error) { +func (l *JSONLogger) CaptureFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.ScopeContext, depth int, err error) { // TODO: Add rData to this interface as well l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { memory := scope.GetMemoryData() stack := scope.GetStackData() @@ -100,6 +100,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, revert l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (l *JSONLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index aa2dbd906a..8f83f068b2 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -23,10 +23,10 @@ import ( "sync/atomic" "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/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func init() { @@ -62,7 +62,7 @@ func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tr ids: make(map[string]int), } return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureStart: t.CaptureStart, CaptureEnter: t.CaptureEnter, @@ -88,7 +88,7 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -func (t *fourByteTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *fourByteTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) @@ -103,7 +103,7 @@ func (t *fourByteTracer) CaptureStart(from common.Address, to common.Address, cr } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *fourByteTracer) CaptureEnter(opcode live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) CaptureEnter(opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if t.interrupt.Load() { return diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 74a13038d9..831b39cf7d 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -25,10 +25,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go @@ -127,7 +127,7 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac return nil, err } return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureStart: t.CaptureStart, @@ -176,11 +176,11 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *callTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *callTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.depth++ if t.config.OnlyTopCall { return @@ -223,7 +223,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, rever t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *callTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.gasLimit = tx.Gas() } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 4cd5308e40..d0914e04a8 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -25,10 +25,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) //go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go @@ -141,7 +141,7 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: ft.CaptureTxStart, CaptureTxEnd: ft.CaptureTxEnd, CaptureStart: ft.CaptureStart, @@ -167,17 +167,17 @@ func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, re } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *flatCallTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { +func (t *flatCallTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *flatCallTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *flatCallTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.tracer.CaptureEnter(typ, from, to, input, gas, value) // Child calls must have a value, even if it's zero. @@ -211,7 +211,7 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, r } } -func (t *flatCallTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *flatCallTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.tracer.CaptureTxStart(env, tx, from) // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 501f598385..92099133bf 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -21,9 +21,9 @@ 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/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" ) func init() { @@ -58,7 +58,7 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace t := &muxTracer{names: names, tracers: objects} return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureStart: t.CaptureStart, @@ -99,7 +99,7 @@ func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverte } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { for _, t := range t.tracers { if t.CaptureState != nil { t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) @@ -108,7 +108,7 @@ func (t *muxTracer) CaptureState(pc uint64, op live.OpCode, gas, cost uint64, sc } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op live.OpCode, gas, cost uint64, scope live.ScopeContext, depth int, err error) { +func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { for _, t := range t.tracers { if t.CaptureFault != nil { t.CaptureFault(pc, op, gas, cost, scope, depth, err) @@ -126,7 +126,7 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { } // CaptureGasConsumed is called when gas is consumed. -func (t *muxTracer) OnGasChange(old, new uint64, reason live.GasChangeReason) { +func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { for _, t := range t.tracers { if t.OnGasChange != nil { t.OnGasChange(old, new, reason) @@ -135,7 +135,7 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason live.GasChangeReason) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *muxTracer) CaptureEnter(typ live.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { if t.CaptureEnter != nil { t.CaptureEnter(typ, from, to, input, gas, value) @@ -153,7 +153,7 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, revert } } -func (t *muxTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *muxTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { if t.CaptureTxStart != nil { t.CaptureTxStart(env, tx, from) @@ -169,7 +169,7 @@ func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt, err error) { } } -func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason live.BalanceChangeReason) { +func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { for _, t := range t.tracers { if t.OnBalanceChange != nil { t.OnBalanceChange(a, prev, new, reason) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 7ac77ffaa9..f6483eb2cb 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,11 +24,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/directory" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/log" ) @@ -59,7 +59,7 @@ type accountMarshaling struct { type prestateTracer struct { directory.NoopTracer - env *live.VMContext + env *tracing.VMContext pre stateMap post stateMap to common.Address @@ -89,7 +89,7 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. deleted: make(map[common.Address]bool), } return &directory.Tracer{ - LiveLogger: &live.LiveLogger{ + LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, CaptureState: t.CaptureState, @@ -100,7 +100,7 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost uint64, scope live.ScopeContext, rData []byte, depth int, err error) { +func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { if err != nil { return } @@ -146,7 +146,7 @@ func (t *prestateTracer) CaptureState(pc uint64, opcode live.OpCode, gas, cost u } } -func (t *prestateTracer) CaptureTxStart(env *live.VMContext, tx *types.Transaction, from common.Address) { +func (t *prestateTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env if tx.To() == nil { t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 39d79413bd..305975775f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -37,10 +37,10 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" @@ -961,7 +961,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { } // Override account balance. if account.Balance != nil { - statedb.SetBalance(addr, (*big.Int)(*account.Balance), live.BalanceChangeUnspecified) + statedb.SetBalance(addr, (*big.Int)(*account.Balance), tracing.BalanceChangeUnspecified) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 5a021b245a..37b89afc51 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -34,9 +34,9 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -109,7 +109,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *live.LiveLogger) error { +func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.LiveLogger) error { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 25b50a79e3..a12714181b 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -32,10 +32,10 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -299,7 +299,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - the coinbase self-destructed, or // - there are only 'bad' transactions, which aren't executed. In those cases, // the coinbase gets no txfee, so isn't created, and thus needs to be touched - statedb.AddBalance(block.Coinbase(), new(big.Int), live.BalanceChangeUnspecified) + statedb.AddBalance(block.Coinbase(), new(big.Int), tracing.BalanceChangeUnspecified) // Commit state mutations into database. root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number())) @@ -323,7 +323,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo for addr, a := range accounts { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce) - statedb.SetBalance(addr, a.Balance, live.BalanceChangeUnspecified) + statedb.SetBalance(addr, a.Balance, tracing.BalanceChangeUnspecified) for k, v := range a.Storage { statedb.SetState(addr, k, v) } From d4ec634c05a2308389962e00dc849ecc36e84705 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Feb 2024 19:41:58 +0100 Subject: [PATCH 14/33] rename GetLogger to Hooks # Conflicts: # eth/tracers/logger/access_list_tracer.go # eth/tracers/logger/logger.go # eth/tracers/logger/logger_json.go # eth/tracers/logger/logger_test.go # eth/tracers/tracers_test.go # internal/ethapi/api.go --- cmd/evm/blockrunner.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/runner.go | 4 ++-- cmd/evm/staterunner.go | 4 ++-- core/blockchain_test.go | 6 +++--- core/tracing/hooks.go | 3 ++- eth/tracers/api.go | 2 +- eth/tracers/logger/access_list_tracer.go | 4 ++-- eth/tracers/logger/logger.go | 14 +++++++------- eth/tracers/logger/logger_json.go | 4 ++-- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- internal/ethapi/api.go | 2 +- tests/state_test.go | 2 +- 14 files changed, 27 insertions(+), 26 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index ed439b6fb2..1f7d07f31a 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -58,7 +58,7 @@ func blockTestCmd(ctx *cli.Context) error { DisableStack: ctx.Bool(DisableStackFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), - }, os.Stderr).Logger() + }, os.Stderr).Hooks() } // Load the test content from the input file src, err := os.ReadFile(ctx.Args().First()) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 20b5eee1b1..97a1101544 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -124,7 +124,7 @@ func Transition(ctx *cli.Context) error { if err != nil { return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - logger := logger.NewJSONLogger(logConfig, traceFile).Logger() + logger := logger.NewJSONLogger(logConfig, traceFile).Hooks() tracer := &directory.Tracer{ LiveLogger: logger, // JSONLogger streams out result to file. diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 259ea5220e..47ae707063 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -128,10 +128,10 @@ func runCmd(ctx *cli.Context) error { blobBaseFee = new(big.Int) // TODO (MariusVanDerWijden) implement blob fee in state tests ) if ctx.Bool(MachineFlag.Name) { - tracer = logger.NewJSONLogger(logconfig, os.Stdout).Logger() + tracer = logger.NewJSONLogger(logconfig, os.Stdout).Hooks() } else if ctx.Bool(DebugFlag.Name) { debugLogger = logger.NewStructLogger(logconfig) - tracer = debugLogger.Logger() + tracer = debugLogger.Hooks() } else { debugLogger = logger.NewStructLogger(logconfig) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 5e26ff2ee6..0bb8f73439 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -61,10 +61,10 @@ func stateTestCmd(ctx *cli.Context) error { var cfg vm.Config switch { case ctx.Bool(MachineFlag.Name): - cfg.Tracer = logger.NewJSONLogger(config, os.Stderr).Logger() + cfg.Tracer = logger.NewJSONLogger(config, os.Stderr).Hooks() case ctx.Bool(DebugFlag.Name): - cfg.Tracer = logger.NewStructLogger(config).Logger() + cfg.Tracer = logger.NewStructLogger(config).Hooks() } // Load the test content from the input file if len(ctx.Args().First()) != 0 { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index c3f77d70da..b5fa0cffa2 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3248,7 +3248,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout).Logger(), + Tracer: logger.NewJSONLogger(nil, os.Stdout).Hooks(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -3330,7 +3330,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout).Logger(), + Tracer: logger.NewJSONLogger(nil, os.Stdout).Hooks(), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -4682,7 +4682,7 @@ func TestEIP3651(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Logger()}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 6f9795af3b..6a89003677 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -116,7 +117,7 @@ type LiveLogger struct { // due to it being known previously. This can happen e.g. when recovering // from a crash. OnSkippedBlock func(event BlockEvent) - OnGenesisBlock func(genesis *types.Block, alloc types.GenesisAlloc) + OnGenesisBlock func(genesis *types.Block, alloc core.GenesisAlloc) /* - State events - diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 0fb13696c3..d3f565edbe 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -777,7 +777,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Swap out the noop logger to the standard tracer writer = bufio.NewWriter(dump) vmConf = vm.Config{ - Tracer: logger.NewJSONLogger(&logConfig, writer).Logger(), + Tracer: logger.NewJSONLogger(&logConfig, writer).Hooks(), EnablePreimageRecording: true, } } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 51e03ba25d..a69c8b3048 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -133,8 +133,8 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) GetLogger() *tracing.LiveLogger { - return &tracing.LiveLogger{ +func (a *AccessListTracer) Hooks() *tracing.Hooks { + return &tracing.Hooks{ CaptureState: a.CaptureState, } } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 8165ce5087..2398a803d8 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -133,8 +133,8 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } -func (l *StructLogger) Logger() *tracing.LiveLogger { - return &tracing.LiveLogger{ +func (l *StructLogger) Hooks() *tracing.Hooks { + return &tracing.Hooks{ CaptureTxStart: l.CaptureTxStart, CaptureTxEnd: l.CaptureTxEnd, CaptureEnd: l.CaptureEnd, @@ -144,9 +144,9 @@ func (l *StructLogger) Logger() *tracing.LiveLogger { func (l *StructLogger) Tracer() *directory.Tracer { return &directory.Tracer{ - LiveLogger: l.Logger(), - GetResult: l.GetResult, - Stop: l.Stop, + Hooks: l.Hooks(), + GetResult: l.GetResult, + Stop: l.Stop, } } @@ -352,8 +352,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) Logger() *tracing.LiveLogger { - return &tracing.LiveLogger{ +func (t *mdLogger) Hooks() *tracing.Hooks { + return &tracing.Hooks{ CaptureTxStart: t.CaptureTxStart, CaptureStart: t.CaptureStart, CaptureState: t.CaptureState, diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 76278c2bca..246b91bdf3 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -45,8 +45,8 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) Logger() *tracing.LiveLogger { - return &tracing.LiveLogger{ +func (l *JSONLogger) Hooks() *tracing.Hooks { + return &tracing.Hooks{ CaptureTxStart: l.CaptureTxStart, CaptureEnd: l.CaptureEnd, CaptureState: l.CaptureState, diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index ddb558832d..c2982ab036 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -55,7 +55,7 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Logger()}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 7f509b8ae6..505db4fa4e 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -89,7 +89,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Logger()}) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 305975775f..d1ac21b9d8 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1640,7 +1640,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) - config := vm.Config{Tracer: tracer.GetLogger(), NoBaseFee: true} + config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { diff --git a/tests/state_test.go b/tests/state_test.go index 9759f9cb7a..bf098055d4 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -152,7 +152,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - config.Tracer = logger.NewJSONLogger(&logger.Config{}, w).Logger() + config.Tracer = logger.NewJSONLogger(&logger.Config{}, w).Hooks() err2 := test(config) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) From 688f0b965460eb9a19e38adce8ac77e0b67517c9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 29 Feb 2024 15:13:03 +0100 Subject: [PATCH 15/33] rename scopeContext to opContext --- core/tracing/hooks.go | 20 +++++++++++--------- core/vm/interpreter.go | 12 ++++++------ eth/tracers/directory/noop.go | 4 ++-- eth/tracers/js/goja.go | 18 +++++++++--------- eth/tracers/live/noop.go | 4 ++-- eth/tracers/logger/access_list_tracer.go | 6 +++--- eth/tracers/logger/logger.go | 14 +++++++------- eth/tracers/logger/logger_json.go | 8 ++++---- eth/tracers/native/call.go | 2 +- eth/tracers/native/call_flat.go | 4 ++-- eth/tracers/native/mux.go | 4 ++-- eth/tracers/native/prestate.go | 8 ++++---- 12 files changed, 53 insertions(+), 51 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 6a89003677..3d78009f95 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -26,13 +26,15 @@ import ( "github.com/holiman/uint256" ) -type ScopeContext interface { - GetMemoryData() []byte - GetStackData() []uint256.Int - GetCaller() common.Address - GetAddress() common.Address - GetCallValue() *uint256.Int - GetCallInput() []byte +// OpContext provides the context at which the opcode is being +// executed in, including the memory, stack and various contract-level information. +type OpContext interface { + MemoryData() []byte + StackData() []uint256.Int + Caller() common.Address + Address() common.Address + CallValue() *uint256.Int + CallInput() []byte } type StateDB interface { @@ -99,8 +101,8 @@ type LiveLogger struct { // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. CaptureExit func(output []byte, gasUsed uint64, err error, reverted bool) // Opcode level - CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, rData []byte, depth int, err error) - CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope ScopeContext, depth int, err error) + CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) CaptureKeccakPreimage func(hash common.Hash, data []byte) // Misc OnGasChange func(old, new uint64, reason GasChangeReason) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 99d95f0160..b19e79531f 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -41,33 +41,33 @@ type ScopeContext struct { Contract *Contract } -func (ctx *ScopeContext) GetMemoryData() []byte { +func (ctx *ScopeContext) MemoryData() []byte { if ctx.Memory == nil { return nil } return ctx.Memory.Data() } -func (ctx *ScopeContext) GetStackData() []uint256.Int { +func (ctx *ScopeContext) StackData() []uint256.Int { if ctx.Stack == nil { return nil } return ctx.Stack.Data() } -func (ctx *ScopeContext) GetCaller() common.Address { +func (ctx *ScopeContext) Caller() common.Address { return ctx.Contract.Caller() } -func (ctx *ScopeContext) GetAddress() common.Address { +func (ctx *ScopeContext) Address() common.Address { return ctx.Contract.Address() } -func (ctx *ScopeContext) GetCallValue() *uint256.Int { +func (ctx *ScopeContext) CallValue() *uint256.Int { return ctx.Contract.Value() } -func (ctx *ScopeContext) GetCallInput() []byte { +func (ctx *ScopeContext) CallInput() []byte { return ctx.Contract.Input } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index a6bb457d2f..2c250a066a 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -68,11 +68,11 @@ func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *NoopTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *NoopTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *NoopTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.ScopeContext, depth int, err error) { +func (t *NoopTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 578b1a10af..c9bf5ab5b9 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -300,7 +300,7 @@ func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create b } // CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -310,8 +310,8 @@ func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, log := t.log log.op.op = vm.OpCode(op) - log.memory.memory = scope.GetMemoryData() - log.stack.stack = scope.GetStackData() + log.memory.memory = scope.MemoryData() + log.stack.stack = scope.StackData() log.contract.scope = scope log.pc = pc log.gas = gas @@ -325,7 +325,7 @@ func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } // CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { +func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { if t.err != nil { return } @@ -789,14 +789,14 @@ func (do *dbObj) setupObject() *goja.Object { } type contractObj struct { - scope tracing.ScopeContext + scope tracing.OpContext vm *goja.Runtime toBig toBigFn toBuf toBufFn } func (co *contractObj) GetCaller() goja.Value { - caller := co.scope.GetCaller().Bytes() + caller := co.scope.Caller().Bytes() res, err := co.toBuf(co.vm, caller) if err != nil { co.vm.Interrupt(err) @@ -806,7 +806,7 @@ func (co *contractObj) GetCaller() goja.Value { } func (co *contractObj) GetAddress() goja.Value { - addr := co.scope.GetAddress().Bytes() + addr := co.scope.Address().Bytes() res, err := co.toBuf(co.vm, addr) if err != nil { co.vm.Interrupt(err) @@ -816,7 +816,7 @@ func (co *contractObj) GetAddress() goja.Value { } func (co *contractObj) GetValue() goja.Value { - value := co.scope.GetCallValue() + value := co.scope.CallValue() res, err := co.toBig(co.vm, value.String()) if err != nil { co.vm.Interrupt(err) @@ -826,7 +826,7 @@ func (co *contractObj) GetValue() goja.Value { } func (co *contractObj) GetInput() goja.Value { - input := common.CopyBytes(co.scope.GetCallInput()) + input := common.CopyBytes(co.scope.CallInput()) res, err := co.toBuf(co.vm, input) if err != nil { co.vm.Interrupt(err) diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index ea843a38e7..b5d8c3ae5b 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -56,11 +56,11 @@ func (t *noop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted boo } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noop) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *noop) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noop) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.ScopeContext, depth int, err error) { +func (t *noop) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index a69c8b3048..7e76080a94 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -140,13 +140,13 @@ func (a *AccessListTracer) Hooks() *tracing.Hooks { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { - stackData := scope.GetStackData() +func (a *AccessListTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + stackData := scope.StackData() stackLen := len(stackData) op := vm.OpCode(opcode) if (op == vm.SLOAD || op == vm.SSTORE) && stackLen >= 1 { slot := common.Hash(stackData[stackLen-1].Bytes32()) - a.list.addSlot(scope.GetAddress(), slot) + a.list.addSlot(scope.Address(), slot) } if (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT) && stackLen >= 1 { addr := common.Address(stackData[stackLen-1].Bytes20()) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 2398a803d8..3867749d46 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -161,7 +161,7 @@ func (l *StructLogger) Reset() { // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -172,8 +172,8 @@ func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost } op := vm.OpCode(opcode) - memory := scope.GetMemoryData() - stack := scope.GetStackData() + memory := scope.MemoryData() + stack := scope.StackData() // Copy a snapshot of the current memory state to a new buffer var mem []byte if l.cfg.EnableMemory { @@ -188,7 +188,7 @@ func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost stck[i] = item } } - contractAddr := scope.GetAddress() + contractAddr := scope.Address() stackLen := len(stack) // Copy a snapshot of the current storage to a new container var storage Storage @@ -384,8 +384,8 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b } // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { - stack := scope.GetStackData() +func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) if !t.cfg.DisableStack { @@ -404,7 +404,7 @@ func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } } -func (t *mdLogger) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { +func (t *mdLogger) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 246b91bdf3..72eda302d8 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -54,15 +54,15 @@ func (l *JSONLogger) Hooks() *tracing.Hooks { } } -func (l *JSONLogger) CaptureFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.ScopeContext, depth int, err error) { +func (l *JSONLogger) CaptureFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { // TODO: Add rData to this interface as well l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { - memory := scope.GetMemoryData() - stack := scope.GetStackData() +func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + memory := scope.MemoryData() + stack := scope.StackData() log := StructLog{ Pc: pc, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 831b39cf7d..0b6790ce89 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -176,7 +176,7 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index d0914e04a8..9eef26ca5e 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -167,12 +167,12 @@ func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, re } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *flatCallTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { +func (t *flatCallTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 92099133bf..68b600b923 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -99,7 +99,7 @@ func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverte } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { for _, t := range t.tracers { if t.CaptureState != nil { t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) @@ -108,7 +108,7 @@ func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, depth int, err error) { +func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { for _, t := range t.tracers { if t.CaptureFault != nil { t.CaptureFault(pc, op, gas, cost, scope, depth, err) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index f6483eb2cb..765356f10f 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -100,7 +100,7 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.ScopeContext, rData []byte, depth int, err error) { +func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if err != nil { return } @@ -109,9 +109,9 @@ func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cos return } op := vm.OpCode(opcode) - stackData := scope.GetStackData() + stackData := scope.StackData() stackLen := len(stackData) - caller := scope.GetAddress() + caller := scope.Address() switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) @@ -133,7 +133,7 @@ func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cos case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] - init, err := directory.GetMemoryCopyPadded(scope.GetMemoryData(), int64(offset.Uint64()), int64(size.Uint64())) + init, err := directory.GetMemoryCopyPadded(scope.MemoryData(), int64(offset.Uint64()), int64(size.Uint64())) if err != nil { log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size) return From 3253b8bab55fa1d467afc03eb12d3bca3b1a3d41 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 29 Feb 2024 15:33:23 +0100 Subject: [PATCH 16/33] assign const values for gas change reasons --- core/tracing/hooks.go | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 3d78009f95..f7488e537d 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -37,6 +37,7 @@ type OpContext interface { CallInput() []byte } +// StateDB gives tracers access to the whole state. type StateDB interface { GetBalance(common.Address) *uint256.Int GetNonce(common.Address) uint64 @@ -52,6 +53,7 @@ type Canceler interface { Cancel() } +// VMContext provides the context for the EVM execution. type VMContext struct { Coinbase common.Address BlockNumber *big.Int @@ -191,49 +193,49 @@ const ( type GasChangeReason byte const ( - GasChangeUnspecified GasChangeReason = iota + GasChangeUnspecified GasChangeReason = 0 // GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only // one such gas change per transaction. - GasChangeTxInitialBalance + GasChangeTxInitialBalance GasChangeReason = 1 // GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is // always exactly one of those per transaction. - GasChangeTxIntrinsicGas + GasChangeTxIntrinsicGas GasChangeReason = 2 // GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared) // this generates an increase in gas. There is at most one of such gas change per transaction. - GasChangeTxRefunds + GasChangeTxRefunds GasChangeReason = 3 // GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned // to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas // left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller. // There is at most one of such gas change per transaction. - GasChangeTxLeftOverReturned + GasChangeTxLeftOverReturned GasChangeReason = 4 // GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only // one such gas change per call. - GasChangeCallInitialBalance + GasChangeCallInitialBalance GasChangeReason = 5 // GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always // be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even // will be emitted. - GasChangeCallLeftOverReturned + GasChangeCallLeftOverReturned GasChangeReason = 6 // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it // executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child. // If there was no gas left to be refunded, no such even will be emitted. - GasChangeCallLeftOverRefunded + GasChangeCallLeftOverRefunded GasChangeReason = 7 // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. - GasChangeCallContractCreation + GasChangeCallContractCreation GasChangeReason = 8 // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. - GasChangeCallContractCreation2 + GasChangeCallContractCreation2 GasChangeReason = 9 // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. - GasChangeCallCodeStorage + GasChangeCallCodeStorage GasChangeReason = 10 // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was // performed can be check by `CaptureState` handling. - GasChangeCallOpCode + GasChangeCallOpCode GasChangeReason = 11 // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution. - GasChangeCallPrecompiledContract + GasChangeCallPrecompiledContract GasChangeReason = 12 // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules. - GasChangeCallStorageColdAccess + GasChangeCallStorageColdAccess GasChangeReason = 13 // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. - GasChangeCallFailedExecution + GasChangeCallFailedExecution GasChangeReason = 14 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // it will be "manually" tracked by a direct emit of the gas change event. From e7fe23698816620dc91c828c51509a1629f6e250 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 29 Feb 2024 16:22:34 +0100 Subject: [PATCH 17/33] a type for each hook # Conflicts: # core/tracing/hooks.go --- core/tracing/hooks.go | 120 +++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index f7488e537d..e8584c2b64 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -20,7 +20,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -79,58 +78,115 @@ type BlockEvent struct { // TODO: provide utils for consumers type OpCode byte -type LiveLogger struct { +type ( /* - VM events - */ - // Transaction level + + // TxStartHook is called before the execution of a transaction starts. // Call simulations don't come with a valid signature. `from` field // to be used for address of the caller. - CaptureTxStart func(vm *VMContext, tx *types.Transaction, from common.Address) - CaptureTxEnd func(receipt *types.Receipt, err error) - // Top call frame - CaptureStart func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - // CaptureEnd is invoked when the processing of the top call ends. - // See docs for `CaptureExit` for info on the `reverted` parameter. - CaptureEnd func(output []byte, gasUsed uint64, err error, reverted bool) - // Rest of call frames - CaptureEnter func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) - // CaptureExit is invoked when the processing of a message ends. + TxStartHook = func(vm *VMContext, tx *types.Transaction, from common.Address) + + // TxEndHook is called after the execution of a transaction ends. + TxEndHook = func(receipt *types.Receipt, err error) + + // StartHook is invoked when the processing of the root call starts. + StartHook = func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) + + // EndHook is invoked when the processing of the top call ends. + // See docs for `ExitHook` for info on the `reverted` parameter. + EndHook = func(output []byte, gasUsed uint64, err error, reverted bool) + + // EnterHook is invoked when the processing of a message starts. + EnterHook = func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + + // ExitHook is invoked when the processing of a message ends. // `revert` is true when there was an error during the execution. // Exceptionally, before the homestead hardfork a contract creation that // ran out of gas when attempting to persist the code to database did not // count as a call failure and did not cause a revert of the call. This will // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. - CaptureExit func(output []byte, gasUsed uint64, err error, reverted bool) - // Opcode level - CaptureState func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) - CaptureFault func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) - CaptureKeccakPreimage func(hash common.Hash, data []byte) - // Misc - OnGasChange func(old, new uint64, reason GasChangeReason) + ExitHook = func(output []byte, gasUsed uint64, err error, reverted bool) + + // StateHook is invoked just prior to the execution of an opcode. + StateHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + + // FaultHook is invoked when an error occurs during the execution of an opcode. + FaultHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) + + // KeccakPreimageHook is invoked on the KECCAK256 opcode to provide the preimage for the hash. + KeccakPreimageHook = func(hash common.Hash, data []byte) + + // GasChangeHook is invoked when the gas changes. + GasChangeHook = func(old, new uint64, reason GasChangeReason) /* - Chain events - */ - OnBlockchainInit func(chainConfig *params.ChainConfig) - // OnBlockStart is called before executing `block`. + + // BlockchainInitHook is called when the blockchain is initialized. + BlockchainInitHook = func(chainConfig *params.ChainConfig) + + // BlockStartHook is called before executing `block`. // `td` is the total difficulty prior to `block`. - OnBlockStart func(event BlockEvent) - OnBlockEnd func(err error) - // OnSkippedBlock indicates a block was skipped during processing + BlockStartHook = func(event BlockEvent) + + // BlockEndHook is called after executing a block. + BlockEndHook = func(err error) + + // SkippedBlockHook indicates a block was skipped during processing // due to it being known previously. This can happen e.g. when recovering // from a crash. - OnSkippedBlock func(event BlockEvent) - OnGenesisBlock func(genesis *types.Block, alloc core.GenesisAlloc) + SkippedBlockHook = func(event BlockEvent) + + // GenesisBlockHook is called when the genesis block is being processed. + GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) /* - State events - */ - OnBalanceChange func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) - OnNonceChange func(addr common.Address, prev, new uint64) - OnCodeChange func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) - OnStorageChange func(addr common.Address, slot common.Hash, prev, new common.Hash) - OnLog func(log *types.Log) + + // BalanceChangeHook is called when the balance of an account changes. + BalanceChangeHook = func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) + + // NonceChangeHook is called when the nonce of an account changes. + NonceChangeHook = func(addr common.Address, prev, new uint64) + + // CodeChangeHook is called when the code of an account changes. + CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) + + // StorageChangeHook is called when the storage of an account changes. + StorageChangeHook = func(addr common.Address, slot common.Hash, prev, new common.Hash) + + // LogHook is called when a log is emitted. + LogHook = func(log *types.Log) +) + +type Hooks struct { + // VM events + CaptureTxStart TxStartHook + CaptureTxEnd TxEndHook + CaptureStart StartHook + CaptureEnd EndHook + CaptureEnter EnterHook + CaptureExit ExitHook + CaptureState StateHook + CaptureFault FaultHook + CaptureKeccakPreimage KeccakPreimageHook + OnGasChange GasChangeHook + // Chain events + OnBlockchainInit BlockchainInitHook + OnBlockStart BlockStartHook + OnBlockEnd BlockEndHook + OnSkippedBlock SkippedBlockHook + OnGenesisBlock GenesisBlockHook + // State events + OnBalanceChange BalanceChangeHook + OnNonceChange NonceChangeHook + OnCodeChange CodeChangeHook + OnStorageChange StorageChangeHook + OnLog LogHook } // BalanceChangeReason is used to indicate the reason for a balance change, useful From a2ad953d213f770ebf872f222322962d0f82dbd7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 29 Feb 2024 16:38:54 +0100 Subject: [PATCH 18/33] rm old logger file --- core/vm/logger.go | 51 ----------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 core/vm/logger.go diff --git a/core/vm/logger.go b/core/vm/logger.go deleted file mode 100644 index 269aed509c..0000000000 --- a/core/vm/logger.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 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 . - -package vm - -// EVMLogger is used to collect execution traces from an EVM transaction -// execution. CaptureState is called for each step of the VM with the -// current VM state. -// Note that reference types are actual VM data structures; make copies -// if you need to retain them beyond the current call. -/*type EVMLogger interface { - // Transaction level - // Call simulations don't come with a valid signature. `from` field - // to be used for address of the caller. - CaptureTxStart(evm *EVM, tx *types.Transaction, from common.Address) - CaptureTxEnd(receipt *types.Receipt, err error) - // Top call frame - CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - // CaptureEnd is invoked when the processing of the top call ends. - // See docs for `CaptureExit` for info on the `reverted` parameter. - CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) - // Rest of call frames - CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) - // CaptureExit is invoked when the processing of a message ends. - // `revert` is true when there was an error during the execution. - // Exceptionally, before the homestead hardfork a contract creation that - // ran out of gas when attempting to persist the code to database did not - // count as a call failure and did not cause a revert of the call. This will - // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. - CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) - // Opcode level - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) - CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) - CaptureKeccakPreimage(hash common.Hash, data []byte) - // Misc - OnGasChange(old, new uint64, reason GasChangeReason) -} -*/ From 25a3a744c3202c535e5ff57233c7c36125622a72 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 29 Feb 2024 17:18:43 +0100 Subject: [PATCH 19/33] rename Capture hooks to On # Conflicts: # cmd/evm/internal/t8ntool/execution.go # core/vm/instructions.go # eth/tracers/directory/noop.go # eth/tracers/internal/tracetest/calltrace_test.go # eth/tracers/internal/tracetest/flat_calltrace_test.go # eth/tracers/internal/tracetest/prestate_test.go # eth/tracers/js/goja.go # eth/tracers/js/tracer_test.go # eth/tracers/live/noop.go # eth/tracers/native/4byte.go # eth/tracers/native/call.go # eth/tracers/native/call_flat.go # eth/tracers/native/mux.go # eth/tracers/native/prestate.go --- cmd/evm/internal/t8ntool/execution.go | 6 +- core/state_processor.go | 8 +-- core/tracing/hooks.go | 26 +++---- core/vm/evm.go | 16 ++--- core/vm/instructions.go | 20 +++--- core/vm/interpreter.go | 16 ++--- core/vm/runtime/runtime.go | 6 +- core/vm/runtime/runtime_test.go | 10 +-- eth/tracers/api.go | 4 +- eth/tracers/directory/noop.go | 32 ++++----- .../internal/tracetest/calltrace_test.go | 10 +-- .../internal/tracetest/flat_calltrace_test.go | 6 +- .../internal/tracetest/prestate_test.go | 6 +- eth/tracers/js/goja.go | 22 +++--- eth/tracers/js/tracer_test.go | 30 ++++---- eth/tracers/live/noop.go | 42 ++++++------ eth/tracers/logger/access_list_tracer.go | 2 +- eth/tracers/logger/logger.go | 18 ++--- eth/tracers/logger/logger_json.go | 8 +-- eth/tracers/native/4byte.go | 8 +-- eth/tracers/native/call.go | 12 ++++ eth/tracers/native/call_flat.go | 18 ++--- eth/tracers/native/mux.go | 68 +++++++++---------- eth/tracers/native/prestate.go | 8 +-- 24 files changed, 207 insertions(+), 195 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 7129ba88de..4e72d11b5b 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -241,7 +241,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) if tracer != nil { - tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) @@ -251,7 +251,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) if tracer != nil { - tracer.CaptureTxEnd(nil, err) + tracer.OnTxEnd(nil, err) if err := writeTraceResult(tracer, traceOutput); err != nil { log.Warn("Error writing tracer output", "err", err) } @@ -298,7 +298,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) if tracer != nil { - tracer.LiveLogger.CaptureTxEnd(receipt, nil) + tracer.Hooks.OnTxEnd(receipt, nil) writeTraceResult(tracer, traceOutput) } } diff --git a/core/state_processor.go b/core/state_processor.go index d3ca3dde34..59e3c80c2a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -111,8 +111,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // 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 *state.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.CaptureTxStart != nil { - evm.Config.Tracer.CaptureTxStart(&tracing.VMContext{ + if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil { + evm.Config.Tracer.OnTxStart(&tracing.VMContext{ ChainConfig: evm.ChainConfig(), StateDB: statedb, BlockNumber: evm.Context.BlockNumber, @@ -120,9 +120,9 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo Coinbase: evm.Context.Coinbase, Random: evm.Context.Random, }, tx, msg.From) - if evm.Config.Tracer.CaptureTxEnd != nil { + if evm.Config.Tracer.OnTxEnd != nil { defer func() { - evm.Config.Tracer.CaptureTxEnd(receipt, err) + evm.Config.Tracer.OnTxEnd(receipt, err) }() } } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index e8584c2b64..f912a6c87d 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -109,8 +109,8 @@ type ( // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. ExitHook = func(output []byte, gasUsed uint64, err error, reverted bool) - // StateHook is invoked just prior to the execution of an opcode. - StateHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + // OpcodeHook is invoked just prior to the execution of an opcode. + OpcodeHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) // FaultHook is invoked when an error occurs during the execution of an opcode. FaultHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) @@ -165,16 +165,16 @@ type ( type Hooks struct { // VM events - CaptureTxStart TxStartHook - CaptureTxEnd TxEndHook - CaptureStart StartHook - CaptureEnd EndHook - CaptureEnter EnterHook - CaptureExit ExitHook - CaptureState StateHook - CaptureFault FaultHook - CaptureKeccakPreimage KeccakPreimageHook - OnGasChange GasChangeHook + OnTxStart TxStartHook + OnTxEnd TxEndHook + OnStart StartHook + OnEnd EndHook + OnEnter EnterHook + OnExit ExitHook + OnOpcode OpcodeHook + OnFault FaultHook + OnKeccakPreimage KeccakPreimageHook + OnGasChange GasChangeHook // Chain events OnBlockchainInit BlockchainInitHook OnBlockStart BlockStartHook @@ -284,7 +284,7 @@ const ( // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. GasChangeCallCodeStorage GasChangeReason = 10 // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was - // performed can be check by `CaptureState` handling. + // performed can be check by `OnOpcode` handling. GasChangeCallOpCode GasChangeReason = 11 // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution. GasChangeCallPrecompiledContract GasChangeReason = 12 diff --git a/core/vm/evm.go b/core/vm/evm.go index 8064de4a86..ba314b51da 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -522,11 +522,11 @@ func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to co tracer := evm.Config.Tracer if isRoot { - if tracer.CaptureStart != nil { - tracer.CaptureStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) + if tracer.OnStart != nil { + tracer.OnStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) } - } else if tracer.CaptureEnter != nil { - tracer.CaptureEnter(tracing.OpCode(typ), from, to, input, startGas, value) + } else if tracer.OnEnter != nil { + tracer.OnEnter(tracing.OpCode(typ), from, to, input, startGas, value) } if tracer.OnGasChange != nil { @@ -548,11 +548,11 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas reverted = false } if isRoot { - if tracer.CaptureEnd != nil { - tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + if tracer.OnEnd != nil { + tracer.OnEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } - } else if tracer.CaptureExit != nil { - tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + } else if tracer.OnExit != nil { + tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index d06b59b121..0f85f424e5 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -248,8 +248,8 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if evm.Config.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.CaptureKeccakPreimage != nil { - interpreter.evm.Config.Tracer.CaptureKeccakPreimage(common.BytesToHash(interpreter.hasherBuf[:]), data) + if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnKeccakPreimage != nil { + interpreter.evm.Config.Tracer.OnKeccakPreimage(common.BytesToHash(interpreter.hasherBuf[:]), data) } size.SetBytes(interpreter.hasherBuf[:]) return nil, nil @@ -858,11 +858,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - if tracer.CaptureEnter != nil { - tracer.CaptureEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + if tracer.OnEnter != nil { + tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } - if tracer.CaptureExit != nil { - tracer.CaptureExit([]byte{}, 0, nil, false) + if tracer.OnExit != nil { + tracer.OnExit([]byte{}, 0, nil, false) } } return nil, errStopToken @@ -878,11 +878,11 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { - if tracer.CaptureEnter != nil { - tracer.CaptureEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + if tracer.OnEnter != nil { + tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } - if tracer.CaptureExit != nil { - tracer.CaptureExit([]byte{}, 0, nil, false) + if tracer.OnExit != nil { + tracer.OnExit([]byte{}, 0, nil, false) } } return nil, errStopToken diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index b19e79531f..4d867fbc05 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -190,11 +190,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( defer func() { if err != nil { if !logged { - if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) } - } else if in.evm.Config.Tracer.CaptureFault != nil { - in.evm.Config.Tracer.CaptureFault(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + } else if in.evm.Config.Tracer.OnFault != nil { + in.evm.Config.Tracer.OnFault(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } } }() @@ -255,8 +255,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if in.evm.Config.Tracer.OnGasChange != nil { in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } - if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } @@ -267,8 +267,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if in.evm.Config.Tracer.OnGasChange != nil { in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } - if in.evm.Config.Tracer.CaptureState != nil { - in.evm.Config.Tracer.CaptureState(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index aba137c50c..49415e50fa 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -123,7 +123,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -159,7 +159,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -190,7 +190,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil { - cfg.EVMConfig.Tracer.CaptureTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) + cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 2997ca5351..fdf8abbc1f 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -335,7 +335,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode b.Fatal(err) } cfg.EVMConfig = vm.Config{ - Tracer: tracer.LiveLogger, + Tracer: tracer.Hooks, } } var ( @@ -510,7 +510,7 @@ func TestEip2929Cases(t *testing.T) { code, ops) Execute(code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Logger(), + Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Hooks(), ExtraEips: []int{2929}, }, }) @@ -663,7 +663,7 @@ func TestColdAccountAccessCost(t *testing.T) { tracer := logger.NewStructLogger(nil) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: tracer.GetTracer().LiveLogger, + Tracer: tracer.Hooks(), }, }) have := tracer.StructLogs()[tc.step].GasCost @@ -834,7 +834,7 @@ func TestRuntimeJSTracer(t *testing.T) { GasLimit: 1000000, State: statedb, EVMConfig: vm.Config{ - Tracer: tracer.LiveLogger, + Tracer: tracer.Hooks, }}) if err != nil { t.Fatal("didn't expect error", err) @@ -868,7 +868,7 @@ func TestJSTracerCreateTx(t *testing.T) { _, _, _, err = Create(code, &Config{ State: statedb, EVMConfig: vm.Config{ - Tracer: tracer.LiveLogger, + Tracer: tracer.Hooks, }}) if err != nil { t.Fatal(err) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d3f565edbe..d0eefa84b1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -784,9 +784,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - vmConf.Tracer.CaptureTxStart(vmenv.GetVMContext(), tx, msg.From) + vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) - vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) if writer != nil { writer.Flush() } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 2c250a066a..637f0da326 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -37,22 +37,22 @@ type NoopTracer struct{} func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { t := &NoopTracer{} return &Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureStart: t.CaptureStart, - CaptureEnd: t.CaptureEnd, - CaptureEnter: t.CaptureEnter, - CaptureExit: t.CaptureExit, - CaptureState: t.CaptureState, - CaptureFault: t.CaptureFault, - CaptureKeccakPreimage: t.CaptureKeccakPreimage, - OnGasChange: t.OnGasChange, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnStart: t.CaptureStart, + OnEnd: t.CaptureEnd, + OnEnter: t.CaptureEnter, + OnExit: t.CaptureExit, + OnOpcode: t.CaptureState, + OnFault: t.CaptureFault, + OnKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, GetResult: t.GetResult, Stop: t.Stop, diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index fcc56180d1..01c5ae1fdb 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -149,13 +149,13 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) - tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected. res, err := tracer.GetResult() if err != nil { @@ -398,12 +398,12 @@ func TestInternals(t *testing.T) { if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) } - tc.tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) + tc.tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) } - tc.tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) + tc.tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected res, err := tc.tracer.GetResult() if err != nil { diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 7ae99d2b9d..8cf9eae541 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -107,13 +107,13 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) - tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return fmt.Errorf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the etalon res, err := tracer.GetResult() diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 08e1eccc3c..a055ba334d 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -117,13 +117,13 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) - tracer.CaptureTxStart(evm.GetVMContext(), tx, msg.From) + evm := vm.NewEVM(context, core.NewEVMTxContext(msg), statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) + tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected res, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index c9bf5ab5b9..3d96253b71 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -213,15 +213,15 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir t.logValue = t.log.setupObject() return &directory.Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureStart: t.CaptureStart, - CaptureEnd: t.CaptureEnd, - CaptureEnter: t.CaptureEnter, - CaptureExit: t.CaptureExit, - CaptureState: t.CaptureState, - CaptureFault: t.CaptureFault, + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnStart: t.CaptureStart, + OnEnd: t.CaptureEnd, + OnEnter: t.CaptureEnter, + OnExit: t.CaptureExit, + OnOpcode: t.CaptureState, + OnFault: t.CaptureFault, }, GetResult: t.GetResult, Stop: t.Stop, @@ -329,7 +329,7 @@ func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, if t.err != nil { return } - // Other log fields have been already set as part of the last CaptureState. + // Other log fields have been already set as part of the last OnOpcode. t.log.err = err if _, err := t.fault(t.obj, t.logValue, t.dbValue); err != nil { t.onError("fault", err) @@ -407,7 +407,7 @@ func (t *jsTracer) Stop(err error) { // execution. func (t *jsTracer) onError(context string, err error) { t.err = wrapError(context, err) - // `env` is set on CaptureStart which comes before any JS execution. + // `env` is set on OnStart which comes before any JS execution. // So it should be non-nil. t.env.VM.Cancel() } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index ac8fbe23fc..c1546ca055 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -75,12 +75,12 @@ func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.Chain contract.Code = contractCode } - tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) - tracer.CaptureStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.OnStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) - tracer.CaptureEnd(ret, startGas-contract.Gas, err, true) + tracer.OnEnd(ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund - tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) + tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) if err != nil { return nil, err } @@ -185,13 +185,13 @@ func TestHaltBetweenSteps(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.LiveLogger}) - tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) - tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) - tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) + tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") tracer.Stop(timeout) - tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) + tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) if _, err := tracer.GetResult(); !strings.Contains(err.Error(), timeout.Error()) { t.Errorf("Expected timeout error, got %v", err) @@ -207,10 +207,10 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.LiveLogger}) - tracer.CaptureTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) - tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) - tracer.CaptureEnd(nil, 0, nil, false) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) + tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) + tracer.OnEnd(nil, 0, nil, false) ret, err := tracer.GetResult() if err != nil { t.Fatal(err) @@ -279,8 +279,8 @@ func TestEnterExit(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - tracer.CaptureEnter(tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) - tracer.CaptureExit([]byte{}, 400, nil, false) + tracer.OnEnter(tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.OnExit([]byte{}, 400, nil, false) have, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index b5d8c3ae5b..05560cfb24 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -23,27 +23,27 @@ type noop struct{} func newNoopTracer(_ json.RawMessage) (*tracing.LiveLogger, error) { t := &noop{} - return &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureStart: t.CaptureStart, - CaptureEnd: t.CaptureEnd, - CaptureEnter: t.CaptureEnter, - CaptureExit: t.CaptureExit, - CaptureState: t.CaptureState, - CaptureFault: t.CaptureFault, - CaptureKeccakPreimage: t.CaptureKeccakPreimage, - OnGasChange: t.OnGasChange, - OnBlockchainInit: t.OnBlockchainInit, - OnBlockStart: t.OnBlockStart, - OnBlockEnd: t.OnBlockEnd, - OnSkippedBlock: t.OnSkippedBlock, - OnGenesisBlock: t.OnGenesisBlock, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + return &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnStart: t.CaptureStart, + OnEnd: t.CaptureEnd, + OnEnter: t.CaptureEnter, + OnExit: t.CaptureExit, + OnOpcode: t.CaptureState, + OnFault: t.CaptureFault, + OnKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBlockchainInit: t.OnBlockchainInit, + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnSkippedBlock: t.OnSkippedBlock, + OnGenesisBlock: t.OnGenesisBlock, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, nil } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 7e76080a94..92df195fe0 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -135,7 +135,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi func (a *AccessListTracer) Hooks() *tracing.Hooks { return &tracing.Hooks{ - CaptureState: a.CaptureState, + OnOpcode: a.CaptureState, } } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 3867749d46..6e694368b1 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -135,10 +135,10 @@ func NewStructLogger(cfg *Config) *StructLogger { func (l *StructLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - CaptureTxStart: l.CaptureTxStart, - CaptureTxEnd: l.CaptureTxEnd, - CaptureEnd: l.CaptureEnd, - CaptureState: l.CaptureState, + OnTxStart: l.CaptureTxStart, + OnTxEnd: l.CaptureTxEnd, + OnEnd: l.CaptureEnd, + OnOpcode: l.CaptureState, } } @@ -354,11 +354,11 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { func (t *mdLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - CaptureTxStart: t.CaptureTxStart, - CaptureStart: t.CaptureStart, - CaptureState: t.CaptureState, - CaptureFault: t.CaptureFault, - CaptureEnd: t.CaptureEnd, + OnTxStart: t.CaptureTxStart, + OnStart: t.CaptureStart, + OnOpcode: t.CaptureState, + OnFault: t.CaptureFault, + OnEnd: t.CaptureEnd, } } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 72eda302d8..5067fb8a58 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -47,10 +47,10 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { func (l *JSONLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - CaptureTxStart: l.CaptureTxStart, - CaptureEnd: l.CaptureEnd, - CaptureState: l.CaptureState, - CaptureFault: l.CaptureFault, + OnTxStart: l.CaptureTxStart, + OnEnd: l.CaptureEnd, + OnOpcode: l.CaptureState, + OnFault: l.CaptureFault, } } diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 8f83f068b2..a0a4a6ff4f 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -62,10 +62,10 @@ func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tr ids: make(map[string]int), } return &directory.Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureStart: t.CaptureStart, - CaptureEnter: t.CaptureEnter, + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnStart: t.CaptureStart, + OnEnter: t.CaptureEnter, }, GetResult: t.GetResult, Stop: t.Stop, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 0b6790ce89..d42f36666b 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -127,6 +127,7 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac return nil, err } return &directory.Tracer{ +<<<<<<< HEAD LiveLogger: &tracing.LiveLogger{ CaptureTxStart: t.CaptureTxStart, CaptureTxEnd: t.CaptureTxEnd, @@ -136,6 +137,17 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac CaptureExit: t.CaptureExit, CaptureState: t.CaptureState, OnLog: t.OnLog, +======= + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnStart: t.CaptureStart, + OnEnd: t.CaptureEnd, + OnEnter: t.CaptureEnter, + OnExit: t.CaptureExit, + OnOpcode: t.CaptureState, + OnLog: t.OnLog, +>>>>>>> 923c180058 (rename Capture hooks to On) }, GetResult: t.GetResult, Stop: t.Stop, diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 9eef26ca5e..c0ec5c312e 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -141,15 +141,15 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} return &directory.Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: ft.CaptureTxStart, - CaptureTxEnd: ft.CaptureTxEnd, - CaptureStart: ft.CaptureStart, - CaptureEnd: ft.CaptureEnd, - CaptureEnter: ft.CaptureEnter, - CaptureExit: ft.CaptureExit, - CaptureState: ft.CaptureState, - CaptureFault: ft.CaptureFault, + Hooks: &tracing.Hooks{ + OnTxStart: ft.CaptureTxStart, + OnTxEnd: ft.CaptureTxEnd, + OnStart: ft.CaptureStart, + OnEnd: ft.CaptureEnd, + OnEnter: ft.CaptureEnter, + OnExit: ft.CaptureExit, + OnOpcode: ft.CaptureState, + OnFault: ft.CaptureFault, }, Stop: ft.Stop, GetResult: ft.GetResult, diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 68b600b923..4516ab1dff 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -58,22 +58,22 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace t := &muxTracer{names: names, tracers: objects} return &directory.Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureStart: t.CaptureStart, - CaptureEnd: t.CaptureEnd, - CaptureEnter: t.CaptureEnter, - CaptureExit: t.CaptureExit, - CaptureState: t.CaptureState, - CaptureFault: t.CaptureFault, - CaptureKeccakPreimage: t.CaptureKeccakPreimage, - OnGasChange: t.OnGasChange, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnStart: t.CaptureStart, + OnEnd: t.CaptureEnd, + OnEnter: t.CaptureEnter, + OnExit: t.CaptureExit, + OnOpcode: t.CaptureState, + OnFault: t.CaptureFault, + OnKeccakPreimage: t.CaptureKeccakPreimage, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, GetResult: t.GetResult, Stop: t.Stop, @@ -83,8 +83,8 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { - if t.CaptureStart != nil { - t.CaptureStart(from, to, create, input, gas, value) + if t.OnStart != nil { + t.OnStart(from, to, create, input, gas, value) } } } @@ -92,8 +92,8 @@ func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create // CaptureEnd is called after the call finishes to finalize the tracing. func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - if t.CaptureEnd != nil { - t.CaptureEnd(output, gasUsed, err, reverted) + if t.OnEnd != nil { + t.OnEnd(output, gasUsed, err, reverted) } } } @@ -101,8 +101,8 @@ func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverte // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { for _, t := range t.tracers { - if t.CaptureState != nil { - t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + if t.OnOpcode != nil { + t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) } } } @@ -110,8 +110,8 @@ func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, // CaptureFault implements the EVMLogger interface to trace an execution fault. func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { for _, t := range t.tracers { - if t.CaptureFault != nil { - t.CaptureFault(pc, op, gas, cost, scope, depth, err) + if t.OnFault != nil { + t.OnFault(pc, op, gas, cost, scope, depth, err) } } } @@ -119,8 +119,8 @@ func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { for _, t := range t.tracers { - if t.CaptureKeccakPreimage != nil { - t.CaptureKeccakPreimage(hash, data) + if t.OnKeccakPreimage != nil { + t.OnKeccakPreimage(hash, data) } } } @@ -137,8 +137,8 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { - if t.CaptureEnter != nil { - t.CaptureEnter(typ, from, to, input, gas, value) + if t.OnEnter != nil { + t.OnEnter(typ, from, to, input, gas, value) } } } @@ -147,24 +147,24 @@ func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to com // execute any code. func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - if t.CaptureExit != nil { - t.CaptureExit(output, gasUsed, err, reverted) + if t.OnExit != nil { + t.OnExit(output, gasUsed, err, reverted) } } } func (t *muxTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { - if t.CaptureTxStart != nil { - t.CaptureTxStart(env, tx, from) + if t.OnTxStart != nil { + t.OnTxStart(env, tx, from) } } } func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt, err error) { for _, t := range t.tracers { - if t.CaptureTxEnd != nil { - t.CaptureTxEnd(receipt, err) + if t.OnTxEnd != nil { + t.OnTxEnd(receipt, err) } } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 765356f10f..5e053236a9 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -89,10 +89,10 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. deleted: make(map[common.Address]bool), } return &directory.Tracer{ - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureState: t.CaptureState, + Hooks: &tracing.Hooks{ + OnTxStart: t.CaptureTxStart, + OnTxEnd: t.CaptureTxEnd, + OnOpcode: t.CaptureState, }, GetResult: t.GetResult, Stop: t.Stop, From 03e48ee4512a0c8a8551b2ac36f95d5e2d7a4944 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 6 Mar 2024 16:34:18 +0100 Subject: [PATCH 20/33] rename tracer methods to On pattern # Conflicts # core/vm/interpreter.go # eth/tracers/directory/noop.go # eth/tracers/js/goja.go # eth/tracers/live/noop.go # eth/tracers/logger/logger.go # eth/tracers/logger/logger_json.go # eth/tracers/native/4byte.go # eth/tracers/native/call.go # eth/tracers/native/call_flat.go # eth/tracers/native/mux.go --- cmd/evm/blockrunner.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/runner.go | 2 +- core/blockchain.go | 2 +- core/state/statedb.go | 4 +- core/tracing/hooks.go | 3 +- core/vm/contract.go | 2 +- core/vm/contracts.go | 2 +- core/vm/interpreter.go | 6 +- eth/ethconfig/config.go | 2 +- eth/tracers/api.go | 4 +- eth/tracers/directory/live/dir.go | 4 +- eth/tracers/directory/noop.go | 45 +++++---------- eth/tracers/directory/tracers.go | 2 +- .../internal/tracetest/calltrace_test.go | 8 +-- .../internal/tracetest/flat_calltrace_test.go | 2 +- .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/goja.go | 54 ++++++++++-------- eth/tracers/js/tracer_test.go | 2 +- eth/tracers/live/noop.go | 48 ++++++---------- eth/tracers/logger/access_list_tracer.go | 6 +- eth/tracers/logger/logger.go | 56 ++++++++++++------- eth/tracers/logger/logger_json.go | 23 ++++---- eth/tracers/logger/logger_test.go | 3 +- eth/tracers/native/4byte.go | 21 ++----- eth/tracers/native/call.go | 53 +++++++++--------- eth/tracers/native/call_flat.go | 54 +++++------------- eth/tracers/native/mux.go | 55 +++++------------- eth/tracers/native/prestate.go | 14 ++--- tests/block_test_util.go | 2 +- 31 files changed, 206 insertions(+), 281 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 1f7d07f31a..07af0bc9a2 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -50,7 +50,7 @@ func blockTestCmd(ctx *cli.Context) error { return errors.New("path-to-test argument required") } - var tracer *tracing.LiveLogger + var tracer *tracing.Hooks // Configure the EVM logger if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(&logger.Config{ diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 4e72d11b5b..52e5bbe9de 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -229,7 +229,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return nil, nil, nil, err } if vmConfig.Tracer != nil { - vmConfig.Tracer = tracer.LiveLogger + vmConfig.Tracer = tracer.Hooks } statedb.SetTxContext(tx.Hash(), txIndex) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 97a1101544..bb28620b01 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -126,7 +126,7 @@ func Transition(ctx *cli.Context) error { } logger := logger.NewJSONLogger(logConfig, traceFile).Hooks() tracer := &directory.Tracer{ - LiveLogger: logger, + Hooks: logger, // JSONLogger streams out result to file. GetResult: func() (json.RawMessage, error) { return nil, nil }, Stop: func(err error) {}, diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 47ae707063..3d481d5fe7 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -117,7 +117,7 @@ func runCmd(ctx *cli.Context) error { } var ( - tracer *tracing.LiveLogger + tracer *tracing.Hooks debugLogger *logger.StructLogger statedb *state.StateDB chainConfig *params.ChainConfig diff --git a/core/blockchain.go b/core/blockchain.go index b3f72bd213..cc88434e8f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -266,7 +266,7 @@ type BlockChain struct { processor Processor // Block transaction processor interface forker *ForkChoice vmConfig vm.Config - logger *tracing.LiveLogger + logger *tracing.Hooks } // NewBlockChain returns a fully initialised block chain using information diff --git a/core/state/statedb.go b/core/state/statedb.go index 0047a9c8e1..054f022708 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -64,7 +64,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState - logger *tracing.LiveLogger + logger *tracing.Hooks snaps *snapshot.Tree // Nil if snapshot is not available snap snapshot.Snapshot // Nil if snapshot is not available @@ -175,7 +175,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) } // SetLogger sets the logger for account update hooks. -func (s *StateDB) SetLogger(l *tracing.LiveLogger) { +func (s *StateDB) SetLogger(l *tracing.Hooks) { s.logger = l } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index f912a6c87d..872d4af2dd 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -141,7 +142,7 @@ type ( SkippedBlockHook = func(event BlockEvent) // GenesisBlockHook is called when the genesis block is being processed. - GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) + GenesisBlockHook = func(genesis *types.Block, alloc core.GenesisAlloc) /* - State events - diff --git a/core/vm/contract.go b/core/vm/contract.go index 291a426b3b..860d0f2467 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -160,7 +160,7 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64, logger *tracing.LiveLogger, reason tracing.GasChangeReason) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) { if c.Gas < gas { return false } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 6b2512570a..821f33327a 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -169,7 +169,7 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.LiveLogger) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4d867fbc05..bee43ac1cd 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -27,7 +27,7 @@ import ( // Config are the configuration options for the Interpreter type Config struct { - Tracer *tracing.LiveLogger + Tracer *tracing.Hooks NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled @@ -178,8 +178,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( res []byte // result of the opcode execution function debug = in.evm.Config.Tracer != nil ) - // Don't move this deferred function, it's placed before the capturestate-deferred method, - // so that it get's executed _after_: the capturestate needs the stacks before + // Don't move this deferred function, it's placed before the OnOpcode-deferred method, + // so that it gets executed _after_: the OnOpcode needs the stacks before // they are returned to the pools defer func() { returnStack(stack) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 7abac3bec5..33ee536f88 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -153,7 +153,7 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTracer *tracing.LiveLogger + VMTracer *tracing.Hooks // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d0eefa84b1..447ba3119c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -937,8 +937,8 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *direc return nil, err } } - vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.LiveLogger, NoBaseFee: true}) - statedb.SetLogger(tracer.LiveLogger) + vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, 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 { diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/directory/live/dir.go index a097754310..cedf81c35e 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/directory/live/dir.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" ) -type ctorFunc func(config json.RawMessage) (*tracing.LiveLogger, error) +type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error) // Directory is the collection of tracers which can be used // during normal block import operations. @@ -23,7 +23,7 @@ func (d *directory) Register(name string, f ctorFunc) { } // New instantiates a tracer by name. -func (d *directory) New(name string, config json.RawMessage) (*tracing.LiveLogger, error) { +func (d *directory) New(name string, config json.RawMessage) (*tracing.Hooks, error) { if f, ok := d.elems[name]; ok { return f(config) } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 637f0da326..551c6635e1 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -38,15 +38,13 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { t := &NoopTracer{} return &Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnStart: t.CaptureStart, - OnEnd: t.CaptureEnd, - OnEnter: t.CaptureEnter, - OnExit: t.CaptureExit, - OnOpcode: t.CaptureState, - OnFault: t.CaptureFault, - OnKeccakPreimage: t.CaptureKeccakPreimage, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnKeccakPreimage: t.OnKeccakPreimage, OnGasChange: t.OnGasChange, OnBalanceChange: t.OnBalanceChange, OnNonceChange: t.OnNonceChange, @@ -59,41 +57,26 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *NoopTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *NoopTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *NoopTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { -} +func (t *NoopTracer) OnKeccakPreimage(hash common.Hash, data []byte) {} -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *NoopTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { -} - -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -// OnGasChange is called when gas is either consumed or refunded. func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *NoopTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *NoopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { } -func (*NoopTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (*NoopTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { } -func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} +func (*NoopTracer) OnTxEnd(receipt *types.Receipt, err error) {} func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { } diff --git a/eth/tracers/directory/tracers.go b/eth/tracers/directory/tracers.go index 78dc9ae6e7..766278974c 100644 --- a/eth/tracers/directory/tracers.go +++ b/eth/tracers/directory/tracers.go @@ -41,7 +41,7 @@ type Context struct { // This involves a method to retrieve results and one to // stop tracing. type Tracer struct { - *tracing.LiveLogger + *tracing.Hooks GetResult func() (json.RawMessage, error) // Stop terminates execution of the tracer at the first opportune moment. Stop func(err error) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 01c5ae1fdb..8ca877aea5 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -144,7 +144,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer.LiveLogger) + 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) @@ -251,7 +251,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err != nil { b.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.LiveLogger}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) snap := statedb.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -379,7 +379,7 @@ func TestInternals(t *testing.T) { }, }, false, rawdb.HashScheme) defer triedb.Close() - statedb.SetLogger(tc.tracer.LiveLogger) + statedb.SetLogger(tc.tracer.Hooks) tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ To: &to, Value: big.NewInt(0), @@ -393,7 +393,7 @@ func TestInternals(t *testing.T) { Origin: origin, GasPrice: tx.GasPrice(), } - evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer.LiveLogger}) + evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer.Hooks}) msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 8cf9eae541..afffb80bf8 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -102,7 +102,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer.LiveLogger) + 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) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index a055ba334d..48a95f43c1 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -112,7 +112,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } - statedb.SetLogger(tracer.LiveLogger) + 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) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 3d96253b71..4bac8edfeb 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -214,23 +214,21 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnStart: t.CaptureStart, - OnEnd: t.CaptureEnd, - OnEnter: t.CaptureEnter, - OnExit: t.CaptureExit, - OnOpcode: t.CaptureState, - OnFault: t.CaptureFault, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, }, GetResult: t.GetResult, Stop: t.Stop, }, nil } -// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// OnTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env // Need statedb access for db object db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} @@ -249,9 +247,9 @@ func (t *jsTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, t.ctx["gasPrice"] = gasPriceBig } -// CaptureTxEnd implements the Tracer interface and is invoked at the end of +// OnTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. -func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *jsTracer) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { // Don't override vm error if _, ok := t.ctx["error"]; !ok { @@ -262,8 +260,8 @@ func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) { t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) } -// CaptureStart implements the Tracer interface to initialize the tracing operation. -func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +// onStart implements the Tracer interface to initialize the tracing operation. +func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { cancel := func(err error) { t.err = err t.env.VM.Cancel() @@ -299,8 +297,8 @@ func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create b t.ctx["value"] = valueBig } -// CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +// OnOpcode implements the Tracer interface to trace a single step of VM execution. +func (t *jsTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -324,8 +322,8 @@ func (t *jsTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } } -// CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +// OnFault implements the Tracer interface to trace an execution fault +func (t *jsTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { if t.err != nil { return } @@ -336,15 +334,19 @@ func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, } } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +// onEnd is called after the call finishes to finalize the tracing. +func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool) { if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *jsTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *jsTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if depth == 0 { + t.onStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value) + return + } if !t.traceFrame { return } @@ -367,9 +369,13 @@ func (t *jsTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to comm } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *jsTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + t.onEnd(output, gasUsed, err, reverted) + return + } if !t.traceFrame { return } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index c1546ca055..5893c6844f 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -64,7 +64,7 @@ func testCtx() *vmContext { func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.LiveLogger}) + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 05560cfb24..afb52a9448 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -21,18 +21,16 @@ func init() { // as soon as we have a real live tracer. type noop struct{} -func newNoopTracer(_ json.RawMessage) (*tracing.LiveLogger, error) { +func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { t := &noop{} return &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnStart: t.CaptureStart, - OnEnd: t.CaptureEnd, - OnEnter: t.CaptureEnter, - OnExit: t.CaptureExit, - OnOpcode: t.CaptureState, - OnFault: t.CaptureFault, - OnKeccakPreimage: t.CaptureKeccakPreimage, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnKeccakPreimage: t.OnKeccakPreimage, OnGasChange: t.OnGasChange, OnBlockchainInit: t.OnBlockchainInit, OnBlockStart: t.OnBlockStart, @@ -47,38 +45,24 @@ func newNoopTracer(_ json.RawMessage) (*tracing.LiveLogger, error) { }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noop) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *noop) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *noop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *noop) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noop) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *noop) OnKeccakPreimage(hash common.Hash, data []byte) {} + +func (t *noop) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noop) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { +func (t *noop) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { } -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (t *noop) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *noop) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *noop) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { -} - -func (t *noop) CaptureTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { -} - -func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *noop) OnTxEnd(receipt *types.Receipt, err error) { } func (t *noop) OnBlockStart(ev tracing.BlockEvent) { diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 92df195fe0..4ac49fd91f 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -135,12 +135,12 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi func (a *AccessListTracer) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnOpcode: a.CaptureState, + OnOpcode: a.OnOpcode, } } -// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +// OnOpcode captures all opcodes that touch storage or addresses and adds them to the accesslist. +func (a *AccessListTracer) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stackData := scope.StackData() stackLen := len(stackData) op := vm.OpCode(opcode) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 6e694368b1..c0b66d8c27 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -135,10 +135,10 @@ func NewStructLogger(cfg *Config) *StructLogger { func (l *StructLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: l.CaptureTxStart, - OnTxEnd: l.CaptureTxEnd, - OnEnd: l.CaptureEnd, - OnOpcode: l.CaptureState, + OnTxStart: l.OnTxStart, + OnTxEnd: l.OnTxEnd, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, } } @@ -158,10 +158,10 @@ func (l *StructLogger) Reset() { l.err = nil } -// CaptureState logs a new structured log message and pushes it out to the environment +// OnOpcode logs a new structured log message and pushes it out to the environment // -// CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +// OnOpcode also tracks SLOAD/SSTORE ops to track storage change. +func (l *StructLogger) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -226,8 +226,11 @@ func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost l.logs = append(l.logs, log) } -// CaptureEnd is called after the call finishes to finalize the tracing. -func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +// OnExit is called a call frame finishes processing. +func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth != 0 { + return + } l.output = output l.err = err if l.cfg.Debug { @@ -264,11 +267,11 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } -func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt, err error) { +func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { // Don't override vm error if l.err == nil { @@ -354,19 +357,23 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { func (t *mdLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnStart: t.CaptureStart, - OnOpcode: t.CaptureState, - OnFault: t.CaptureFault, - OnEnd: t.CaptureEnd, + OnTxStart: t.OnTxStart, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, } } -func (t *mdLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env } -func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *mdLogger) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if depth != 0 { + return + } + create := vm.OpCode(typ) == vm.CREATE if !create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", from.String(), to.String(), @@ -383,8 +390,15 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b `) } -// CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", + output, gasUsed, err) + } +} + +// OnOpcode also tracks SLOAD/SSTORE ops to track storage change. +func (t *mdLogger) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) @@ -404,7 +418,7 @@ func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } } -func (t *mdLogger) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +func (t *mdLogger) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 5067fb8a58..6744ac729c 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -47,20 +47,19 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { func (l *JSONLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: l.CaptureTxStart, - OnEnd: l.CaptureEnd, - OnOpcode: l.CaptureState, - OnFault: l.CaptureFault, + OnTxStart: l.OnTxStart, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, } } -func (l *JSONLogger) CaptureFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { +func (l *JSONLogger) OnFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { // TODO: Add rData to this interface as well - l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) + l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err) } -// CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (l *JSONLogger) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { memory := scope.MemoryData() stack := scope.StackData() @@ -86,8 +85,10 @@ func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64 l.encoder.Encode(log) } -// CaptureEnd is triggered at end of execution. -func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +func (l *JSONLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth > 0 { + return + } type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` @@ -100,6 +101,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, revert l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (l *JSONLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index c2982ab036..d3bfc13a03 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -60,8 +60,7 @@ func TestStoreCapture(t *testing.T) { ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash - logger.CaptureTxStart(env.GetVMContext(), nil, common.Address{}) - logger.CaptureStart(common.Address{}, contract.Address(), false, nil, 0, nil) + logger.OnTxStart(env.GetVMContext(), nil, common.Address{}) _, err := env.Interpreter().Run(contract, []byte{}, false) if err != nil { t.Fatal(err) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index a0a4a6ff4f..7add963e16 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -52,7 +52,7 @@ type fourByteTracer struct { ids map[string]int // ids aggregates the 4byte ids found interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on CaptureStart based on given rules + activePrecompiles []common.Address // Updated on tx start based on given rules } // newFourByteTracer returns a native go tracer which collects @@ -63,9 +63,8 @@ func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tr } return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnStart: t.CaptureStart, - OnEnter: t.CaptureEnter, + OnTxStart: t.OnTxStart, + OnEnter: t.OnEnter, }, GetResult: t.GetResult, Stop: t.Stop, @@ -88,22 +87,14 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -func (t *fourByteTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - // Save the outer calldata - if len(input) >= 4 { - t.store(input[0:4], len(input)-4) - } -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *fourByteTracer) CaptureEnter(opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *fourByteTracer) OnEnter(depth int, opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if t.interrupt.Load() { return diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index d42f36666b..07e86ab1f0 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -127,27 +127,12 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac return nil, err } return &directory.Tracer{ -<<<<<<< HEAD - LiveLogger: &tracing.LiveLogger{ - CaptureTxStart: t.CaptureTxStart, - CaptureTxEnd: t.CaptureTxEnd, - CaptureStart: t.CaptureStart, - CaptureEnd: t.CaptureEnd, - CaptureEnter: t.CaptureEnter, - CaptureExit: t.CaptureExit, - CaptureState: t.CaptureState, - OnLog: t.OnLog, -======= Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnStart: t.CaptureStart, - OnEnd: t.CaptureEnd, - OnEnter: t.CaptureEnter, - OnExit: t.CaptureExit, - OnOpcode: t.CaptureState, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, OnLog: t.OnLog, ->>>>>>> 923c180058 (rename Capture hooks to On) }, GetResult: t.GetResult, Stop: t.Stop, @@ -191,10 +176,10 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, revert func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *callTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - t.depth++ - if t.config.OnlyTopCall { +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *callTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.depth = depth + if t.config.OnlyTopCall && depth > 0 { return } // Skip if tracing was interrupted @@ -214,10 +199,15 @@ func (t *callTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to co t.callstack = append(t.callstack, call) } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { - t.depth-- +func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + t.captureEnd(output, gasUsed, err, reverted) + return + } + + t.depth = depth - 1 if t.config.OnlyTopCall { return } @@ -235,11 +225,18 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, rever t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *callTracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) { + if len(t.callstack) != 1 { + return + } + t.callstack[0].processOutput(output, err, reverted) +} + +func (t *callTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.gasLimit = tx.Gas() } -func (t *callTracer) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) { // Error happened during tx validation. if err != nil { return diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index c0ec5c312e..d321278732 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -115,7 +115,7 @@ type flatCallTracer struct { config flatCallTracerConfig ctx *directory.Context // Holds tracer context data reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on CaptureStart based on given rules + activePrecompiles []common.Address // Updated on tx start based on given rules } type flatCallTracerConfig struct { @@ -142,43 +142,19 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: ft.CaptureTxStart, - OnTxEnd: ft.CaptureTxEnd, - OnStart: ft.CaptureStart, - OnEnd: ft.CaptureEnd, - OnEnter: ft.CaptureEnter, - OnExit: ft.CaptureExit, - OnOpcode: ft.CaptureState, - OnFault: ft.CaptureFault, + OnTxStart: ft.OnTxStart, + OnTxEnd: ft.OnTxEnd, + OnEnter: ft.OnEnter, + OnExit: ft.OnExit, }, Stop: ft.Stop, GetResult: ft.GetResult, }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *flatCallTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.tracer.CaptureStart(from, to, create, input, gas, value) -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - t.tracer.CaptureEnd(output, gasUsed, err, reverted) -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { - t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { - t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *flatCallTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - t.tracer.CaptureEnter(typ, from, to, input, gas, value) +// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *flatCallTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.tracer.OnEnter(depth, typ, from, to, input, gas, value) // Child calls must have a value, even if it's zero. // Practically speaking, only STATICCALL has nil value. Set it to zero. @@ -187,10 +163,10 @@ func (t *flatCallTracer) CaptureEnter(typ tracing.OpCode, from common.Address, t } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't +// OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. -func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { - t.tracer.CaptureExit(output, gasUsed, err, reverted) +func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + t.tracer.OnExit(depth, output, gasUsed, err, reverted) // Parity traces don't include CALL/STATICCALLs to precompiles. // By default we remove them from the callstack. @@ -211,15 +187,15 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, r } } -func (t *flatCallTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { - t.tracer.CaptureTxStart(env, tx, from) +func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + t.tracer.OnTxStart(env, tx, from) // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) } -func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt, err error) { - t.tracer.CaptureTxEnd(receipt, err) +func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) { + t.tracer.OnTxEnd(receipt, err) } // GetResult returns an empty json object. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 4516ab1dff..a54b5611af 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -59,15 +59,13 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace t := &muxTracer{names: names, tracers: objects} return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnStart: t.CaptureStart, - OnEnd: t.CaptureEnd, - OnEnter: t.CaptureEnter, - OnExit: t.CaptureExit, - OnOpcode: t.CaptureState, - OnFault: t.CaptureFault, - OnKeccakPreimage: t.CaptureKeccakPreimage, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnKeccakPreimage: t.OnKeccakPreimage, OnGasChange: t.OnGasChange, OnBalanceChange: t.OnBalanceChange, OnNonceChange: t.OnNonceChange, @@ -80,26 +78,7 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - for _, t := range t.tracers { - if t.OnStart != nil { - t.OnStart(from, to, create, input, gas, value) - } - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - for _, t := range t.tracers { - if t.OnEnd != nil { - t.OnEnd(output, gasUsed, err, reverted) - } - } -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *muxTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { for _, t := range t.tracers { if t.OnOpcode != nil { t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) @@ -107,8 +86,7 @@ func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, } } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +func (t *muxTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { for _, t := range t.tracers { if t.OnFault != nil { t.OnFault(pc, op, gas, cost, scope, depth, err) @@ -116,8 +94,7 @@ func (t *muxTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, } } -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { +func (t *muxTracer) OnKeccakPreimage(hash common.Hash, data []byte) { for _, t := range t.tracers { if t.OnKeccakPreimage != nil { t.OnKeccakPreimage(hash, data) @@ -125,7 +102,6 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { } } -// CaptureGasConsumed is called when gas is consumed. func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { for _, t := range t.tracers { if t.OnGasChange != nil { @@ -134,8 +110,7 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) } } -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { if t.OnEnter != nil { t.OnEnter(typ, from, to, input, gas, value) @@ -143,9 +118,7 @@ func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to com } } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { if t.OnExit != nil { t.OnExit(output, gasUsed, err, reverted) @@ -153,7 +126,7 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, revert } } -func (t *muxTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { if t.OnTxStart != nil { t.OnTxStart(env, tx, from) @@ -161,7 +134,7 @@ func (t *muxTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction } } -func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *muxTracer) OnTxEnd(receipt *types.Receipt, err error) { for _, t := range t.tracers { if t.OnTxEnd != nil { t.OnTxEnd(receipt, err) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 5e053236a9..d51780da21 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -90,17 +90,17 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.CaptureTxStart, - OnTxEnd: t.CaptureTxEnd, - OnOpcode: t.CaptureState, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnOpcode: t.OnOpcode, }, GetResult: t.GetResult, Stop: t.Stop, }, nil } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +// OnOpcode implements the EVMLogger interface to trace a single step of VM execution. +func (t *prestateTracer) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if err != nil { return } @@ -146,7 +146,7 @@ func (t *prestateTracer) CaptureState(pc uint64, opcode tracing.OpCode, gas, cos } } -func (t *prestateTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { t.env = env if tx.To() == nil { t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) @@ -160,7 +160,7 @@ func (t *prestateTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transa t.lookupAccount(env.Coinbase) } -func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *prestateTracer) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { return } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 37b89afc51..e39cbf5aae 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -109,7 +109,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.LiveLogger) error { +func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks) error { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} From 7190602bd20830f6a07491700a0e3fb9d2c0dc45 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 6 Mar 2024 16:44:19 +0100 Subject: [PATCH 21/33] rm embedding of noop tracer --- eth/tracers/js/goja.go | 2 -- eth/tracers/logger/access_list_tracer.go | 2 -- eth/tracers/logger/logger.go | 2 -- eth/tracers/logger/logger_json.go | 2 -- eth/tracers/native/4byte.go | 1 - eth/tracers/native/call.go | 1 - eth/tracers/native/call_flat.go | 1 - eth/tracers/native/prestate.go | 1 - 8 files changed, 12 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 4bac8edfeb..9e7c699f40 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -98,8 +98,6 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b // jsTracer is an implementation of the Tracer interface which evaluates // JS functions on the relevant EVM hooks. It uses Goja as its JS engine. type jsTracer struct { - directory.NoopTracer - vm *goja.Runtime env *tracing.VMContext toBig toBigFn // Converts a hex string into a JS bigint diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 4ac49fd91f..f4206d524c 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -21,7 +21,6 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -103,7 +102,6 @@ func (al accessList) accessList() types.AccessList { // AccessListTracer is a tracer that accumulates touched accounts and storage // slots into an internal set. type AccessListTracer struct { - directory.NoopTracer excl map[common.Address]struct{} // Set of account to exclude from the list list accessList // Set of accounts and storage slots touched } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c0b66d8c27..fb4a008ca2 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -108,7 +108,6 @@ func (s *StructLog) ErrorString() string { // a track record of modified storage which is used in reporting snapshots of the // contract their storage. type StructLogger struct { - directory.NoopTracer cfg Config env *tracing.VMContext @@ -339,7 +338,6 @@ func WriteLogs(writer io.Writer, logs []*types.Log) { } type mdLogger struct { - directory.NoopTracer out io.Writer cfg *Config env *tracing.VMContext diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 6744ac729c..a1c81c8856 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -25,11 +25,9 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" ) type JSONLogger struct { - directory.NoopTracer encoder *json.Encoder cfg *Config env *tracing.VMContext diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 7add963e16..e6e9ad0e51 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -48,7 +48,6 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { - directory.NoopTracer ids map[string]int // ids aggregates the 4byte ids found interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 07e86ab1f0..72a07fc854 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -105,7 +105,6 @@ type callFrameMarshaling struct { } type callTracer struct { - directory.NoopTracer callstack []callFrame config callTracerConfig gasLimit uint64 diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index d321278732..e5e83bc2e8 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -110,7 +110,6 @@ type flatCallResultMarshaling struct { // flatCallTracer reports call frame information of a tx in a flat format, i.e. // as opposed to the nested format of `callTracer`. type flatCallTracer struct { - directory.NoopTracer tracer *callTracer config flatCallTracerConfig ctx *directory.Context // Holds tracer context data diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index d51780da21..97b29493a7 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -58,7 +58,6 @@ type accountMarshaling struct { } type prestateTracer struct { - directory.NoopTracer env *tracing.VMContext pre stateMap post stateMap From 5c6fb316b76b1e48c64fba5f16a0bc8a9e584ab9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 6 Mar 2024 17:08:00 +0100 Subject: [PATCH 22/33] rm OnKeccakPreimage # Conflicts: # core/tracing/hooks.go --- core/tracing/hooks.go | 20 +++++++------------- core/vm/instructions.go | 3 --- eth/tracers/directory/noop.go | 27 ++++++++++++--------------- eth/tracers/live/noop.go | 3 --- eth/tracers/native/mux.go | 33 ++++++++++++--------------------- 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 872d4af2dd..ca3d17c1a9 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -116,9 +116,6 @@ type ( // FaultHook is invoked when an error occurs during the execution of an opcode. FaultHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) - // KeccakPreimageHook is invoked on the KECCAK256 opcode to provide the preimage for the hash. - KeccakPreimageHook = func(hash common.Hash, data []byte) - // GasChangeHook is invoked when the gas changes. GasChangeHook = func(old, new uint64, reason GasChangeReason) @@ -166,16 +163,13 @@ type ( type Hooks struct { // VM events - OnTxStart TxStartHook - OnTxEnd TxEndHook - OnStart StartHook - OnEnd EndHook - OnEnter EnterHook - OnExit ExitHook - OnOpcode OpcodeHook - OnFault FaultHook - OnKeccakPreimage KeccakPreimageHook - OnGasChange GasChangeHook + OnTxStart TxStartHook + OnTxEnd TxEndHook + OnEnter EnterHook + OnExit ExitHook + OnOpcode OpcodeHook + OnFault FaultHook + OnGasChange GasChangeHook // Chain events OnBlockchainInit BlockchainInitHook OnBlockStart BlockStartHook diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 0f85f424e5..1a5a29dd43 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -248,9 +248,6 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if evm.Config.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnKeccakPreimage != nil { - interpreter.evm.Config.Tracer.OnKeccakPreimage(common.BytesToHash(interpreter.hasherBuf[:]), data) - } size.SetBytes(interpreter.hasherBuf[:]) return nil, nil } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 551c6635e1..39049dace4 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -38,19 +38,18 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { t := &NoopTracer{} return &Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.OnTxStart, - OnTxEnd: t.OnTxEnd, - OnEnter: t.OnEnter, - OnExit: t.OnExit, - OnOpcode: t.OnOpcode, - OnFault: t.OnFault, - OnKeccakPreimage: t.OnKeccakPreimage, - OnGasChange: t.OnGasChange, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, GetResult: t.GetResult, Stop: t.Stop, @@ -63,8 +62,6 @@ func (t *NoopTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, sc func (t *NoopTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -func (t *NoopTracer) OnKeccakPreimage(hash common.Hash, data []byte) {} - func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} func (t *NoopTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index afb52a9448..31e9ce7e3e 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -30,7 +30,6 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { OnExit: t.OnExit, OnOpcode: t.OnOpcode, OnFault: t.OnFault, - OnKeccakPreimage: t.OnKeccakPreimage, OnGasChange: t.OnGasChange, OnBlockchainInit: t.OnBlockchainInit, OnBlockStart: t.OnBlockStart, @@ -51,8 +50,6 @@ func (t *noop) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tr func (t *noop) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -func (t *noop) OnKeccakPreimage(hash common.Hash, data []byte) {} - func (t *noop) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index a54b5611af..885cc3a830 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -59,19 +59,18 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace t := &muxTracer{names: names, tracers: objects} return &directory.Tracer{ Hooks: &tracing.Hooks{ - OnTxStart: t.OnTxStart, - OnTxEnd: t.OnTxEnd, - OnEnter: t.OnEnter, - OnExit: t.OnExit, - OnOpcode: t.OnOpcode, - OnFault: t.OnFault, - OnKeccakPreimage: t.OnKeccakPreimage, - OnGasChange: t.OnGasChange, - OnBalanceChange: t.OnBalanceChange, - OnNonceChange: t.OnNonceChange, - OnCodeChange: t.OnCodeChange, - OnStorageChange: t.OnStorageChange, - OnLog: t.OnLog, + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, }, GetResult: t.GetResult, Stop: t.Stop, @@ -94,14 +93,6 @@ func (t *muxTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scop } } -func (t *muxTracer) OnKeccakPreimage(hash common.Hash, data []byte) { - for _, t := range t.tracers { - if t.OnKeccakPreimage != nil { - t.OnKeccakPreimage(hash, data) - } - } -} - func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { for _, t := range t.tracers { if t.OnGasChange != nil { From ea02c9ebc2e211027105a6847ed4508df716096c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 6 Mar 2024 18:42:18 +0100 Subject: [PATCH 23/33] fix eth config --- cmd/geth/config.go | 17 ----------------- cmd/utils/flags.go | 12 ++++++++++++ eth/backend.go | 10 +++++++++- eth/ethconfig/config.go | 4 ++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 95d59a04fa..2f49c486f9 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -18,7 +18,6 @@ package main import ( "bufio" - "encoding/json" "errors" "fmt" "os" @@ -38,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/version" @@ -181,21 +179,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { cfg.Eth.OverrideVerkle = &v } - if ctx.IsSet(utils.VMTraceFlag.Name) { - if name := ctx.String(utils.VMTraceFlag.Name); name != "" { - var config string - if ctx.IsSet(utils.VMTraceConfigFlag.Name) { - config = ctx.String(utils.VMTraceConfigFlag.Name) - } - t, err := live.Directory.New(name, json.RawMessage(config)) - if err != nil { - utils.Fatalf("Failed to create tracer %q: %v", name, err) - } - - cfg.Eth.VMTracer = t - } - } - backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Create gauge with geth system and build information diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 2490e79fe5..41f782ed4f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1900,6 +1900,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) } + // VM tracing config. + if ctx.IsSet(VMTraceFlag.Name) { + if name := ctx.String(VMTraceFlag.Name); name != "" { + var config string + if ctx.IsSet(VMTraceConfigFlag.Name) { + config = ctx.String(VMTraceConfigFlag.Name) + } + + cfg.VMTrace = name + cfg.VMTraceConfig = config + } + } } // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if diff --git a/eth/backend.go b/eth/backend.go index 1ba7552d76..29af07cc56 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -18,6 +18,7 @@ package eth import ( + "encoding/json" "errors" "fmt" "math/big" @@ -44,6 +45,7 @@ import ( "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -192,7 +194,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, - Tracer: config.VMTracer, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, @@ -206,6 +207,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { StateScheme: scheme, } ) + if config.VMTrace != "" { + t, err := live.Directory.New(config.VMTrace, json.RawMessage(config.VMTraceConfig)) + if err != nil { + return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) + } + vmConfig.Tracer = t + } // Override the chain config with provided settings. var overrides core.ChainOverrides if config.OverrideCancun != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 33ee536f88..27754f7c15 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" @@ -153,7 +152,8 @@ type Config struct { EnablePreimageRecording bool // Enables VM tracing - VMTracer *tracing.Hooks + VMTrace string + VMTraceConfig string // Miscellaneous options DocRoot string `toml:"-"` From 94fc0b4a9edfe62a735c988cb1bd41afe997bbab Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 7 Mar 2024 10:30:13 +0100 Subject: [PATCH 24/33] replace opcode with byte # Conflicts: # core/tracing/hooks.go # core/vm/evm.go # core/vm/instructions.go # eth/tracers/js/tracer_test.go --- core/tracing/hooks.go | 29 +++++++----------------- core/vm/evm.go | 17 +++----------- core/vm/instructions.go | 4 ++-- core/vm/interpreter.go | 8 +++---- eth/tracers/directory/noop.go | 6 ++--- eth/tracers/js/goja.go | 6 ++--- eth/tracers/js/tracer_test.go | 13 +++++------ eth/tracers/live/noop.go | 6 ++--- eth/tracers/logger/access_list_tracer.go | 2 +- eth/tracers/logger/logger.go | 8 +++---- eth/tracers/logger/logger_json.go | 4 ++-- eth/tracers/native/4byte.go | 2 +- eth/tracers/native/call.go | 2 +- eth/tracers/native/call_flat.go | 2 +- eth/tracers/native/mux.go | 6 ++--- eth/tracers/native/prestate.go | 2 +- 16 files changed, 46 insertions(+), 71 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index ca3d17c1a9..b262b0aed7 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -20,26 +20,24 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - "github.com/holiman/uint256" ) // OpContext provides the context at which the opcode is being // executed in, including the memory, stack and various contract-level information. type OpContext interface { MemoryData() []byte - StackData() []uint256.Int + StackData() []big.Int Caller() common.Address Address() common.Address - CallValue() *uint256.Int + CallValue() *big.Int CallInput() []byte } // StateDB gives tracers access to the whole state. type StateDB interface { - GetBalance(common.Address) *uint256.Int + GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 GetCode(common.Address) []byte GetState(common.Address, common.Hash) common.Hash @@ -75,10 +73,6 @@ type BlockEvent struct { Safe *types.Header } -// OpCode is an EVM opcode -// TODO: provide utils for consumers -type OpCode byte - type ( /* - VM events - @@ -92,15 +86,8 @@ type ( // TxEndHook is called after the execution of a transaction ends. TxEndHook = func(receipt *types.Receipt, err error) - // StartHook is invoked when the processing of the root call starts. - StartHook = func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - - // EndHook is invoked when the processing of the top call ends. - // See docs for `ExitHook` for info on the `reverted` parameter. - EndHook = func(output []byte, gasUsed uint64, err error, reverted bool) - // EnterHook is invoked when the processing of a message starts. - EnterHook = func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) + EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) // ExitHook is invoked when the processing of a message ends. // `revert` is true when there was an error during the execution. @@ -108,13 +95,13 @@ type ( // ran out of gas when attempting to persist the code to database did not // count as a call failure and did not cause a revert of the call. This will // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. - ExitHook = func(output []byte, gasUsed uint64, err error, reverted bool) + ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool) // OpcodeHook is invoked just prior to the execution of an opcode. - OpcodeHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) // FaultHook is invoked when an error occurs during the execution of an opcode. - FaultHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, depth int, err error) + FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error) // GasChangeHook is invoked when the gas changes. GasChangeHook = func(old, new uint64, reason GasChangeReason) @@ -139,7 +126,7 @@ type ( SkippedBlockHook = func(event BlockEvent) // GenesisBlockHook is called when the genesis block is being processed. - GenesisBlockHook = func(genesis *types.Block, alloc core.GenesisAlloc) + GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) /* - State events - diff --git a/core/vm/evm.go b/core/vm/evm.go index ba314b51da..8baa69adfa 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -520,13 +520,8 @@ func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { tracer := evm.Config.Tracer - - if isRoot { - if tracer.OnStart != nil { - tracer.OnStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value) - } - } else if tracer.OnEnter != nil { - tracer.OnEnter(tracing.OpCode(typ), from, to, input, startGas, value) + if tracer.OnEnter != nil { + tracer.OnEnter(0, byte(typ), from, to, input, startGas, value) } if tracer.OnGasChange != nil { @@ -547,13 +542,7 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { reverted = false } - if isRoot { - if tracer.OnEnd != nil { - tracer.OnEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) - } - } else if tracer.OnExit != nil { - tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) - } + tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } func (evm *EVM) GetVMContext() *tracing.VMContext { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1a5a29dd43..ddf5e7374b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -856,7 +856,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.OnExit != nil { tracer.OnExit([]byte{}, 0, nil, false) @@ -876,7 +876,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer.OnEnter != nil { - tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.OnExit != nil { tracer.OnExit([]byte{}, 0, nil, false) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index bee43ac1cd..47d75a89c9 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -191,10 +191,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if err != nil { if !logged { if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) } } else if in.evm.Config.Tracer.OnFault != nil { - in.evm.Config.Tracer.OnFault(pcCopy, tracing.OpCode(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } } }() @@ -256,7 +256,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } @@ -268,7 +268,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, tracing.OpCode(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 39049dace4..d0edf12e21 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -56,15 +56,15 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { }, nil } -func (t *NoopTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *NoopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -func (t *NoopTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { +func (t *NoopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} -func (t *NoopTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } func (t *NoopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 9e7c699f40..458b99f525 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -296,7 +296,7 @@ func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, } // OnOpcode implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *jsTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -321,7 +321,7 @@ func (t *jsTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scop } // OnFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +func (t *jsTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { if t.err != nil { return } @@ -340,7 +340,7 @@ func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *jsTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { if depth == 0 { t.onStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value) return diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 5893c6844f..9ca6363250 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/directory" @@ -76,7 +75,7 @@ func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.Chain } tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) - tracer.OnStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value) + tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.OnEnd(ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund @@ -187,7 +186,7 @@ func TestHaltBetweenSteps(t *testing.T) { } env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) - tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) + tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0)) tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") tracer.Stop(timeout) @@ -209,8 +208,8 @@ func TestNoStepExec(t *testing.T) { } env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks}) tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) - tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) - tracer.OnEnd(nil, 0, nil, false) + tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0)) + tracer.OnExit(0, nil, 0, nil, false) ret, err := tracer.GetResult() if err != nil { t.Fatal(err) @@ -279,8 +278,8 @@ func TestEnterExit(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - tracer.OnEnter(tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) - tracer.OnExit([]byte{}, 400, nil, false) + tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) + tracer.OnExit(1, []byte{}, 400, nil, false) have, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 31e9ce7e3e..2236674201 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -44,13 +44,13 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { }, nil } -func (t *noop) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *noop) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -func (t *noop) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tracing.OpContext, depth int, err error) { +func (t *noop) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -func (t *noop) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *noop) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } func (t *noop) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index f4206d524c..fc7713b245 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -138,7 +138,7 @@ func (a *AccessListTracer) Hooks() *tracing.Hooks { } // OnOpcode captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (a *AccessListTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stackData := scope.StackData() stackLen := len(stackData) op := vm.OpCode(opcode) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index fb4a008ca2..791a3db2eb 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -160,7 +160,7 @@ func (l *StructLogger) Reset() { // OnOpcode logs a new structured log message and pushes it out to the environment // // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -367,7 +367,7 @@ func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.env = env } -func (t *mdLogger) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { if depth != 0 { return } @@ -396,7 +396,7 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r } // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) @@ -416,7 +416,7 @@ func (t *mdLogger) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scop } } -func (t *mdLogger) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index a1c81c8856..e9a4508969 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -52,12 +52,12 @@ func (l *JSONLogger) Hooks() *tracing.Hooks { } } -func (l *JSONLogger) OnFault(pc uint64, op tracing.OpCode, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { +func (l *JSONLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { // TODO: Add rData to this interface as well l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err) } -func (l *JSONLogger) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (l *JSONLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { memory := scope.MemoryData() stack := scope.StackData() diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index e6e9ad0e51..550b0115a3 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -93,7 +93,7 @@ func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *fourByteTracer) OnEnter(depth int, opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) OnEnter(depth int, opcode byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if t.interrupt.Load() { return diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 72a07fc854..d671d3d364 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -176,7 +176,7 @@ func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64 } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *callTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.depth = depth if t.config.OnlyTopCall && depth > 0 { return diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index e5e83bc2e8..47d388d312 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -152,7 +152,7 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *flatCallTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.tracer.OnEnter(depth, typ, from, to, input, gas, value) // Child calls must have a value, even if it's zero. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 885cc3a830..5274113518 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -77,7 +77,7 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace }, nil } -func (t *muxTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { for _, t := range t.tracers { if t.OnOpcode != nil { t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) @@ -85,7 +85,7 @@ func (t *muxTracer) OnOpcode(pc uint64, op tracing.OpCode, gas, cost uint64, sco } } -func (t *muxTracer) OnFault(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, depth int, err error) { +func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { for _, t := range t.tracers { if t.OnFault != nil { t.OnFault(pc, op, gas, cost, scope, depth, err) @@ -101,7 +101,7 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) } } -func (t *muxTracer) OnEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { if t.OnEnter != nil { t.OnEnter(typ, from, to, input, gas, value) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 97b29493a7..e90a1729bb 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -99,7 +99,7 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } // OnOpcode implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) OnOpcode(pc uint64, opcode tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { if err != nil { return } From a476051c48daa26f43e4dfcceb099a760deae993 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 7 Mar 2024 12:15:57 +0100 Subject: [PATCH 25/33] add fn refundGas --- core/vm/contract.go | 11 +++++++++++ core/vm/instructions.go | 36 ++++++------------------------------ 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index 860d0f2467..8a927777b6 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -171,6 +171,17 @@ func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasC return true } +// RefundGas refunds gas to the contract +func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) { + if gas == 0 { + return + } + if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { + logger.OnGasChange(c.Gas, c.Gas+gas, reason) + } + c.Gas += gas +} + // Address returns the contracts address func (c *Contract) Address() common.Address { return c.self.Address() diff --git a/core/vm/instructions.go b/core/vm/instructions.go index ddf5e7374b..0b9ea37e9d 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -612,11 +612,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } scope.Stack.push(&stackvalue) - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -657,11 +653,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] } scope.Stack.push(&stackvalue) - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -707,11 +699,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -747,11 +735,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -780,11 +764,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -813,11 +793,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - if interpreter.evm.Config.Tracer != nil && interpreter.evm.Config.Tracer.OnGasChange != nil && returnGas > 0 { - interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, tracing.GasChangeCallLeftOverRefunded) - } - - scope.Contract.Gas += returnGas + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil From d0a86c45b54663f62771d48200c2be2a2f822785 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 7 Mar 2024 13:08:27 +0100 Subject: [PATCH 26/33] rm canceler --- core/tracing/hooks.go | 7 ------- core/vm/evm.go | 1 - eth/tracers/js/goja.go | 35 +++++++++++++++++++++-------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index b262b0aed7..df1da15f87 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -45,12 +45,6 @@ type StateDB interface { GetRefund() uint64 } -// Canceler is an interface that wraps the Cancel method. -// It allows loggers to cancel EVM processing. -type Canceler interface { - Cancel() -} - // VMContext provides the context for the EVM execution. type VMContext struct { Coinbase common.Address @@ -61,7 +55,6 @@ type VMContext struct { GasPrice *big.Int ChainConfig *params.ChainConfig StateDB StateDB - VM Canceler } // BlockEvent is emitted upon tracing an incoming block. diff --git a/core/vm/evm.go b/core/vm/evm.go index 8baa69adfa..099ee6c877 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -554,6 +554,5 @@ func (evm *EVM) GetVMContext() *tracing.VMContext { GasPrice: evm.TxContext.GasPrice, ChainConfig: evm.ChainConfig(), StateDB: evm.StateDB, - VM: evm, } } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 458b99f525..86454d376a 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -239,7 +239,6 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) if err != nil { t.err = err - t.env.VM.Cancel() return } t.ctx["gasPrice"] = gasPriceBig @@ -248,6 +247,9 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from // OnTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. func (t *jsTracer) OnTxEnd(receipt *types.Receipt, err error) { + if t.err != nil { + return + } if err != nil { // Don't override vm error if _, ok := t.ctx["error"]; !ok { @@ -260,9 +262,8 @@ func (t *jsTracer) OnTxEnd(receipt *types.Receipt, err error) { // onStart implements the Tracer interface to initialize the tracing operation. func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - cancel := func(err error) { - t.err = err - t.env.VM.Cancel() + if t.err != nil { + return } if create { t.ctx["type"] = t.vm.ToValue("CREATE") @@ -271,19 +272,19 @@ func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, } fromVal, err := t.toBuf(t.vm, from.Bytes()) if err != nil { - cancel(err) + t.err = err return } t.ctx["from"] = fromVal toVal, err := t.toBuf(t.vm, to.Bytes()) if err != nil { - cancel(err) + t.err = err return } t.ctx["to"] = toVal inputVal, err := t.toBuf(t.vm, input) if err != nil { - cancel(err) + t.err = err return } t.ctx["input"] = inputVal @@ -334,6 +335,9 @@ func (t *jsTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O // onEnd is called after the call finishes to finalize the tracing. func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool) { + if t.err != nil { + return + } if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } @@ -341,6 +345,9 @@ func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.err != nil { + return + } if depth == 0 { t.onStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value) return @@ -348,9 +355,6 @@ func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.A if !t.traceFrame { return } - if t.err != nil { - return - } t.frame.typ = vm.OpCode(typ).String() t.frame.from = from @@ -370,6 +374,9 @@ func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.A // OnExit is called when EVM exits a scope, even if the scope didn't // execute any code. func (t *jsTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.err != nil { + return + } if depth == 0 { t.onEnd(output, gasUsed, err, reverted) return @@ -389,6 +396,9 @@ func (t *jsTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, r // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error func (t *jsTracer) GetResult() (json.RawMessage, error) { + if t.err != nil { + return nil, t.err + } ctx := t.vm.ToValue(t.ctx) res, err := t.result(t.obj, ctx, t.dbValue) if err != nil { @@ -398,7 +408,7 @@ func (t *jsTracer) GetResult() (json.RawMessage, error) { if err != nil { return nil, err } - return json.RawMessage(encoded), t.err + return encoded, t.err } // Stop terminates execution of the tracer at the first opportune moment. @@ -411,9 +421,6 @@ func (t *jsTracer) Stop(err error) { // execution. func (t *jsTracer) onError(context string, err error) { t.err = wrapError(context, err) - // `env` is set on OnStart which comes before any JS execution. - // So it should be non-nil. - t.env.VM.Cancel() } func wrapError(context string, err error) error { From 77486e91fb8ee551cc58dee7b3acc77d460bc53c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Mar 2024 12:45:22 +0100 Subject: [PATCH 27/33] fix lint issue --- core/vm/evm.go | 2 ++ eth/tracers/logger/logger.go | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 099ee6c877..cb7c1dad18 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -545,6 +545,8 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } +// GetVMContext provides context about the block being executed as well as state +// to the tracers. func (evm *EVM) GetVMContext() *tracing.VMContext { return &tracing.VMContext{ Coinbase: evm.Context.Coinbase, diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 791a3db2eb..7e2e7aeff8 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -183,9 +183,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope var stck []uint256.Int if !l.cfg.DisableStack { stck = make([]uint256.Int, len(stack)) - for i, item := range stack { - stck[i] = item - } + copy(stck, stack) } contractAddr := scope.Address() stackLen := len(stack) From 77a701cca49f239379ff86b35dcc8c4a50bd18a1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Mar 2024 18:01:08 +0100 Subject: [PATCH 28/33] rm extra param # Conflicts: # core/vm/evm.go --- core/vm/evm.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index cb7c1dad18..aafc577787 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -183,7 +183,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if evm.Config.Tracer != nil { evm.captureBegin(evm.depth == 0, CALL, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { - evm.captureEnd(evm.depth == 0, CALL, startGas, leftOverGas, ret, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -255,7 +255,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if evm.Config.Tracer != nil { evm.captureBegin(false, CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { - evm.captureEnd(false, CALLCODE, startGas, leftOverGas, ret, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -310,7 +310,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // DELEGATECALL inherits value from parent call evm.captureBegin(false, DELEGATECALL, caller.Address(), addr, input, gas, parent.value) defer func(startGas uint64) { - evm.captureEnd(false, DELEGATECALL, startGas, leftOverGas, ret, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -351,7 +351,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if evm.Config.Tracer != nil { evm.captureBegin(false, STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { - evm.captureEnd(false, STATICCALL, startGas, leftOverGas, ret, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -418,7 +418,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Tracer != nil { evm.captureBegin(evm.depth == 0, typ, caller.Address(), address, codeAndHash.code, gas, value) defer func(startGas uint64) { - evm.captureEnd(evm.depth == 0, typ, startGas, leftOverGas, ret, err) + evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } // Depth check execution. Fail if we're trying to execute above the @@ -529,7 +529,7 @@ func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to co } } -func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas uint64, ret []byte, err error) { +func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { tracer := evm.Config.Tracer if leftOverGas != 0 && tracer.OnGasChange != nil { @@ -542,7 +542,7 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { reverted = false } - tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } // GetVMContext provides context about the block being executed as well as state From 177074432db847c78081f61618f7e6e6ed390683 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Thu, 14 Mar 2024 08:58:51 -0400 Subject: [PATCH 29/33] Call `OnBlockchainInit` before `OnGenesisBlock` (#22) # Conflicts: # core/blockchain.go --- core/blockchain.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index cc88434e8f..ee230123cd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -437,6 +437,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } + if bc.logger != nil && bc.logger.OnBlockchainInit != nil { + bc.logger.OnBlockchainInit(chainConfig) + } + if bc.logger != nil && bc.logger.OnGenesisBlock != nil { if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { alloc, err := getGenesisState(bc.db, block.Hash()) @@ -488,10 +492,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } - if bc.logger != nil && bc.logger.OnBlockchainInit != nil { - bc.logger.OnBlockchainInit(chainConfig) - } - // Start tx indexer/unindexer if required. + + // Start tx indexer if it's enabled. if txLookupLimit != nil { bc.txLookupLimit = *txLookupLimit From 28a80d617f42ebce4f437a0c959be588136fc0c9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 14 Mar 2024 14:07:19 +0100 Subject: [PATCH 30/33] fix empty tracer config --- cmd/utils/flags.go | 6 +++--- eth/backend.go | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 41f782ed4f..928dd2cb9d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2211,11 +2211,11 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { - var config string + var config json.RawMessage if ctx.IsSet(VMTraceConfigFlag.Name) { - config = ctx.String(VMTraceConfigFlag.Name) + config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name)) } - t, err := live.Directory.New(name, json.RawMessage(config)) + t, err := live.Directory.New(name, config) if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/eth/backend.go b/eth/backend.go index 29af07cc56..746266cd10 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -208,7 +208,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } ) if config.VMTrace != "" { - t, err := live.Directory.New(config.VMTrace, json.RawMessage(config.VMTraceConfig)) + var traceConfig json.RawMessage + if config.VMTraceConfig != "" { + traceConfig = json.RawMessage(config.VMTraceConfig) + } + t, err := live.Directory.New(config.VMTrace, traceConfig) if err != nil { return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) } From 3834f135a96e9e167bdb999a79d11f35fdd6e392 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Thu, 14 Mar 2024 16:53:22 -0400 Subject: [PATCH 31/33] Series of changes to get backport to 1.13.5 working --- accounts/abi/bind/backends/simulated.go | 3 +- cmd/evm/internal/t8ntool/transition.go | 4 +- cmd/geth/snapshot.go | 9 +- core/genesis.go | 68 +++------------ core/genesis_test.go | 2 +- core/state/dump.go | 24 +++-- core/state/state_object.go | 2 +- core/state/statedb.go | 6 +- core/tracing/hooks.go | 3 +- core/types/account.go | 87 +++++++++++++++++++ .../gen_account.go} | 44 +++++----- core/vm/instructions.go | 4 +- core/vm/interpreter.go | 4 +- eth/tracers/js/tracer_test.go | 2 +- eth/tracers/native/call.go | 34 ++------ eth/tracers/native/mux.go | 4 +- light/odr_test.go | 3 +- 17 files changed, 161 insertions(+), 142 deletions(-) create mode 100644 core/types/account.go rename core/{gen_genesis_account.go => types/gen_account.go} (61%) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 3bb0e8651b..3fc346fc68 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/filters" @@ -681,7 +682,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // Set infinite balance to the fake caller account. from := stateDB.GetOrNewStateObject(call.From) - from.SetBalance(math.MaxBig256, state.BalanceChangeUnspecified) + from.SetBalance(math.MaxBig256, tracing.BalanceChangeUnspecified) // Execute the call. msg := &core.Message{ diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index bb28620b01..2600a6759e 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -186,9 +186,7 @@ func Transition(ctx *cli.Context) error { } prestate.Env = *inputData.Env - vmConfig := vm.Config{ - Tracer: tracer, - } + vmConfig := vm.Config{} // Construct the chainconfig var chainConfig *params.ChainConfig if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 25c6311c4c..d30d394d9f 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -568,11 +568,10 @@ func dumpState(ctx *cli.Context) error { return err } da := &state.DumpAccount{ - Balance: account.Balance.String(), - Nonce: account.Nonce, - Root: account.Root.Bytes(), - CodeHash: account.CodeHash, - SecureKey: accIt.Hash().Bytes(), + Balance: account.Balance.String(), + Nonce: account.Nonce, + Root: account.Root.Bytes(), + CodeHash: account.CodeHash, } if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash)) diff --git a/core/genesis.go b/core/genesis.go index 16f8ec83a1..a6c51f3c20 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -18,7 +18,6 @@ package core import ( "bytes" - "encoding/hex" "encoding/json" "errors" "fmt" @@ -41,7 +40,6 @@ import ( ) //go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go -//go:generate go run github.com/fjl/gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go var errGenesisNoConfig = errors.New("genesis has no chain configuration") @@ -106,23 +104,14 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { return &genesis, nil } -// GenesisAlloc specifies the initial state that is part of the genesis block. -type GenesisAlloc map[common.Address]GenesisAccount +// Deprecated: use types.GenesisAccount instead. +type GenesisAccount = types.Account -func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { - m := make(map[common.UnprefixedAddress]GenesisAccount) - if err := json.Unmarshal(data, &m); err != nil { - return err - } - *ga = make(GenesisAlloc) - for addr, a := range m { - (*ga)[common.Address(addr)] = a - } - return nil -} +// Deprecated: use types.GenesisAlloc instead. +type GenesisAlloc = types.GenesisAlloc -// hash computes the state root according to the genesis specification. -func (ga *GenesisAlloc) hash() (common.Hash, error) { +// hashAlloc computes the state root according to the genesis specification. +func hashAlloc(ga *types.GenesisAlloc) (common.Hash, error) { // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. db := state.NewDatabase(rawdb.NewMemoryDatabase()) @@ -143,10 +132,10 @@ func (ga *GenesisAlloc) hash() (common.Hash, error) { return statedb.Commit(0, false) } -// flush is very similar with hash, but the main difference is all the generated +// flushAlloc is very similar with hash, but the main difference is all the generated // states will be persisted into the given database. Also, the genesis state // specification will be flushed as well. -func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { +func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { return err @@ -215,15 +204,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc GenesisAll return nil, nil } -// GenesisAccount is an account in the state of the genesis block. -type GenesisAccount struct { - Code []byte `json:"code,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` - Balance *big.Int `json:"balance" gencodec:"required"` - Nonce uint64 `json:"nonce,omitempty"` - PrivateKey []byte `json:"secretKey,omitempty"` // for tests -} - // field type overrides for gencodec type genesisSpecMarshaling struct { Nonce math.HexOrDecimal64 @@ -239,34 +219,6 @@ type genesisSpecMarshaling struct { BlobGasUsed *math.HexOrDecimal64 } -type genesisAccountMarshaling struct { - Code hexutil.Bytes - Balance *math.HexOrDecimal256 - Nonce math.HexOrDecimal64 - Storage map[storageJSON]storageJSON - PrivateKey hexutil.Bytes -} - -// storageJSON represents a 256 bit byte array, but allows less than 256 bits when -// unmarshaling from hex. -type storageJSON common.Hash - -func (h *storageJSON) UnmarshalText(text []byte) error { - text = bytes.TrimPrefix(text, []byte("0x")) - if len(text) > 64 { - return fmt.Errorf("too many hex characters in storage key/value %q", text) - } - offset := len(h) - len(text)/2 // pad on the left - if _, err := hex.Decode(h[offset:], text); err != nil { - return fmt.Errorf("invalid hex storage key/value %q", text) - } - return nil -} - -func (h storageJSON) MarshalText() ([]byte, error) { - return hexutil.Bytes(h[:]).MarshalText() -} - // GenesisMismatchError is raised when trying to overwrite an existing // genesis block with an incompatible one. type GenesisMismatchError struct { @@ -449,7 +401,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { // ToBlock returns the genesis block according to genesis specification. func (g *Genesis) ToBlock() *types.Block { - root, err := g.Alloc.hash() + root, err := hashAlloc(&g.Alloc) if err != nil { panic(err) } @@ -526,7 +478,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided // database. - if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil { + if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) diff --git a/core/genesis_test.go b/core/genesis_test.go index fac88ff373..2a7eedf40d 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -231,7 +231,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) { {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, {2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}}, } - hash, _ = alloc.hash() + hash, _ = hashAlloc(alloc) ) blob, _ := json.Marshal(alloc) rawdb.WriteGenesisStateSpec(db, hash, blob) diff --git a/core/state/dump.go b/core/state/dump.go index 1840e5b220..d3a7b1170e 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -104,14 +104,13 @@ type iterativeDump struct { // OnAccount implements DumpCollector interface func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { dumpAccount := &DumpAccount{ - Balance: account.Balance, - Nonce: account.Nonce, - Root: account.Root, - CodeHash: account.CodeHash, - Code: account.Code, - Storage: account.Storage, - SecureKey: account.SecureKey, - Address: addr, + Balance: account.Balance, + Nonce: account.Nonce, + Root: account.Root, + CodeHash: account.CodeHash, + Code: account.Code, + Storage: account.Storage, + Address: addr, } d.Encode(dumpAccount) } @@ -150,11 +149,10 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] panic(err) } account := DumpAccount{ - Balance: data.Balance.String(), - Nonce: data.Nonce, - Root: data.Root[:], - CodeHash: data.CodeHash, - SecureKey: it.Key, + Balance: data.Balance.String(), + Nonce: data.Nonce, + Root: data.Root[:], + CodeHash: data.CodeHash, } var ( addrBytes = s.trie.GetKey(it.Key) diff --git a/core/state/state_object.go b/core/state/state_object.go index cd718ae058..250c549f3a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -420,7 +420,7 @@ func (s *stateObject) AddBalance(amount *big.Int, reason tracing.BalanceChangeRe // SubBalance removes amount from s's balance. // It is used to remove funds from the origin account of a transfer. func (s *stateObject) SubBalance(amount *big.Int, reason tracing.BalanceChangeReason) { - if amount.IsZero() { + if amount.Sign() == 0 { return } s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason) diff --git a/core/state/statedb.go b/core/state/statedb.go index 054f022708..22516af322 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -384,7 +384,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool { // AddBalance adds amount to the account associated with addr. func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { - stateObject := s.getOrNewStateObject(addr) + stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount, reason) } @@ -392,14 +392,14 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracin // SubBalance subtracts amount from the account associated with addr. func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { - stateObject := s.getOrNewStateObject(addr) + stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { stateObject.SubBalance(amount, reason) } } func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) { - stateObject := s.getOrNewStateObject(addr) + stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { stateObject.SetBalance(amount, reason) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index df1da15f87..a2041f50a0 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -22,13 +22,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" ) // OpContext provides the context at which the opcode is being // executed in, including the memory, stack and various contract-level information. type OpContext interface { MemoryData() []byte - StackData() []big.Int + StackData() []uint256.Int Caller() common.Address Address() common.Address CallValue() *big.Int diff --git a/core/types/account.go b/core/types/account.go new file mode 100644 index 0000000000..bb0f4ca02e --- /dev/null +++ b/core/types/account.go @@ -0,0 +1,87 @@ +// 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 . + +package types + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" +) + +//go:generate go run github.com/fjl/gencodec -type Account -field-override accountMarshaling -out gen_account.go + +// Account represents an Ethereum account and its attached data. +// This type is used to specify accounts in the genesis block state, and +// is also useful for JSON encoding/decoding of accounts. +type Account struct { + Code []byte `json:"code,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *big.Int `json:"balance" gencodec:"required"` + Nonce uint64 `json:"nonce,omitempty"` + + // used in tests + PrivateKey []byte `json:"secretKey,omitempty"` +} + +type accountMarshaling struct { + Code hexutil.Bytes + Balance *math.HexOrDecimal256 + Nonce math.HexOrDecimal64 + Storage map[storageJSON]storageJSON + PrivateKey hexutil.Bytes +} + +// storageJSON represents a 256 bit byte array, but allows less than 256 bits when +// unmarshaling from hex. +type storageJSON common.Hash + +func (h *storageJSON) UnmarshalText(text []byte) error { + text = bytes.TrimPrefix(text, []byte("0x")) + if len(text) > 64 { + return fmt.Errorf("too many hex characters in storage key/value %q", text) + } + offset := len(h) - len(text)/2 // pad on the left + if _, err := hex.Decode(h[offset:], text); err != nil { + return fmt.Errorf("invalid hex storage key/value %q", text) + } + return nil +} + +func (h storageJSON) MarshalText() ([]byte, error) { + return hexutil.Bytes(h[:]).MarshalText() +} + +// GenesisAlloc specifies the initial state of a genesis block. +type GenesisAlloc map[common.Address]Account + +func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { + m := make(map[common.UnprefixedAddress]Account) + if err := json.Unmarshal(data, &m); err != nil { + return err + } + *ga = make(GenesisAlloc) + for addr, a := range m { + (*ga)[common.Address(addr)] = a + } + return nil +} diff --git a/core/gen_genesis_account.go b/core/types/gen_account.go similarity index 61% rename from core/gen_genesis_account.go rename to core/types/gen_account.go index a9d47e6ba3..4e475896a7 100644 --- a/core/gen_genesis_account.go +++ b/core/types/gen_account.go @@ -1,6 +1,6 @@ // Code generated by github.com/fjl/gencodec. DO NOT EDIT. -package core +package types import ( "encoding/json" @@ -12,62 +12,62 @@ import ( "github.com/ethereum/go-ethereum/common/math" ) -var _ = (*genesisAccountMarshaling)(nil) +var _ = (*accountMarshaling)(nil) // MarshalJSON marshals as JSON. -func (g GenesisAccount) MarshalJSON() ([]byte, error) { - type GenesisAccount struct { +func (a Account) MarshalJSON() ([]byte, error) { + type Account struct { Code hexutil.Bytes `json:"code,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` Nonce math.HexOrDecimal64 `json:"nonce,omitempty"` PrivateKey hexutil.Bytes `json:"secretKey,omitempty"` } - var enc GenesisAccount - enc.Code = g.Code - if g.Storage != nil { - enc.Storage = make(map[storageJSON]storageJSON, len(g.Storage)) - for k, v := range g.Storage { + var enc Account + enc.Code = a.Code + if a.Storage != nil { + enc.Storage = make(map[storageJSON]storageJSON, len(a.Storage)) + for k, v := range a.Storage { enc.Storage[storageJSON(k)] = storageJSON(v) } } - enc.Balance = (*math.HexOrDecimal256)(g.Balance) - enc.Nonce = math.HexOrDecimal64(g.Nonce) - enc.PrivateKey = g.PrivateKey + enc.Balance = (*math.HexOrDecimal256)(a.Balance) + enc.Nonce = math.HexOrDecimal64(a.Nonce) + enc.PrivateKey = a.PrivateKey return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (g *GenesisAccount) UnmarshalJSON(input []byte) error { - type GenesisAccount struct { +func (a *Account) UnmarshalJSON(input []byte) error { + type Account struct { Code *hexutil.Bytes `json:"code,omitempty"` Storage map[storageJSON]storageJSON `json:"storage,omitempty"` Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"` Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"` PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"` } - var dec GenesisAccount + var dec Account if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.Code != nil { - g.Code = *dec.Code + a.Code = *dec.Code } if dec.Storage != nil { - g.Storage = make(map[common.Hash]common.Hash, len(dec.Storage)) + a.Storage = make(map[common.Hash]common.Hash, len(dec.Storage)) for k, v := range dec.Storage { - g.Storage[common.Hash(k)] = common.Hash(v) + a.Storage[common.Hash(k)] = common.Hash(v) } } if dec.Balance == nil { - return errors.New("missing required field 'balance' for GenesisAccount") + return errors.New("missing required field 'balance' for Account") } - g.Balance = (*big.Int)(dec.Balance) + a.Balance = (*big.Int)(dec.Balance) if dec.Nonce != nil { - g.Nonce = uint64(*dec.Nonce) + a.Nonce = uint64(*dec.Nonce) } if dec.PrivateKey != nil { - g.PrivateKey = *dec.PrivateKey + a.PrivateKey = *dec.PrivateKey } return nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 0b9ea37e9d..673908f44f 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -835,7 +835,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.OnExit != nil { - tracer.OnExit([]byte{}, 0, nil, false) + tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken @@ -855,7 +855,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) } if tracer.OnExit != nil { - tracer.OnExit([]byte{}, 0, nil, false) + tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) } } return nil, errStopToken diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 47d75a89c9..a8fdac855d 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,6 +17,8 @@ package vm import ( + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" @@ -63,7 +65,7 @@ func (ctx *ScopeContext) Address() common.Address { return ctx.Contract.Address() } -func (ctx *ScopeContext) CallValue() *uint256.Int { +func (ctx *ScopeContext) CallValue() *big.Int { return ctx.Contract.Value() } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 9ca6363250..895d6be684 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -77,7 +77,7 @@ func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.Chain tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) - tracer.OnEnd(ret, startGas-contract.Gas, err, true) + tracer.OnExit(0, ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) if err != nil { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index d671d3d364..83db1139f1 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -147,32 +147,7 @@ func newCallTracerObject(ctx *directory.Context, cfg json.RawMessage) (*callTrac } // First callframe contains tx context info // and is populated on start and end. - return &callTracer{callstack: make([]callFrame, 1), config: config}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - toCopy := to - t.callstack[0] = callFrame{ - Type: vm.CALL, - From: from, - To: &toCopy, - Input: common.CopyBytes(input), - Gas: t.gasLimit, - Value: value, - } - if create { - t.callstack[0].Type = vm.CREATE - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - t.callstack[0].processOutput(output, err, reverted) -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). @@ -195,6 +170,9 @@ func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common Gas: gas, Value: value, } + if depth == 0 { + call.Gas = t.gasLimit + } t.callstack = append(t.callstack, call) } @@ -210,17 +188,19 @@ func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, if t.config.OnlyTopCall { return } + size := len(t.callstack) if size <= 1 { return } - // pop call + // Pop call. call := t.callstack[size-1] t.callstack = t.callstack[:size-1] size -= 1 call.GasUsed = gasUsed call.processOutput(output, err, reverted) + // Nest call into parent. t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 5274113518..177082ffd9 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -104,7 +104,7 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { for _, t := range t.tracers { if t.OnEnter != nil { - t.OnEnter(typ, from, to, input, gas, value) + t.OnEnter(depth, typ, from, to, input, gas, value) } } } @@ -112,7 +112,7 @@ func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common. func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { if t.OnExit != nil { - t.OnExit(output, gasUsed, err, reverted) + t.OnExit(depth, output, gasUsed, err, reverted) } } } diff --git a/light/odr_test.go b/light/odr_test.go index 44450fc2ff..7296163e1d 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -30,6 +30,7 @@ import ( "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/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -201,7 +202,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } // Perform read-only call. - st.SetBalance(testBankAddress, math.MaxBig256, state.BalanceChangeUnspecified) + st.SetBalance(testBankAddress, math.MaxBig256, tracing.BalanceChangeUnspecified) msg := &core.Message{ From: testBankAddress, To: &testContractAddr, From 17fcdfaadfdea4f3d4ff1445da492956303c74ef Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 15 Mar 2024 10:58:50 -0400 Subject: [PATCH 32/33] Fixed incorrect `captureBeging/captureEnd` in EVM --- core/vm/evm.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index aafc577787..d5ce1c5120 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -181,7 +181,7 @@ func (evm *EVM) Interpreter() *EVMInterpreter { func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { // Capture the tracer start/end events in debug mode if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth == 0, CALL, caller.Address(), addr, input, gas, value) + evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -253,7 +253,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(false, CALLCODE, caller.Address(), addr, input, gas, value) + evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -308,7 +308,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // that caller is something other than a Contract. parent := caller.(*Contract) // DELEGATECALL inherits value from parent call - evm.captureBegin(false, DELEGATECALL, caller.Address(), addr, input, gas, parent.value) + evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -349,7 +349,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(false, STATICCALL, caller.Address(), addr, input, gas, nil) + evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -416,7 +416,7 @@ func (c *codeAndHash) Hash() common.Hash { // create creates a new contract using code as deployment code. func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth == 0, typ, caller.Address(), address, codeAndHash.code, gas, value) + evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -518,12 +518,11 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } -func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { +func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { tracer := evm.Config.Tracer if tracer.OnEnter != nil { - tracer.OnEnter(0, byte(typ), from, to, input, startGas, value) + tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value) } - if tracer.OnGasChange != nil { tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) } @@ -531,7 +530,6 @@ func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to co func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { tracer := evm.Config.Tracer - if leftOverGas != 0 && tracer.OnGasChange != nil { tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) } @@ -542,7 +540,9 @@ func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret [ if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { reverted = false } - tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + if tracer.OnExit != nil { + tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + } } // GetVMContext provides context about the block being executed as well as state From f596461a2369f6863a9ede9beb9594ec89558f04 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 15 Mar 2024 14:06:11 -0400 Subject: [PATCH 33/33] Backported a bunch more of `eth/tracers` --- common/hexutil/json.go | 45 ++++++ core/genesis.go | 12 +- core/state/dump.go | 41 +++--- eth/api_backend.go | 2 +- eth/state_accessor.go | 4 +- eth/tracers/api.go | 111 ++++++++++++--- eth/tracers/api_test.go | 130 ++++++++++++++++-- eth/tracers/directory/util_test.go | 6 +- .../internal/tracetest/calltrace_test.go | 14 +- .../internal/tracetest/prestate_test.go | 6 + .../testdata/prestate_tracer/blob_tx.json | 63 +++++++++ .../prestate_tracer/create_post_eip158.json | 64 +++++++++ .../create_failed.json | 2 +- .../create_post_eip158.json | 82 +++++++++++ eth/tracers/js/goja.go | 28 +++- .../js/internal/tracers/call_tracer_legacy.js | 2 +- eth/tracers/logger/gen_structlog.go | 16 ++- eth/tracers/logger/logger.go | 6 +- eth/tracers/native/call_flat.go | 6 + les/api_backend.go | 2 +- les/state_accessor.go | 4 +- 21 files changed, 558 insertions(+), 88 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json diff --git a/common/hexutil/json.go b/common/hexutil/json.go index 50db208118..6906bcaf53 100644 --- a/common/hexutil/json.go +++ b/common/hexutil/json.go @@ -23,6 +23,8 @@ import ( "math/big" "reflect" "strconv" + + "github.com/holiman/uint256" ) var ( @@ -30,6 +32,7 @@ var ( bigT = reflect.TypeOf((*Big)(nil)) uintT = reflect.TypeOf(Uint(0)) uint64T = reflect.TypeOf(Uint64(0)) + u256T = reflect.TypeOf((*uint256.Int)(nil)) ) // Bytes marshals/unmarshals as a JSON string with 0x prefix. @@ -91,6 +94,48 @@ func (b *Bytes) UnmarshalGraphQL(input interface{}) error { return err } +// U256 marshals/unmarshals as a JSON string with 0x prefix. +// The zero value marshals as "0x0". +type U256 uint256.Int + +// MarshalText implements encoding.TextMarshaler +func (b U256) MarshalText() ([]byte, error) { + u256 := (*uint256.Int)(&b) + return []byte(u256.Hex()), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *U256) UnmarshalJSON(input []byte) error { + // The uint256.Int.UnmarshalJSON method accepts "dec", "0xhex"; we must be + // more strict, hence we check string and invoke SetFromHex directly. + if !isString(input) { + return errNonString(u256T) + } + // The hex decoder needs to accept empty string ("") as '0', which uint256.Int + // would reject. + if len(input) == 2 { + (*uint256.Int)(b).Clear() + return nil + } + err := (*uint256.Int)(b).SetFromHex(string(input[1 : len(input)-1])) + if err != nil { + return &json.UnmarshalTypeError{Value: err.Error(), Type: u256T} + } + return nil +} + +// UnmarshalText implements encoding.TextUnmarshaler +func (b *U256) UnmarshalText(input []byte) error { + // The uint256.Int.UnmarshalText method accepts "dec", "0xhex"; we must be + // more strict, hence we check string and invoke SetFromHex directly. + return (*uint256.Int)(b).SetFromHex(string(input)) +} + +// String returns the hex encoding of b. +func (b *U256) String() string { + return (*uint256.Int)(b).Hex() +} + // UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out // determines the required input length. This function is commonly used to implement the // UnmarshalJSON method for fixed-size types. diff --git a/core/genesis.go b/core/genesis.go index a6c51f3c20..aa788711f0 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -43,6 +43,12 @@ import ( var errGenesisNoConfig = errors.New("genesis has no chain configuration") +// use types.GenesisAccount instead (Deprecation not ported from latest Geth for now). +type GenesisAccount = types.Account + +// use types.GenesisAlloc instead (Deprecation not ported from latest Geth for now). +type GenesisAlloc = types.GenesisAlloc + // Genesis specifies the header fields, state of a genesis block. It also defines hard // fork switch-over blocks through the chain configuration. type Genesis struct { @@ -104,12 +110,6 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { return &genesis, nil } -// Deprecated: use types.GenesisAccount instead. -type GenesisAccount = types.Account - -// Deprecated: use types.GenesisAlloc instead. -type GenesisAlloc = types.GenesisAlloc - // hashAlloc computes the state root according to the genesis specification. func hashAlloc(ga *types.GenesisAlloc) (common.Hash, error) { // Create an ephemeral in-memory database for computing hash, diff --git a/core/state/dump.go b/core/state/dump.go index d3a7b1170e..9ce6cd394b 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -49,14 +49,15 @@ type DumpCollector interface { // DumpAccount represents an account in the state. type DumpAccount struct { - Balance string `json:"balance"` - Nonce uint64 `json:"nonce"` - Root hexutil.Bytes `json:"root"` - CodeHash hexutil.Bytes `json:"codeHash"` - Code hexutil.Bytes `json:"code,omitempty"` - Storage map[common.Hash]string `json:"storage,omitempty"` - Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode - AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key + Balance string `json:"balance"` + Nonce uint64 `json:"nonce"` + Root hexutil.Bytes `json:"root"` + CodeHash hexutil.Bytes `json:"codeHash"` + Code hexutil.Bytes `json:"code,omitempty"` + Storage map[common.Hash]string `json:"storage,omitempty"` + Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode + SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key + } // Dump represents the full dump in a collected format, as one large map. @@ -104,13 +105,14 @@ type iterativeDump struct { // OnAccount implements DumpCollector interface func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { dumpAccount := &DumpAccount{ - Balance: account.Balance, - Nonce: account.Nonce, - Root: account.Root, - CodeHash: account.CodeHash, - Code: account.Code, - Storage: account.Storage, - Address: addr, + Balance: account.Balance, + Nonce: account.Nonce, + Root: account.Root, + CodeHash: account.CodeHash, + Code: account.Code, + Storage: account.Storage, + SecureKey: account.SecureKey, + Address: addr, } d.Encode(dumpAccount) } @@ -149,10 +151,11 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] panic(err) } account := DumpAccount{ - Balance: data.Balance.String(), - Nonce: data.Nonce, - Root: data.Root[:], - CodeHash: data.CodeHash, + Balance: data.Balance.String(), + Nonce: data.Nonce, + Root: data.Root[:], + CodeHash: data.CodeHash, + SecureKey: it.Key, } var ( addrBytes = s.trie.GetKey(it.Key) diff --git a/eth/api_backend.go b/eth/api_backend.go index 601e555158..c59f32eec2 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -412,6 +412,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } -func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 24694df66c..cf00e582bc 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -216,7 +216,7 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe } // stateAtTransaction returns the execution environment of a certain transaction. -func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -243,7 +243,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) if idx == txIndex { - return msg, context, statedb, release, nil + return tx, context, statedb, release, nil } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 447ba3119c..e6fb576416 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -88,7 +88,7 @@ type Backend interface { Engine() consensus.Engine ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) - StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) + StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -166,6 +166,7 @@ type TraceCallConfig struct { TraceConfig StateOverrides *ethapi.StateOverride BlockOverrides *ethapi.BlockOverrides + TxIndex *hexutil.Uint } // StdTraceConfig holds extra parameters to standard-json trace functions. @@ -227,7 +228,7 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf } sub := notifier.CreateSubscription() - resCh := api.traceChain(from, to, config, notifier.Closed()) + resCh := api.traceChain(from, to, config, sub.Err()) go func() { for result := range resCh { notifier.Notify(sub.ID, result) @@ -241,7 +242,7 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf // the end block but excludes the start one. The return value will be one item per // transaction, dependent on the requested tracer. // The tracing procedure should be aborted in case the closed signal is received. -func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult { +func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan error) chan *blockTraceResult { reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec @@ -278,7 +279,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config) if err != nil { task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) @@ -610,7 +611,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) if err != nil { return nil, err } @@ -627,7 +628,6 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat var ( txs = block.Transactions() blockHash = block.Hash() - blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) pend sync.WaitGroup @@ -650,7 +650,12 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat TxIndex: task.index, TxHash: txs[task.index].Hash(), } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) + // Reconstruct the block context for each transaction + // as the GetHash function of BlockContext is not safe for + // concurrent use. + // See: https://github.com/ethereum/go-ethereum/issues/29114 + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config) if err != nil { results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} continue @@ -662,6 +667,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // Feed the transactions into the tracers and return var failed error + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) txloop: for i, tx := range txs { // Send the trace task over for execution @@ -843,11 +849,15 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if err != nil { return nil, err } - msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) + tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) if err != nil { return nil, err } defer release() + msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee()) + if err != nil { + return nil, err + } txctx := &directory.Context{ BlockHash: blockHash, @@ -855,17 +865,23 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * TxIndex: int(index), TxHash: hash, } - return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) + return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config) } // TraceCall lets you trace a given eth_call. It collects the structured logs // created during the execution of EVM if the given transaction was added on // top of the provided block and returns them as a JSON object. +// If no transaction index is specified, the trace will be conducted on the state +// after executing the specified block. However, if a transaction index is provided, +// the trace will be conducted on the state after executing the specified transaction +// within the specified block. func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) { // Try to retrieve the specified block var ( - err error - block *types.Block + err error + block *types.Block + statedb *state.StateDB + release StateReleaseFunc ) if hash, ok := blockNrOrHash.Hash(); ok { block, err = api.blockByHash(ctx, hash) @@ -890,7 +906,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false) + + if config != nil && config.TxIndex != nil { + _, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex), reexec) + } else { + statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false) + } if err != nil { return nil, err } @@ -905,26 +926,30 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) } // Execute the trace - msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee()) + msg, err := args.ToMessage(api.backend.RPCGasCap(), vmctx.BaseFee) + if err != nil { + return nil, err + } + tx, err := argsToTransaction(api.backend, &args, msg) if err != nil { return nil, err } - var traceConfig *TraceConfig if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, msg, new(directory.Context), vmctx, statedb, traceConfig) + return api.traceTx(ctx, tx, msg, new(directory.Context), vmctx, statedb, traceConfig) } // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will // be tracer dependent. -func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *directory.Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { +func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *directory.Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { var ( tracer *directory.Tracer err error timeout = defaultTraceTimeout + usedGas uint64 ) if config == nil { config = &TraceConfig{} @@ -959,7 +984,8 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *direc // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil { + _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv) + if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } return tracer.GetResult() @@ -1024,3 +1050,54 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) return copy, canon } + +// argsToTransaction produces a Transaction object given call arguments. +// The `msg` field must be converted from the same arguments. +func argsToTransaction(b Backend, args *ethapi.TransactionArgs, msg *core.Message) (*types.Transaction, error) { + chainID := b.ChainConfig().ChainID + if args.ChainID != nil { + if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 { + return nil, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID) + } + } + var data types.TxData + switch { + case args.MaxFeePerGas != nil: + al := types.AccessList{} + if args.AccessList != nil { + al = *args.AccessList + } + data = &types.DynamicFeeTx{ + To: args.To, + ChainID: chainID, + Nonce: msg.Nonce, + Gas: msg.GasLimit, + GasFeeCap: msg.GasFeeCap, + GasTipCap: msg.GasTipCap, + Value: msg.Value, + Data: msg.Data, + AccessList: al, + } + case args.AccessList != nil: + data = &types.AccessListTx{ + To: args.To, + ChainID: chainID, + Nonce: msg.Nonce, + Gas: msg.GasLimit, + GasPrice: msg.GasPrice, + Value: msg.Value, + Data: msg.Data, + AccessList: *args.AccessList, + } + default: + data = &types.LegacyTx{ + To: args.To, + Nonce: msg.Nonce, + Gas: msg.GasLimit, + GasPrice: msg.GasPrice, + Value: msg.Value, + Data: msg.Data, + } + } + return types.NewTx(data), nil +} diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 52db08e9de..7405d2e035 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -155,7 +155,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex return statedb, release, nil } -func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { +func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { return nil, vm.BlockContext{}, nil, nil, errBlockNotFound @@ -174,7 +174,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), b.chain, nil) if idx == txIndex { - return msg, context, statedb, release, nil + return tx, context, statedb, release, nil } vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { @@ -192,7 +192,7 @@ func TestTraceCall(t *testing.T) { accounts := newAccounts(3) genesis := &core.Genesis{ Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ + Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, @@ -200,13 +200,51 @@ func TestTraceCall(t *testing.T) { } genBlocks := 10 signer := types.HomesteadSigner{} + nonce := uint64(0) backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei - tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: nonce, + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) b.AddTx(tx) + nonce++ + + if i == genBlocks-2 { + // Transfer from account[0] to account[2] + tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: nonce, + To: &accounts[2].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) + b.AddTx(tx) + nonce++ + + // Transfer from account[0] to account[1] again + tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: nonce, + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) + b.AddTx(tx) + nonce++ + } }) + + uintPtr := func(i int) *hexutil.Uint { x := hexutil.Uint(i); return &x } + defer backend.teardown() api := NewAPI(backend) var testSuite = []struct { @@ -240,6 +278,51 @@ func TestTraceCall(t *testing.T) { expectErr: nil, expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, }, + // Upon the last state, default to the post block's state + { + blockNumber: rpc.BlockNumber(genBlocks - 1), + call: ethapi.TransactionArgs{ + From: &accounts[2].addr, + To: &accounts[0].addr, + Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))), + }, + config: nil, + expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + }, + // Before the first transaction, should be failed + { + blockNumber: rpc.BlockNumber(genBlocks - 1), + call: ethapi.TransactionArgs{ + From: &accounts[2].addr, + To: &accounts[0].addr, + Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))), + }, + config: &TraceCallConfig{TxIndex: uintPtr(0)}, + expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr), + }, + // Before the target transaction, should be failed + { + blockNumber: rpc.BlockNumber(genBlocks - 1), + call: ethapi.TransactionArgs{ + From: &accounts[2].addr, + To: &accounts[0].addr, + Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))), + }, + config: &TraceCallConfig{TxIndex: uintPtr(1)}, + expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr), + }, + // After the target transaction, should be succeed + { + blockNumber: rpc.BlockNumber(genBlocks - 1), + call: ethapi.TransactionArgs{ + From: &accounts[2].addr, + To: &accounts[0].addr, + Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))), + }, + config: &TraceCallConfig{TxIndex: uintPtr(2)}, + expectErr: nil, + expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + }, // Standard JSON trace upon the non-existent block, error expects { blockNumber: rpc.BlockNumber(genBlocks + 1), @@ -297,8 +380,8 @@ func TestTraceCall(t *testing.T) { t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr) continue } - if !reflect.DeepEqual(err, testspec.expectErr) { - t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err) + if !reflect.DeepEqual(err.Error(), testspec.expectErr.Error()) { + t.Errorf("test %d: error mismatch, want '%v', got '%v'", i, testspec.expectErr, err) } } else { if err != nil { @@ -327,7 +410,7 @@ func TestTraceTransaction(t *testing.T) { accounts := newAccounts(2) genesis := &core.Genesis{ Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ + Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, }, @@ -338,7 +421,14 @@ func TestTraceTransaction(t *testing.T) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei - tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) b.AddTx(tx) target = tx.Hash() }) @@ -375,7 +465,7 @@ func TestTraceBlock(t *testing.T) { accounts := newAccounts(3) genesis := &core.Genesis{ Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ + Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, @@ -388,7 +478,14 @@ func TestTraceBlock(t *testing.T) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei - tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) b.AddTx(tx) txHash = tx.Hash() }) @@ -458,7 +555,7 @@ func TestTracingWithOverrides(t *testing.T) { storageAccount := common.Address{0x13, 37} genesis := &core.Genesis{ Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ + Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, @@ -478,7 +575,14 @@ func TestTracingWithOverrides(t *testing.T) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei - tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &accounts[1].addr, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) b.AddTx(tx) }) defer backend.chain.Stop() @@ -819,7 +923,7 @@ func TestTraceChain(t *testing.T) { accounts := newAccounts(3) genesis := &core.Genesis{ Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ + Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, diff --git a/eth/tracers/directory/util_test.go b/eth/tracers/directory/util_test.go index 904c749d06..731eeb832f 100644 --- a/eth/tracers/directory/util_test.go +++ b/eth/tracers/directory/util_test.go @@ -33,9 +33,9 @@ func TestMemCopying(t *testing.T) { {0, 100, 0, "", 0}, // No need to pad (0 size) {100, 50, 100, "", 100}, // Should pad 100-150 {100, 50, 5, "", 5}, // Wanted range fully within memory - {100, -50, 0, "offset or size must not be negative", 0}, // Errror - {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror - {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror + {100, -50, 0, "offset or size must not be negative", 0}, // Error + {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Error + {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Error } { mem := vm.NewMemory() diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 8ca877aea5..a45ba2bf14 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -223,10 +223,6 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.Fatalf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - msg, err := core.TransactionToMessage(tx, signer, nil) - if err != nil { - b.Fatalf("failed to prepare transaction for tracing: %v", err) - } origin, _ := signer.Sender(tx) txContext := vm.TxContext{ Origin: origin, @@ -241,6 +237,10 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) + if err != nil { + b.Fatalf("failed to prepare transaction for tracing: %v", err) + } triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) defer triedb.Close() @@ -370,11 +370,11 @@ func TestInternals(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), - core.GenesisAlloc{ - to: core.GenesisAccount{ + types.GenesisAlloc{ + to: types.Account{ Code: tc.code, }, - origin: core.GenesisAccount{ + origin: types.Account{ Balance: big.NewInt(500000000000000), }, }, false, rawdb.HashScheme) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 48a95f43c1..9bad16bc4c 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -107,6 +108,11 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { ) defer triedb.Close() + if test.Genesis.ExcessBlobGas != nil && test.Genesis.BlobGasUsed != nil { + excessBlobGas := eip4844.CalcExcessBlobGas(*test.Genesis.ExcessBlobGas, *test.Genesis.BlobGasUsed) + context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + } + tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json new file mode 100644 index 0000000000..315481aff5 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -0,0 +1,63 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "blobGasUsed": "0", + "difficulty": "0", + "excessBlobGas": "36306944", + "extraData": "0xd983010e00846765746888676f312e32312e308664617277696e", + "gasLimit": "15639172", + "hash": "0xc682259fda061bb9ce8ccb491d5b2d436cb73daf04e1025dd116d045ce4ad28c", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xae1a5ba939a4c9ac38aabeff361169fb55a6fc2c9511457e0be6eff9514faec0", + "nonce": "0x0000000000000000", + "number": "315", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", + "timestamp": "1709626771", + "totalDifficulty": "1", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, + "0x0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xde0b6b3a7640000" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true + } + }, + "context": { + "number": "316", + "difficulty": "0", + "timestamp": "1709626785", + "gasLimit": "15654443", + "miner": "0x0000000000000000000000000000000000000000" + }, + "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", + "result": { + "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" }, + "0x0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xde0b6b3a7640000" + } + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json new file mode 100644 index 0000000000..205b472dab --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json @@ -0,0 +1,64 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "difficulty": "2", + "extraData": "0xd983010d0e846765746888676f312e32312e318664617277696e0000000000001713699f05f79a59abec177c7a87b90ceda79b72ff5edc9197dd7627a447cde45b079bbc3765a236cdf680e2d4d2247135d0e6bb6fd92b50638b92504ddb274f00", + "gasLimit": "30000000", + "hash": "0x6ad5258175c66f4e883d238a92a08428d8ebcbeac631ab7b972634cc05effab3", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": "39137", + "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", + "timestamp": "1709022192", + "totalDifficulty": "78275", + "alloc": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": "2" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": "64" + } + }, + "config": { + "chainId": 12345, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + } + } + }, + "context": { + "number": "39138", + "difficulty": "2", + "timestamp": "1709022197", + "gasLimit": "30000000", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + }, + "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", + "result": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": 2 + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": 64 + } + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json index e80dad5667..561ead05b6 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json @@ -83,7 +83,7 @@ }, "post": { "0x808b4da0be6c9512e948521452227efc619bea52": { - "balance": "0x2cd72a36dd031f089", + "balance": "0x2cd987071ba2346b6", "nonce": 1223933 }, "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json new file mode 100644 index 0000000000..83266f6669 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_post_eip158.json @@ -0,0 +1,82 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "difficulty": "2", + "extraData": "0xd983010d0e846765746888676f312e32312e318664617277696e0000000000001713699f05f79a59abec177c7a87b90ceda79b72ff5edc9197dd7627a447cde45b079bbc3765a236cdf680e2d4d2247135d0e6bb6fd92b50638b92504ddb274f00", + "gasLimit": "30000000", + "hash": "0x6ad5258175c66f4e883d238a92a08428d8ebcbeac631ab7b972634cc05effab3", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": "39137", + "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c", + "timestamp": "1709022192", + "totalDifficulty": "78275", + "alloc": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": "2" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": "64" + } + }, + "config": { + "chainId": 12345, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + } + } + }, + "context": { + "number": "39138", + "difficulty": "2", + "timestamp": "1709022197", + "gasLimit": "30000000", + "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0" + }, + "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453", + "tracerConfig": { + "diffMode": true + }, + "result": { + "post": { + "0x1bda2f8e4735507930bd6cfe873bf0bf0f4ab1de": { + "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033", + "nonce": 1 + }, + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f0645688331eb5690" + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6aae9b21b6ee855", + "nonce": 65 + } + }, + "pre": { + "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": { + "balance": "0x10f06447a8d44dba190", + "nonce": 2 + }, + "0x82211934c340b29561381392348d48413e15adc8": { + "balance": "0x6abd7a808913ed2", + "nonce": 64 + } + } + } +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 86454d376a..5c52ba1f11 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -144,19 +144,29 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir vm: vm, ctx: make(map[string]goja.Value), } + + t.setTypeConverters() + t.setBuiltinFunctions() + if ctx == nil { ctx = new(directory.Context) } if ctx.BlockHash != (common.Hash{}) { - t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) + blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes()) + if err != nil { + return nil, err + } + t.ctx["blockHash"] = blockHash if ctx.TxHash != (common.Hash{}) { t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex) - t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes()) + txHash, err := t.toBuf(vm, ctx.TxHash.Bytes()) + if err != nil { + return nil, err + } + t.ctx["txHash"] = txHash } } - t.setTypeConverters() - t.setBuiltinFunctions() ret, err := vm.RunString("(" + code + ")") if err != nil { return nil, err @@ -341,6 +351,12 @@ func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } + outputVal, err := t.toBuf(t.vm, output) + if err != nil { + t.err = err + return + } + t.ctx["output"] = outputVal } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). @@ -520,13 +536,13 @@ func (t *jsTracer) setBuiltinFunctions() { } return false }) - vm.Set("slice", func(slice goja.Value, start, end int) goja.Value { + vm.Set("slice", func(slice goja.Value, start, end int64) goja.Value { b, err := t.fromBuf(vm, slice, false) if err != nil { vm.Interrupt(err) return nil } - if start < 0 || start > end || end > len(b) { + if start < 0 || start > end || end > int64(len(b)) { vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start)) return nil } diff --git a/eth/tracers/js/internal/tracers/call_tracer_legacy.js b/eth/tracers/js/internal/tracers/call_tracer_legacy.js index 451a644b91..0760bb1e3f 100644 --- a/eth/tracers/js/internal/tracers/call_tracer_legacy.js +++ b/eth/tracers/js/internal/tracers/call_tracer_legacy.js @@ -219,7 +219,7 @@ return this.finalize(result); }, - // finalize recreates a call object using the final desired field oder for json + // finalize recreates a call object using the final desired field order for json // serialization. This is a nicety feature to pass meaningfully ordered results // to users who don't interpret it, just display it. finalize: function(call) { diff --git a/eth/tracers/logger/gen_structlog.go b/eth/tracers/logger/gen_structlog.go index df06a9ee6b..b406cb3445 100644 --- a/eth/tracers/logger/gen_structlog.go +++ b/eth/tracers/logger/gen_structlog.go @@ -23,7 +23,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) { GasCost math.HexOrDecimal64 `json:"gasCost"` Memory hexutil.Bytes `json:"memory,omitempty"` MemorySize int `json:"memSize"` - Stack []uint256.Int `json:"stack"` + Stack []hexutil.U256 `json:"stack"` ReturnData hexutil.Bytes `json:"returnData,omitempty"` Storage map[common.Hash]common.Hash `json:"-"` Depth int `json:"depth"` @@ -39,7 +39,12 @@ func (s StructLog) MarshalJSON() ([]byte, error) { enc.GasCost = math.HexOrDecimal64(s.GasCost) enc.Memory = s.Memory enc.MemorySize = s.MemorySize - enc.Stack = s.Stack + if s.Stack != nil { + enc.Stack = make([]hexutil.U256, len(s.Stack)) + for k, v := range s.Stack { + enc.Stack[k] = hexutil.U256(v) + } + } enc.ReturnData = s.ReturnData enc.Storage = s.Storage enc.Depth = s.Depth @@ -59,7 +64,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { GasCost *math.HexOrDecimal64 `json:"gasCost"` Memory *hexutil.Bytes `json:"memory,omitempty"` MemorySize *int `json:"memSize"` - Stack []uint256.Int `json:"stack"` + Stack []hexutil.U256 `json:"stack"` ReturnData *hexutil.Bytes `json:"returnData,omitempty"` Storage map[common.Hash]common.Hash `json:"-"` Depth *int `json:"depth"` @@ -89,7 +94,10 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { s.MemorySize = *dec.MemorySize } if dec.Stack != nil { - s.Stack = dec.Stack + s.Stack = make([]uint256.Int, len(dec.Stack)) + for k, v := range dec.Stack { + s.Stack[k] = uint256.Int(v) + } } if dec.ReturnData != nil { s.ReturnData = *dec.ReturnData diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 7e2e7aeff8..9d6f4c8a19 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -85,6 +85,7 @@ type structLogMarshaling struct { GasCost math.HexOrDecimal64 Memory hexutil.Bytes ReturnData hexutil.Bytes + Stack []hexutil.U256 OpName string `json:"opName"` // adds call to OpName() in MarshalJSON ErrorString string `json:"error,omitempty"` // adds call to ErrorString() in MarshalJSON } @@ -418,11 +419,6 @@ func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } -func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", - output, gasUsed, err) -} - // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 47d388d312..cd53736ed9 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -155,6 +155,9 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { t.tracer.OnEnter(depth, typ, from, to, input, gas, value) + if depth == 0 { + return + } // Child calls must have a value, even if it's zero. // Practically speaking, only STATICCALL has nil value. Set it to zero. if t.tracer.callstack[len(t.tracer.callstack)-1].Value == nil && value == nil { @@ -167,6 +170,9 @@ func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to co func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { t.tracer.OnExit(depth, output, gasUsed, err, reverted) + if depth == 0 { + return + } // Parity traces don't include CALL/STATICCALLs to precompiles. // By default we remove them from the callstack. if t.config.IncludePrecompiles { diff --git a/les/api_backend.go b/les/api_backend.go index 3e9dbadce8..07ec02552e 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -332,6 +332,6 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re return b.eth.stateAtBlock(ctx, block, reexec) } -func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/les/state_accessor.go b/les/state_accessor.go index 9a8214ac2f..a9c8e2dea8 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -39,7 +39,7 @@ func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, } // stateAtTransaction returns the execution environment of a certain transaction. -func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -65,7 +65,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) statedb.SetTxContext(tx.Hash(), idx) if idx == txIndex { - return msg, context, statedb, release, nil + return tx, context, statedb, release, nil } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})