From 9f71824d8c37f1ff97fea635d3503e2bae37481a Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 6 Feb 2024 15:36:12 -0500 Subject: [PATCH] Backported commits from `extended-tracer` - https://github.com/s1na/go-ethereum/commit/6c44a594f4423664cc363ea4e9e50223a4597139 - https://github.com/s1na/go-ethereum/commit/188cd4182e3dee1c7ac5fc91b0c29cde2c2eb48f - https://github.com/s1na/go-ethereum/commit/f3c0a89b574c34dc88349c0b3df9d8b1e7e707ab - https://github.com/s1na/go-ethereum/commit/95b50299a5c4f96ccdd44fe73d543f28629e1938 - https://github.com/s1na/go-ethereum/commit/2cc09548bb86736718ff4c897c1b30e495ac31a6 --- core/blockchain.go | 10 ++- core/state/statedb.go | 20 +----- core/state_processor.go | 2 - eth/tracers/live/noop.go | 98 ++++++++++++++++++++++++++ eth/tracers/live/printer.go | 134 ------------------------------------ 5 files changed, 107 insertions(+), 157 deletions(-) create mode 100644 eth/tracers/live/noop.go delete mode 100644 eth/tracers/live/printer.go diff --git a/core/blockchain.go b/core/blockchain.go index f9278d1908..42648345d5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -190,9 +190,10 @@ func DefaultCacheConfigWithScheme(scheme string) *CacheConfig { 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(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) + OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header) OnBlockEnd(err error) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) OnBeaconBlockRootStart(root common.Hash) @@ -501,6 +502,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } + if bc.logger != nil { + bc.logger.OnBlockchainInit(chainConfig) + } // Start tx indexer/unindexer if required. if txLookupLimit != nil { bc.txLookupLimit = *txLookupLimit @@ -1804,7 +1808,7 @@ 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(), bc.chainConfig) + bc.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) bc.logger.OnBlockEnd(nil) } @@ -1933,7 +1937,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 { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), bc.chainConfig) + bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/core/state/statedb.go b/core/state/statedb.go index 618b1cf042..838cbbe9a9 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -124,9 +124,6 @@ type StateDB struct { // Preimages occurred seen by VM in the scope of block. preimages map[common.Hash][]byte - // Enabled precompile contracts - precompiles map[common.Address]struct{} - // Per-transaction access list accessList *accessList @@ -183,7 +180,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) stateObjectsDestruct: make(map[common.Address]*types.StateAccount), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), - precompiles: make(map[common.Address]struct{}), journal: newJournal(), accessList: newAccessList(), transientStorage: newTransientStorage(), @@ -667,11 +663,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! newobj = newObject(s, addr, nil) if s.logger != nil { - // Precompiled contracts are touched during a call. - // Make sure we avoid emitting a new account event for them. - if _, ok := s.precompiles[addr]; !ok { - s.logger.OnNewAccount(addr, prev != nil) - } + s.logger.OnNewAccount(addr, prev != nil) } if prev == nil { s.journal.append(createObjectChange{account: &addr}) @@ -883,7 +875,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(); bal.Sign() != 0 && s.logger != nil { + if bal := obj.Balance(); s.logger != 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 @@ -1391,14 +1383,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d s.transientStorage = newTransientStorage() } -// PrepareBlock prepares the statedb for execution of a block. It tracks -// the addresses of enabled precompiles for debugging purposes. -func (s *StateDB) PrepareBlock(precompiles []common.Address) { - for _, addr := range precompiles { - s.precompiles[addr] = struct{}{} - } -} - // AddAddressToAccessList adds the given address to the access list func (s *StateDB) AddAddressToAccessList(addr common.Address) { if s.accessList.AddAddress(addr) { diff --git a/core/state_processor.go b/core/state_processor.go index b468dce3af..231f63f969 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -75,13 +75,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg var ( context = NewEVMBlockContext(header, p.bc, nil) vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) - rules = vmenv.ChainConfig().Rules(context.BlockNumber, context.Random != nil, context.Time) signer = types.MakeSigner(p.config, header.Number, header.Time) ) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb, p.bc.logger) } - statedb.PrepareBlock(vm.ActivePrecompiles(rules)) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go new file mode 100644 index 0000000000..822fbbaea3 --- /dev/null +++ b/eth/tracers/live/noop.go @@ -0,0 +1,98 @@ +package live + +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" + "github.com/ethereum/go-ethereum/params" +) + +func init() { + directory.LiveDirectory.Register("noop", newNoopTracer) +} + +// noop is a no-op live tracer. It's there to +// catch changes in the tracing interface, as well as +// for testing live tracing performance. Can be removed +// as soon as we have a real live tracer. +type noop struct{} + +func newNoopTracer() (core.BlockchainLogger, error) { + return &noop{}, 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) { +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *noop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +} + +// 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) { +} + +// 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) { +} + +// 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) { +} + +// 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) OnBeaconBlockRootStart(root common.Hash) {} +func (t *noop) OnBeaconBlockRootEnd() {} + +func (t *noop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +} + +func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { +} + +func (t *noop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { +} + +func (t *noop) OnBlockEnd(err error) { +} + +func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { +} + +func (t *noop) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +} + +func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +} + +func (t *noop) OnNonceChange(a common.Address, prev, new uint64) { +} + +func (t *noop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (t *noop) OnStorageChange(a common.Address, k, prev, new common.Hash) { +} + +func (t *noop) OnLog(l *types.Log) { + +} + +func (t *noop) OnNewAccount(a common.Address, reset bool) { +} + +func (t *noop) OnGasChange(old, new uint64, reason vm.GasChangeReason) { +} diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go deleted file mode 100644 index fc6e759005..0000000000 --- a/eth/tracers/live/printer.go +++ /dev/null @@ -1,134 +0,0 @@ -package live - -import ( - "encoding/json" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "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" - "github.com/ethereum/go-ethereum/params" -) - -func init() { - directory.LiveDirectory.Register("printer", newPrinter) -} - -type Printer struct{} - -func newPrinter() (core.BlockchainLogger, error) { - return &Printer{}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (p *Printer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - fmt.Printf("CaptureStart: from=%v, to=%v, create=%v, input=%s, gas=%v, value=%v\n", from, to, create, hexutil.Bytes(input), gas, value) -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { - fmt.Printf("CaptureEnd: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err) -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (p *Printer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - //fmt.Printf("CaptureState: pc=%v, op=%v, gas=%v, cost=%v, scope=%v, rData=%v, depth=%v, err=%v\n", pc, op, gas, cost, scope, rData, depth, err) -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (p *Printer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { - fmt.Printf("CaptureFault: pc=%v, op=%v, gas=%v, cost=%v, depth=%v, err=%v\n", pc, op, gas, cost, depth, err) -} - -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (p *Printer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (p *Printer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - fmt.Printf("CaptureEnter: typ=%v, from=%v, to=%v, input=%s, gas=%v, value=%v\n", typ, from, to, hexutil.Bytes(input), gas, value) -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { - fmt.Printf("CaptureExit: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err) -} - -func (p *Printer) OnBeaconBlockRootStart(root common.Hash) {} -func (p *Printer) OnBeaconBlockRootEnd() {} - -func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { - buf, err := json.Marshal(tx) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Printf("CaptureTxStart: tx=%s\n", buf) -} - -func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) { - if err != nil { - fmt.Printf("CaptureTxEnd err: %v\n", err) - return - } - buf, err := json.Marshal(receipt) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) -} - -func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header, _ *params.ChainConfig) { - if finalized != nil && safe != nil { - fmt.Printf("OnBlockStart: b=%v, td=%v, finalized=%v, safe=%v\n", b.NumberU64(), td, finalized.Number.Uint64(), safe.Number.Uint64()) - } else { - fmt.Printf("OnBlockStart: b=%v, td=%v\n", b.NumberU64(), td) - } -} - -func (p *Printer) OnBlockEnd(err error) { - fmt.Printf("OnBlockEnd: err=%v\n", err) -} - -func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { - fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc)) -} - -func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { - fmt.Printf("OnBalanceChange: a=%v, prev=%v, new=%v\n", a, prev, new) -} - -func (p *Printer) OnNonceChange(a common.Address, prev, new uint64) { - fmt.Printf("OnNonceChange: a=%v, prev=%v, new=%v\n", a, prev, new) -} - -func (p *Printer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { - fmt.Printf("OnCodeChange: a=%v, prevCodeHash=%v, prev=%s, codeHash=%v, code=%s\n", a, prevCodeHash, hexutil.Bytes(prev), codeHash, hexutil.Bytes(code)) -} - -func (p *Printer) OnStorageChange(a common.Address, k, prev, new common.Hash) { - fmt.Printf("OnStorageChange: a=%v, k=%v, prev=%v, new=%v\n", a, k, prev, new) -} - -func (p *Printer) OnLog(l *types.Log) { - buf, err := json.Marshal(l) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Printf("OnLog: l=%s\n", buf) -} - -func (p *Printer) OnNewAccount(a common.Address, reset bool) { - fmt.Printf("OnNewAccount: a=%v\n", a) -} - -func (p *Printer) OnGasChange(old, new uint64, reason vm.GasChangeReason) { - fmt.Printf("OnGasChange: old=%v, new=%v, diff=%v\n", old, new, new-old) -}