From 642a374b9d9c7664530ac8b1d695d6a5041d771b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Jun 2023 17:40:49 +0200 Subject: [PATCH 001/100] Initial support for extended tracer --- cmd/geth/chaincmd.go | 1 + cmd/geth/main.go | 1 + cmd/utils/flags.go | 8 ++++++ core/blockchain.go | 13 +++++++++ core/state_processor.go | 4 +++ eth/tracers/printer.go | 64 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+) create mode 100644 eth/tracers/printer.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index b27ce557106f..bd66c3bcfd9c 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -94,6 +94,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, + utils.VMTraceFlag, }, utils.DatabasePathFlags), Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file diff --git a/cmd/geth/main.go b/cmd/geth/main.go index dcdf0045ce25..904944be9aec 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -130,6 +130,7 @@ var ( utils.DeveloperPeriodFlag, utils.DeveloperGasLimitFlag, utils.VMEnableDebugFlag, + utils.VMTraceFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, utils.NoCompactionFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 692970477d07..e9cbe7f189cd 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -529,6 +529,11 @@ var ( Usage: "Record information useful for VM and contract debugging", Category: flags.VMCategory, } + VMTraceFlag = &cli.BoolFlag{ + Name: "vmtrace", + Usage: "Record internal VM operations (costly)", + Category: flags.VMCategory, + } // API options. RPCGlobalGasCapFlag = &cli.Uint64Flag{ @@ -2164,6 +2169,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if err != nil { Fatalf("Can't create BlockChain: %v", err) } + if ctx.IsSet(VMTraceFlag.Name) { + chain.SetLogger(tracers.NewPrinter()) + } return chain, chainDb } diff --git a/core/blockchain.go b/core/blockchain.go index ec8b789c586b..7acee5414486 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -153,6 +153,12 @@ var defaultCacheConfig = &CacheConfig{ SnapshotWait: true, } +type BlockchainLogger interface { + vm.EVMLogger + CaptureBlockStart(*types.Block) + CaptureBlockEnd() +} + // BlockChain represents the canonical chain given a database with a genesis // block. The Blockchain manages chain imports, reverts, chain reorganisations. // @@ -226,6 +232,7 @@ type BlockChain struct { processor Processor // Block transaction processor interface forker *ForkChoice vmConfig vm.Config + logger BlockchainLogger } // NewBlockChain returns a fully initialised block chain using information @@ -443,6 +450,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return bc, nil } +// TODO: need to move this to NewBlockchain to capture genesis block +func (bc *BlockChain) SetLogger(l BlockchainLogger) { + bc.logger = l + bc.vmConfig.Tracer = l +} + // empty returns an indicator whether the blockchain is empty. // Note, it's a special case that we connect a non-empty ancient // database with an empty node, so that we can plugin the ancient diff --git a/core/state_processor.go b/core/state_processor.go index 4837628e6602..e72cea359b99 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -67,6 +67,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) + if p.bc.logger != nil { + p.bc.logger.CaptureBlockStart(block) + defer p.bc.logger.CaptureBlockEnd() + } // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go new file mode 100644 index 000000000000..18608d64842c --- /dev/null +++ b/eth/tracers/printer.go @@ -0,0 +1,64 @@ +package tracers + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" +) + +type Printer struct{} + +func NewPrinter() *Printer { + return &Printer{} +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (p *Printer) CaptureStart(env *vm.EVM, 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=%v, gas=%v, value=%v\n", from, to, create, input, gas, value) +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error) { + fmt.Printf("CaptureEnd: output=%v, gasUsed=%v, err=%v\n", 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) +} + +// 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=%v, gas=%v, value=%v\n", typ, from, to, 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) { + fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err) +} + +func (p *Printer) CaptureTxStart(gasLimit uint64) { + fmt.Printf("CaptureTxStart: gasLimit=%v\n", gasLimit) + +} + +func (p *Printer) CaptureTxEnd(restGas uint64) { + fmt.Printf("CaptureTxEnd: restGas=%v\n", restGas) +} + +func (p *Printer) CaptureBlockStart(b *types.Block) { + fmt.Printf("CaptureBlockStart: b=%v\n", b.NumberU64()) +} + +func (p *Printer) CaptureBlockEnd() { + fmt.Printf("CaptureBlockEnd\n") +} From e25065bfc389c1bab158f055dcad6fbeb7125cc9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Jun 2023 18:42:57 +0200 Subject: [PATCH 002/100] capture keccak preimage --- core/vm/instructions.go | 4 +++- core/vm/logger.go | 1 + eth/tracers/js/goja.go | 3 +++ eth/tracers/logger/access_list_tracer.go | 2 ++ eth/tracers/logger/logger.go | 5 +++++ eth/tracers/logger/logger_json.go | 3 +++ eth/tracers/native/call_flat.go | 1 + eth/tracers/native/mux.go | 7 +++++++ eth/tracers/native/noop.go | 3 +++ eth/tracers/printer.go | 3 +++ 10 files changed, 31 insertions(+), 1 deletion(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 505aef412775..aaa12e436143 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -247,7 +247,9 @@ 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(common.BytesToHash(interpreter.hasherBuf[:]), data) + } size.SetBytes(interpreter.hasherBuf[:]) return nil, nil } diff --git a/core/vm/logger.go b/core/vm/logger.go index 2667908a84d1..d4b91ccc71a3 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -40,4 +40,5 @@ type EVMLogger interface { // 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) } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index f3d63df8ed5d..ac8822e98f36 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -286,6 +286,9 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } } +// CaptureKeccakPreimage is called during the KECCAK256 opcode. +func (t *jsTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + // CaptureEnd is called after the call finishes to finalize the tracing. func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { t.ctx["output"] = t.vm.ToValue(output) diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 766ee4e4b95c..c6a7bfddbe3c 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -161,6 +161,8 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6 func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { } +func (*AccessListTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c7f171c5bdf9..0c9ce9aec179 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -217,6 +217,9 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { } +// CaptureKeccakPreimage is called during the KECCAK256 opcode. +func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + // CaptureEnd is called after the call finishes to finalize the tracing. func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.output = output @@ -384,6 +387,8 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } +func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index a2cb4cd9fc59..91def6f38989 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -78,6 +78,9 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco l.encoder.Encode(log) } +// CaptureKeccakPreimage is called during the KECCAK256 opcode. +func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + // CaptureEnd is triggered at end of execution. func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { type endLog struct { diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 8612c23387d6..ca5d2e6aec92 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -108,6 +108,7 @@ 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 { + noopTracer tracer *callTracer config flatCallTracerConfig ctx *tracers.Context // Holds tracer context data diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index db8ddd64380d..16ae47e5fa71 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -86,6 +86,13 @@ func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scop } } +// 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) + } +} + // 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) { for _, t := range t.tracers { diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 3beecd8abfed..f60f3873a066 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -54,6 +54,9 @@ func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { } +// CaptureKeccakPreimage is called during the KECCAK256 opcode. +func (t *noopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + // 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) { } diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 18608d64842c..78f2c8b63daf 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -35,6 +35,9 @@ func (p *Printer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm. 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=%v, gas=%v, value=%v\n", typ, from, to, input, gas, value) From f67ac095a60c58507136c4012de703ce563e92b5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 20 Jun 2023 13:43:45 +0200 Subject: [PATCH 003/100] add hooks to state object & genesis --- core/blockchain.go | 6 +++++- core/chain_makers.go | 2 +- core/genesis.go | 22 +++++++++++++--------- core/state/state_object.go | 12 ++++++++++++ core/state/statedb.go | 13 +++++++++++++ eth/tracers/printer.go | 20 ++++++++++++++++++++ les/client.go | 2 +- 7 files changed, 65 insertions(+), 12 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 7acee5414486..cfc6cc7c51af 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -155,8 +155,10 @@ var defaultCacheConfig = &CacheConfig{ type BlockchainLogger interface { vm.EVMLogger + state.StateLogger CaptureBlockStart(*types.Block) CaptureBlockEnd() + OnGenesisBlock(*types.Block) } // BlockChain represents the canonical chain given a database with a genesis @@ -251,7 +253,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // 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. - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) + // TODO: pass in blockchainLogger here to catch genesis block and allocs + chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, nil) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } @@ -1739,6 +1742,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if err != nil { return it.index, err } + statedb.SetLogger(bc.logger) // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") diff --git a/core/chain_makers.go b/core/chain_makers.go index 61d0098af3f6..fe168f8b9c67 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -350,7 +350,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // then generate chain on top. func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { db := rawdb.NewMemoryDatabase() - _, err := genesis.Commit(db, trie.NewDatabase(db)) + _, err := genesis.Commit(db, trie.NewDatabase(db), nil) if err != nil { panic(err) } diff --git a/core/genesis.go b/core/genesis.go index 1e56845d8ad3..2d84efcfdedb 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -138,8 +138,9 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // flush is very similar with deriveHash, 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 (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash, bcLogger BlockchainLogger) error { statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb.SetLogger(bcLogger) if err != nil { return err } @@ -200,7 +201,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash comm return errors.New("not found") } } - return alloc.flush(db, triedb, blockhash) + return alloc.flush(db, triedb, blockhash, nil) } // GenesisAccount is an account in the state of the genesis block. @@ -282,10 +283,10 @@ type ChainOverrides struct { // // The returned chain configuration is never nil. func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlockWithOverride(db, triedb, genesis, nil) + return SetupGenesisBlockWithOverride(db, triedb, genesis, nil, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides, bcLogger BlockchainLogger) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } @@ -305,7 +306,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen } else { log.Info("Writing custom genesis block") } - block, err := genesis.Commit(db, triedb) + block, err := genesis.Commit(db, triedb, bcLogger) if err != nil { return genesis.Config, common.Hash{}, err } @@ -324,7 +325,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen if hash != stored { return genesis.Config, hash, &GenesisMismatchError{stored, hash} } - block, err := genesis.Commit(db, triedb) + block, err := genesis.Commit(db, triedb, bcLogger) if err != nil { return genesis.Config, hash, err } @@ -468,7 +469,7 @@ func (g *Genesis) ToBlock() *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. -func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) { +func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger BlockchainLogger) (*types.Block, error) { block := g.ToBlock() if block.Number().Sign() != 0 { return nil, errors.New("can't commit genesis block with number > 0") @@ -483,10 +484,13 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { return nil, errors.New("can't start clique chain without signers") } + if bcLogger != nil { + bcLogger.OnGenesisBlock(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 := g.Alloc.flush(db, triedb, block.Hash(), bcLogger); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) @@ -505,7 +509,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // Note the state changes will be committed in hash-based scheme, use Commit // if path-scheme is preferred. func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { - block, err := g.Commit(db, trie.NewDatabase(db)) + block, err := g.Commit(db, trie.NewDatabase(db), nil) if err != nil { panic(err) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 606441d2a68b..5ffae5df02aa 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -236,6 +236,9 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) { key: key, prevalue: prev, }) + if s.db.logger != nil { + s.db.logger.OnStorageChange(s.address, key, prev, value) + } s.setState(key, value) } @@ -399,6 +402,9 @@ func (s *stateObject) SetBalance(amount *big.Int) { account: &s.address, prev: new(big.Int).Set(s.data.Balance), }) + if s.db.logger != nil { + s.db.logger.OnBalanceChange(s.address, s.Balance(), amount) + } s.setBalance(amount) } @@ -470,6 +476,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { prevhash: s.CodeHash(), prevcode: prevcode, }) + if s.db.logger != nil { + s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code) + } s.setCode(codeHash, code) } @@ -484,6 +493,9 @@ func (s *stateObject) SetNonce(nonce uint64) { account: &s.address, prev: s.data.Nonce, }) + if s.db.logger != 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 b1b52cd7f11a..0ef6e6e3447b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -53,6 +53,13 @@ func (n *proofList) Delete(key []byte) error { panic("not supported") } +type StateLogger interface { + OnBalanceChange(addr common.Address, prev, new *big.Int) + 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) +} + // 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: @@ -63,6 +70,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState + logger StateLogger // originalRoot is the pre-state root, before any changes were made. // It will be updated when the Commit is called. @@ -161,6 +169,11 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return sdb, nil } +// TODO: move to New +func (s *StateDB) SetLogger(l StateLogger) { + s.logger = l +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 78f2c8b63daf..94e7b10b45c6 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -65,3 +65,23 @@ func (p *Printer) CaptureBlockStart(b *types.Block) { func (p *Printer) CaptureBlockEnd() { fmt.Printf("CaptureBlockEnd\n") } + +func (p *Printer) OnGenesisBlock(b *types.Block) { + fmt.Printf("OnGenesisBlock: b=%v\n", b.NumberU64()) +} + +func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int) { + 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=%v, codeHash=%v, code=%v\n", a, prevCodeHash, prev, codeHash, 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) +} diff --git a/les/client.go b/les/client.go index 0072eb8a1a4b..8cda91fc9dd0 100644 --- a/les/client.go +++ b/les/client.go @@ -97,7 +97,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if config.OverrideCancun != nil { overrides.OverrideCancun = config.OverrideCancun } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides, nil) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } From 84d643270889f1a0ee4e11325bd6a4a3f987aa6d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 22 Jun 2023 13:10:05 +0200 Subject: [PATCH 004/100] add log and newAccount hooks --- core/state/statedb.go | 10 ++++++++++ eth/tracers/printer.go | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0ef6e6e3447b..a7f1310b9863 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -58,6 +58,8 @@ type StateLogger interface { 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) + OnNewAccount(addr common.Address) } // StateDB structs within the ethereum protocol are used to store anything @@ -214,6 +216,9 @@ func (s *StateDB) AddLog(log *types.Log) { log.TxHash = s.thash log.TxIndex = uint(s.txIndex) log.Index = s.logSize + if s.logger != nil { + s.logger.OnLog(log) + } s.logs[s.thash] = append(s.logs[s.thash], log) s.logSize++ } @@ -669,6 +674,11 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) prevStorage: storage, }) } + // TODO: add isPrecompile check + // TODO: should we emit on account reset? + if s.logger != nil { + s.logger.OnNewAccount(addr) + } s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 94e7b10b45c6..e77df833651c 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -85,3 +85,11 @@ func (p *Printer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev 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) { + fmt.Printf("OnLog: l=%v\n", l) +} + +func (p *Printer) OnNewAccount(a common.Address) { + fmt.Printf("OnNewAccount: a=%v\n", a) +} From ee791b2b20e47bb1d55ed6e2b7119fce5b375136 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 23 Jun 2023 16:40:58 +0200 Subject: [PATCH 005/100] add gas consumption hook --- core/state_transition.go | 3 ++ core/vm/contract.go | 5 +++- core/vm/contracts.go | 5 +++- core/vm/contracts_test.go | 8 ++--- core/vm/evm.go | 12 ++++---- core/vm/instructions.go | 4 +-- core/vm/interpreter.go | 4 +-- core/vm/logger.go | 2 ++ core/vm/operations_acl.go | 2 +- eth/tracers/js/goja.go | 5 ++-- eth/tracers/logger/access_list_tracer.go | 2 ++ eth/tracers/logger/logger.go | 4 +++ eth/tracers/logger/logger_json.go | 2 ++ eth/tracers/native/4byte.go | 2 +- eth/tracers/native/call.go | 2 +- eth/tracers/native/call_flat.go | 2 +- eth/tracers/native/mux.go | 7 +++++ eth/tracers/native/prestate.go | 2 +- eth/tracers/{native => }/noop.go | 38 +++++++++++++----------- eth/tracers/printer.go | 4 +++ 20 files changed, 73 insertions(+), 42 deletions(-) rename eth/tracers/{native => }/noop.go (67%) diff --git a/core/state_transition.go b/core/state_transition.go index 022238c8d640..cce83ecf3c00 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -348,6 +348,9 @@ 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.OnGasConsumed(st.gasRemaining, gas) + } st.gasRemaining -= gas // Check clause 6 diff --git a/core/vm/contract.go b/core/vm/contract.go index bb0902969ec7..1d88b0e1b98b 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -159,10 +159,13 @@ 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) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger EVMLogger) (ok bool) { if c.Gas < gas { return false } + if logger != nil { + logger.OnGasConsumed(c.Gas, gas) + } c.Gas -= gas return true } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 6041be6c9f49..cb4cc76c02e9 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -168,11 +168,14 @@ 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) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger EVMLogger) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } + if logger != nil { + logger.OnGasConsumed(suppliedGas, gasCost) + } suppliedGas -= gasCost output, err := p.Run(input) return output, suppliedGas, err diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 5b1e874e91b4..6a17f5b7d54b 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -97,7 +97,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - if res, _, err := RunPrecompiledContract(p, in, gas); err != nil { + if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil { t.Error(err) } else if common.Bytes2Hex(res) != test.Expected { t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) @@ -119,7 +119,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { gas := p.RequiredGas(in) - 1 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(p, in, gas, nil) if err.Error() != "out of gas" { t.Errorf("Expected error [out of gas], got [%v]", err) } @@ -136,7 +136,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(test.Name, func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(p, in, gas, nil) if err.Error() != test.ExpectedError { t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) } @@ -168,7 +168,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { copy(data, in) - res, _, err = RunPrecompiledContract(p, data, reqGas) + res, _, err = RunPrecompiledContract(p, data, reqGas, nil) } bench.StopTimer() elapsed := uint64(time.Since(start)) diff --git a/core/vm/evm.go b/core/vm/evm.go index 36336d8cbd4c..30cfd2b9a8c1 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -222,7 +222,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -285,7 +285,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -330,7 +330,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -379,7 +379,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' @@ -480,7 +480,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) { + if contract.UseGas(createDataGas, evm.Config.Tracer) { evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas @@ -493,7 +493,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) + contract.UseGas(contract.Gas, evm.Config.Tracer) } } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index aaa12e436143..65f8ea1930e3 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -591,7 +591,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer) //TODO: use uint256.Int instead of converting with toBig() var bigVal = big0 if !value.IsZero() { @@ -634,7 +634,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] ) // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer) // reuse size int for stackvalue stackvalue := size //TODO: use uint256.Int instead of converting with toBig() diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 873337850e6f..14aa9cee2112 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -185,7 +185,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) { + if !contract.UseGas(cost, in.evm.Config.Tracer) { return nil, ErrOutOfGas } if operation.dynamicGas != nil { @@ -211,7 +211,7 @@ 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) { + if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer) { return nil, ErrOutOfGas } // Do tracing before memory expansion diff --git a/core/vm/logger.go b/core/vm/logger.go index d4b91ccc71a3..c4955d0c27ec 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -41,4 +41,6 @@ type EVMLogger interface { 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 + OnGasConsumed(gas, amount uint64) } diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 551e1f5f1188..92520972c47e 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -169,7 +169,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) { + if !contract.UseGas(coldCost, evm.Config.Tracer) { return 0, ErrOutOfGas } } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index ac8822e98f36..d6ac946feae7 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -95,6 +95,8 @@ 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 { + tracers.NoopTracer + vm *goja.Runtime env *vm.EVM toBig toBigFn // Converts a hex string into a JS bigint @@ -286,9 +288,6 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } } -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (t *jsTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - // CaptureEnd is called after the call finishes to finalize the tracing. func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { t.ctx["output"] = t.vm.ToValue(output) diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index c6a7bfddbe3c..316c1042780b 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -163,6 +163,8 @@ func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (*AccessListTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +func (*AccessListTracer) OnGasConsumed(gas, amount uint64) {} + func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 0c9ce9aec179..572e4e4c4bfc 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -220,6 +220,8 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +func (l *StructLogger) OnGasConsumed(gas, amount uint64) {} + // CaptureEnd is called after the call finishes to finalize the tracing. func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.output = output @@ -389,6 +391,8 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +func (t *mdLogger) OnGasConsumed(gas, amount uint64) {} + func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 91def6f38989..7237865ee311 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -81,6 +81,8 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +func (l *JSONLogger) OnGasConsumed(gas, amount uint64) {} + // CaptureEnd is triggered at end of execution. func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { type endLog struct { diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 5a2c4f91115f..0699ac887d7e 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -46,7 +46,7 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { - noopTracer + tracers.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 4ac03e512fb7..8e084ad37e5a 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -98,7 +98,7 @@ type callFrameMarshaling struct { } type callTracer struct { - noopTracer + tracers.NoopTracer callstack []callFrame config callTracerConfig gasLimit uint64 diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index ca5d2e6aec92..dedc01cf26a6 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -108,7 +108,7 @@ 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 { - noopTracer + tracers.NoopTracer tracer *callTracer config flatCallTracerConfig ctx *tracers.Context // Holds tracer context data diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 16ae47e5fa71..8680fdda3b01 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -93,6 +93,13 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { } } +// CaptureGasConsumed is called when gas is consumed. +func (t *muxTracer) OnGasConsumed(gas, amount uint64) { + for _, t := range t.tracers { + t.OnGasConsumed(gas, amount) + } +} + // 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) { for _, t := range t.tracers { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b71d5d62152d..78c76166e306 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -54,7 +54,7 @@ type accountMarshaling struct { } type prestateTracer struct { - noopTracer + tracers.NoopTracer env *vm.EVM pre state post state diff --git a/eth/tracers/native/noop.go b/eth/tracers/noop.go similarity index 67% rename from eth/tracers/native/noop.go rename to eth/tracers/noop.go index f60f3873a066..a22ff0c56c3d 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/noop.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package native +package tracers import ( "encoding/json" @@ -22,59 +22,61 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" ) func init() { - tracers.DefaultDirectory.Register("noopTracer", newNoopTracer, false) + DefaultDirectory.Register("noopTracer", newNoopTracer, false) } -// noopTracer is a go implementation of the Tracer interface which +// NoopTracer is a go implementation of the Tracer interface which // performs no action. It's mostly useful for testing purposes. -type noopTracer struct{} +type NoopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { - return &noopTracer{}, nil +func newNoopTracer(ctx *Context, _ json.RawMessage) (Tracer, error) { + return &NoopTracer{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) CaptureStart(env *vm.EVM, 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 *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // 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 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 *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *NoopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { } // CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (t *noopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + +// OnGasConsumed is called when gas is consumed. +func (t *NoopTracer) OnGasConsumed(gas, amount uint64) {} // 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 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 *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*noopTracer) CaptureTxStart(gasLimit uint64) {} +func (*NoopTracer) CaptureTxStart(gasLimit uint64) {} -func (*noopTracer) CaptureTxEnd(restGas uint64) {} +func (*NoopTracer) CaptureTxEnd(restGas uint64) {} // GetResult returns an empty json object. -func (t *noopTracer) GetResult() (json.RawMessage, error) { +func (t *NoopTracer) GetResult() (json.RawMessage, error) { return json.RawMessage(`{}`), nil } // Stop terminates execution of the tracer at the first opportune moment. -func (t *noopTracer) Stop(err error) { +func (t *NoopTracer) Stop(err error) { } diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index e77df833651c..65f749b684ee 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -93,3 +93,7 @@ func (p *Printer) OnLog(l *types.Log) { func (p *Printer) OnNewAccount(a common.Address) { fmt.Printf("OnNewAccount: a=%v\n", a) } + +func (p *Printer) OnGasConsumed(gas, amount uint64) { + fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount) +} From 0d25fbc37dbfbe7fca936d6ba22555f64dbc833a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 26 Jun 2023 11:21:27 +0200 Subject: [PATCH 006/100] pass logger to BC through vmConfig --- cmd/utils/flags.go | 8 ++++---- core/blockchain.go | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e9cbe7f189cd..5df88ce008ef 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2163,15 +2163,15 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} - + if ctx.IsSet(VMTraceFlag.Name) { + vmcfg.Tracer = tracers.NewPrinter() + } // Disable transaction indexing/unindexing by default. chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } - if ctx.IsSet(VMTraceFlag.Name) { - chain.SetLogger(tracers.NewPrinter()) - } + return chain, chainDb } diff --git a/core/blockchain.go b/core/blockchain.go index cfc6cc7c51af..becda25c4d17 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -265,6 +265,14 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } log.Info(strings.Repeat("-", 153)) log.Info("") + var logger BlockchainLogger + if vmConfig.Tracer != nil { + l, ok := vmConfig.Tracer.(BlockchainLogger) + if !ok { + return nil, fmt.Errorf("only extended tracers are supported for live mode") + } + logger = l + } bc := &BlockChain{ chainConfig: chainConfig, @@ -282,6 +290,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks), engine: engine, vmConfig: vmConfig, + logger: logger, } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) @@ -453,12 +462,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return bc, nil } -// TODO: need to move this to NewBlockchain to capture genesis block -func (bc *BlockChain) SetLogger(l BlockchainLogger) { - bc.logger = l - bc.vmConfig.Tracer = l -} - // empty returns an indicator whether the blockchain is empty. // Note, it's a special case that we connect a non-empty ancient // database with an empty node, so that we can plugin the ancient From 8db10784cbb8770b48d37d0c553e2966e0c32edc Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 26 Jun 2023 14:58:33 +0200 Subject: [PATCH 007/100] fix genesis logging --- cmd/utils/flags.go | 3 +++ core/blockchain.go | 18 +++++++++--------- eth/backend.go | 4 ++++ eth/ethconfig/config.go | 3 +++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5df88ce008ef..84820cfb3e2c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1741,6 +1741,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } + if ctx.IsSet(VMTraceFlag.Name) { + cfg.LiveTrace = ctx.Bool(VMTraceFlag.Name) + } if ctx.IsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) diff --git a/core/blockchain.go b/core/blockchain.go index becda25c4d17..f7af512435e7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -250,11 +250,19 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis Journal: cacheConfig.TrieCleanJournal, Preimages: cacheConfig.Preimages, }) + var logger BlockchainLogger + if vmConfig.Tracer != nil { + l, ok := vmConfig.Tracer.(BlockchainLogger) + if !ok { + return nil, fmt.Errorf("only extended tracers are supported for live mode") + } + logger = l + } // 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. // TODO: pass in blockchainLogger here to catch genesis block and allocs - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, nil) + chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, logger) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } @@ -265,14 +273,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } log.Info(strings.Repeat("-", 153)) log.Info("") - var logger BlockchainLogger - if vmConfig.Tracer != nil { - l, ok := vmConfig.Tracer.(BlockchainLogger) - if !ok { - return nil, fmt.Errorf("only extended tracers are supported for live mode") - } - logger = l - } bc := &BlockChain{ chainConfig: chainConfig, diff --git a/eth/backend.go b/eth/backend.go index b3338918be31..c8d9c165074d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -42,6 +42,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" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -192,6 +193,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Preimages: config.Preimages, } ) + if config.LiveTrace { + vmConfig.Tracer = tracers.NewPrinter() + } // 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 a98d9ee4aaff..c61cb2686103 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -147,6 +147,9 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool + // LiveTrace will enable tracing during normal chain processing. + LiveTrace bool + // Miscellaneous options DocRoot string `toml:"-"` From 788851b3e1e152a285a2b21701fb6859d1636dd1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 26 Jun 2023 16:48:24 +0200 Subject: [PATCH 008/100] disable tracing for miner processed txes --- miner/worker.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index d61f8dcada51..cf6fe41fa15d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -30,6 +30,7 @@ import ( "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/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -732,7 +733,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]* snap = env.state.Snapshot() gp = env.gasPool.Gas() ) - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.SetGas(gp) From 057bbdac10a243bfad45404fd1b225b0f7b74934 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 26 Jun 2023 16:56:28 +0200 Subject: [PATCH 009/100] add comments --- core/state/statedb.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index a7f1310b9863..dd80ff5975a7 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -53,6 +53,10 @@ func (n *proofList) Delete(key []byte) error { panic("not supported") } +// StateLogger is used to collect state update traces from EVM transaction +// execution. +// 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) OnNonceChange(addr common.Address, prev, new uint64) @@ -171,7 +175,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return sdb, nil } -// TODO: move to New +// SetLogger sets the logger for account update hooks. func (s *StateDB) SetLogger(l StateLogger) { s.logger = l } From a7de17ed2141eda8560449f5475a51993a08cc36 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 26 Jun 2023 17:39:10 +0200 Subject: [PATCH 010/100] only emit event for new accounts --- core/blockchain.go | 2 ++ core/state/statedb.go | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f7af512435e7..a5f122883bce 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -153,6 +153,8 @@ var defaultCacheConfig = &CacheConfig{ SnapshotWait: true, } +// 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 diff --git a/core/state/statedb.go b/core/state/statedb.go index dd80ff5975a7..67b6da597227 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -648,6 +648,10 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) newobj = newObject(s, addr, types.StateAccount{}) if prev == nil { s.journal.append(createObjectChange{account: &addr}) + // TODO: add isPrecompile check + if s.logger != nil { + s.logger.OnNewAccount(addr) + } } else { // The original account should be marked as destructed and all cached // account and storage data should be cleared as well. Note, it must @@ -678,11 +682,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) prevStorage: storage, }) } - // TODO: add isPrecompile check - // TODO: should we emit on account reset? - if s.logger != nil { - s.logger.OnNewAccount(addr) - } + s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev From 378781654fee04ffe66a68034e8ff4af7519457d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Jun 2023 13:28:53 +0200 Subject: [PATCH 011/100] Upgrade TxStart and TxEnd hooks --- cmd/evm/internal/t8ntool/execution.go | 2 + core/state_processor.go | 6 ++ core/state_transition.go | 7 -- core/vm/logger.go | 5 +- eth/api_backend.go | 2 +- eth/state_accessor.go | 4 +- eth/tracers/api.go | 87 ++++++++++++++++--- eth/tracers/api_test.go | 4 +- .../internal/tracetest/calltrace_test.go | 45 ++++++---- .../internal/tracetest/flat_calltrace_test.go | 7 +- .../internal/tracetest/prestate_test.go | 6 +- eth/tracers/js/goja.go | 9 +- eth/tracers/js/tracer_test.go | 5 +- eth/tracers/logger/access_list_tracer.go | 4 +- eth/tracers/logger/logger.go | 23 +++-- eth/tracers/logger/logger_json.go | 5 +- eth/tracers/native/call.go | 9 +- eth/tracers/native/call_flat.go | 9 +- eth/tracers/native/mux.go | 9 +- eth/tracers/native/prestate.go | 7 +- eth/tracers/noop.go | 5 +- eth/tracers/printer.go | 8 +- les/api_backend.go | 2 +- les/state_accessor.go | 4 +- 24 files changed, 181 insertions(+), 93 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5633198d396e..f8652b485049 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -183,6 +183,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) + tracer.CaptureTxStart(tx) // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { @@ -231,6 +232,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) + tracer.CaptureTxEnd(receipt) } txIndex++ diff --git a/core/state_processor.go b/core/state_processor.go index e72cea359b99..ab94e7f2902a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -87,7 +87,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) + if vmenv.Config.Tracer != nil { + vmenv.Config.Tracer.CaptureTxStart(tx) + } receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + if vmenv.Config.Tracer != nil { + vmenv.Config.Tracer.CaptureTxEnd(receipt) + } if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } diff --git a/core/state_transition.go b/core/state_transition.go index cce83ecf3c00..87772b7b96bb 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -326,13 +326,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - if tracer := st.evm.Config.Tracer; tracer != nil { - tracer.CaptureTxStart(st.initialGas) - defer func() { - tracer.CaptureTxEnd(st.gasRemaining) - }() - } - var ( msg = st.msg sender = vm.AccountRef(msg.From) diff --git a/core/vm/logger.go b/core/vm/logger.go index c4955d0c27ec..4f67b87d1592 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -20,6 +20,7 @@ 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 @@ -29,8 +30,8 @@ import ( // if you need to retain them beyond the current call. type EVMLogger interface { // Transaction level - CaptureTxStart(gasLimit uint64) - CaptureTxEnd(restGas uint64) + CaptureTxStart(tx *types.Transaction) + CaptureTxEnd(receipt *types.Receipt) // Top call frame CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) CaptureEnd(output []byte, gasUsed uint64, err error) diff --git a/eth/api_backend.go b/eth/api_backend.go index 927dcdef1042..18aea2d039ae 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -414,6 +414,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 1b0ab0c54509..83c4ca1f336e 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -189,7 +189,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") @@ -216,7 +216,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 5e90180df8d5..e4c3bb2cb439 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -23,6 +23,7 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "os" "runtime" "sync" @@ -87,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. @@ -277,7 +278,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) @@ -612,7 +613,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 } @@ -655,7 +656,7 @@ 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) + 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 @@ -789,7 +790,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) - _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + vmConf.Tracer.CaptureTxStart(tx) + vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) if writer != nil { writer.Flush() } @@ -846,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 := &Context{ BlockHash: blockHash, @@ -858,7 +865,7 @@ 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 @@ -912,18 +919,21 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc 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(Context), vmctx, statedb, traceConfig) + return api.traceTx(ctx, tx, msg, new(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 *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 *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { var ( tracer Tracer err error @@ -962,9 +972,13 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte // 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 { + tracer.CaptureTxStart(tx) + res, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)) + if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } + r := &types.Receipt{GasUsed: res.UsedGas} + tracer.CaptureTxEnd(r) return tracer.GetResult() } @@ -1023,3 +1037,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 fdb02b18950e..33bed6554a88 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -156,7 +156,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 @@ -175,7 +175,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 { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index bf1c31c08ddb..695480f86b1e 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -18,6 +18,7 @@ package tracetest import ( "encoding/json" + "fmt" "math/big" "os" "path/filepath" @@ -31,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "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" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -148,10 +150,12 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } + tracer.CaptureTxStart(tx) 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}) // Retrieve the trace result and compare against the expected. res, err := tracer.GetResult() if err != nil { @@ -261,8 +265,12 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { func TestInternals(t *testing.T) { var ( + config = params.AllEthashProtocolChanges to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") - origin = common.HexToAddress("0x00000000000000000000000000000000feed") + originHex = "0x71562b71999873db5b286df957af199ec94617f7" + origin = common.HexToAddress(originHex) + signer = types.LatestSigner(config) + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") txContext = vm.TxContext{ Origin: origin, GasPrice: big.NewInt(1), @@ -302,13 +310,13 @@ func TestInternals(t *testing.T) { byte(vm.CALL), }, tracer: mkTracer("callTracer", nil), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, originHex), }, { name: "Stack depletion in LOG0", code: []byte{byte(vm.LOG3)}, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, originHex), }, { name: "Mem expansion in LOG0", @@ -321,7 +329,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, originHex), }, { // Leads to OOM on the prestate tracer @@ -340,7 +348,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52640350"}}`, originHex), }, } { _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), @@ -353,20 +361,25 @@ func TestInternals(t *testing.T) { }, }, false) evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) - msg := &core.Message{ - To: &to, - From: origin, - Value: big.NewInt(0), - GasLimit: 50000, - GasPrice: big.NewInt(0), - GasFeeCap: big.NewInt(0), - GasTipCap: big.NewInt(0), - SkipAccountChecks: false, + tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ + To: &to, + Value: big.NewInt(0), + Gas: 50000, + GasPrice: big.NewInt(0), + }) + if err != nil { + t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) - if _, err := st.TransitionDb(); err != nil { + 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(tx) + 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}) // 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 85e95401a215..dc3cdde26173 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -113,11 +113,12 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - - if _, err = st.TransitionDb(); err != nil { + tracer.CaptureTxStart(tx) + 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}) // 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 991da10b3ab1..93839ef3beab 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -119,10 +119,12 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { + tracer.CaptureTxStart(tx) + 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}) // 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 d6ac946feae7..2d086a8157cd 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -23,6 +23,7 @@ import ( "math/big" "github.com/dop251/goja" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -214,14 +215,14 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer // CaptureTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *jsTracer) CaptureTxStart(tx *types.Transaction) { + t.gasLimit = tx.Gas() } // CaptureTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. -func (t *jsTracer) CaptureTxEnd(restGas uint64) { - t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas) +func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt) { + t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) } // CaptureStart implements the Tracer interface to initialize the tracing operation. diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index bf6427faf673..0031b0cb3c17 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -26,6 +26,7 @@ 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/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/params" @@ -73,12 +74,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon contract.Code = contractCode } - tracer.CaptureTxStart(gasLimit) + tracer.CaptureTxStart(types.NewTx(&types.LegacyTx{Gas: gasLimit})) tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, err) // Rest gas assumes no refund - tracer.CaptureTxEnd(contract.Gas) + tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}) if err != nil { return nil, err } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 316c1042780b..89692591cfa7 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -172,9 +172,9 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(gasLimit uint64) {} +func (*AccessListTracer) CaptureTxStart(tx *types.Transaction) {} -func (*AccessListTracer) CaptureTxEnd(restGas uint64) {} +func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt) {} // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 572e4e4c4bfc..709fe6462991 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -109,12 +109,11 @@ type StructLogger struct { cfg Config env *vm.EVM - storage map[common.Address]Storage - logs []StructLog - output []byte - err error - gasLimit uint64 - usedGas uint64 + storage map[common.Address]Storage + logs []StructLog + output []byte + err error + usedGas uint64 interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -266,12 +265,10 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(gasLimit uint64) { - l.gasLimit = gasLimit -} +func (l *StructLogger) CaptureTxStart(tx *types.Transaction) {} -func (l *StructLogger) CaptureTxEnd(restGas uint64) { - l.usedGas = l.gasLimit - restGas +func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) { + l.usedGas = receipt.GasUsed } // StructLogs returns the captured log entries. @@ -403,9 +400,9 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*mdLogger) CaptureTxStart(gasLimit uint64) {} +func (*mdLogger) CaptureTxStart(tx *types.Transaction) {} -func (*mdLogger) CaptureTxEnd(restGas uint64) {} +func (*mdLogger) CaptureTxEnd(receipt *types.Receipt) {} // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 7237865ee311..f91ef2bb4be5 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -102,6 +103,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {} +func (l *JSONLogger) CaptureTxStart(tx *types.Transaction) {} -func (l *JSONLogger) CaptureTxEnd(restGas uint64) {} +func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt) {} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 8e084ad37e5a..a3b3fb788ce4 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -25,6 +25,7 @@ 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/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -233,12 +234,12 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *callTracer) CaptureTxStart(tx *types.Transaction) { + t.gasLimit = tx.Gas() } -func (t *callTracer) CaptureTxEnd(restGas uint64) { - t.callstack[0].GasUsed = t.gasLimit - restGas +func (t *callTracer) CaptureTxEnd(receipt *types.Receipt) { + t.callstack[0].GasUsed = receipt.GasUsed if t.config.WithLog { // Logs are not emitted when the call fails clearFailedLogs(&t.callstack[0], false) diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index dedc01cf26a6..51183cff6f62 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" ) @@ -202,12 +203,12 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *flatCallTracer) CaptureTxStart(gasLimit uint64) { - t.tracer.CaptureTxStart(gasLimit) +func (t *flatCallTracer) CaptureTxStart(tx *types.Transaction) { + t.tracer.CaptureTxStart(tx) } -func (t *flatCallTracer) CaptureTxEnd(restGas uint64) { - t.tracer.CaptureTxEnd(restGas) +func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt) { + t.tracer.CaptureTxEnd(receipt) } // GetResult returns an empty json object. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 8680fdda3b01..583930ed7783 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -21,6 +21,7 @@ import ( "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" ) @@ -115,15 +116,15 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *muxTracer) CaptureTxStart(gasLimit uint64) { +func (t *muxTracer) CaptureTxStart(tx *types.Transaction) { for _, t := range t.tracers { - t.CaptureTxStart(gasLimit) + t.CaptureTxStart(tx) } } -func (t *muxTracer) CaptureTxEnd(restGas uint64) { +func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt) { for _, t := range t.tracers { - t.CaptureTxEnd(restGas) + t.CaptureTxEnd(receipt) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 78c76166e306..e9ca93b0a492 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "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" @@ -174,11 +175,11 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit +func (t *prestateTracer) CaptureTxStart(tx *types.Transaction) { + t.gasLimit = tx.Gas() } -func (t *prestateTracer) CaptureTxEnd(restGas uint64) { +func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt) { if !t.config.DiffMode { return } diff --git a/eth/tracers/noop.go b/eth/tracers/noop.go index a22ff0c56c3d..d15e1b23a950 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/noop.go @@ -21,6 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -68,9 +69,9 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*NoopTracer) CaptureTxStart(gasLimit uint64) {} +func (*NoopTracer) CaptureTxStart(tx *types.Transaction) {} -func (*NoopTracer) CaptureTxEnd(restGas uint64) {} +func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {} // GetResult returns an empty json object. func (t *NoopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 65f749b684ee..50e6ec58ab9b 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -49,13 +49,13 @@ func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) { fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err) } -func (p *Printer) CaptureTxStart(gasLimit uint64) { - fmt.Printf("CaptureTxStart: gasLimit=%v\n", gasLimit) +func (p *Printer) CaptureTxStart(tx *types.Transaction) { + fmt.Printf("CaptureTxStart: tx=%v\n", tx) } -func (p *Printer) CaptureTxEnd(restGas uint64) { - fmt.Printf("CaptureTxEnd: restGas=%v\n", restGas) +func (p *Printer) CaptureTxEnd(receipt *types.Receipt) { + fmt.Printf("CaptureTxEnd: receipt=%v\n", receipt) } func (p *Printer) CaptureBlockStart(b *types.Block) { diff --git a/les/api_backend.go b/les/api_backend.go index 97665757b19a..30b8743ac1f7 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -333,6 +333,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 9a8214ac2f8f..a9c8e2dea852 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{}) From 3975c7cfcc0e666827e000ff78afebcefcb90aaf Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Jun 2023 14:54:08 +0200 Subject: [PATCH 012/100] minor --- core/state_processor.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index ab94e7f2902a..d306d68cf915 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -87,9 +87,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - if vmenv.Config.Tracer != nil { - vmenv.Config.Tracer.CaptureTxStart(tx) - } + receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if vmenv.Config.Tracer != nil { vmenv.Config.Tracer.CaptureTxEnd(receipt) @@ -112,6 +110,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { + var receipt *types.Receipt + if evm.Config.Tracer != nil { + evm.Config.Tracer.CaptureTxStart(tx) + defer func() { + evm.Config.Tracer.CaptureTxEnd(receipt) + }() + } // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -133,7 +138,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta // Create a new receipt for the transaction, storing the intermediate root and gas used // by the tx. - receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} + receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} if result.Failed() { receipt.Status = types.ReceiptStatusFailed } else { From 619ac2948c27d8b8c309f31d2e3b5dad6401a355 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Jun 2023 18:00:44 +0200 Subject: [PATCH 013/100] provide StateLogger for short-lived tracers --- eth/tracers/api.go | 1 + .../internal/tracetest/calltrace_test.go | 2 + .../internal/tracetest/flat_calltrace_test.go | 1 + .../internal/tracetest/prestate_test.go | 1 + eth/tracers/logger/access_list_tracer.go | 13 ++++ eth/tracers/logger/logger.go | 26 ++++++++ eth/tracers/logger/logger_json.go | 13 ++++ eth/tracers/native/call.go | 62 ++++++------------- eth/tracers/native/mux.go | 36 +++++++++++ eth/tracers/noop.go | 13 ++++ eth/tracers/tracers.go | 8 ++- 11 files changed, 132 insertions(+), 44 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index e4c3bb2cb439..479ca58de637 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -952,6 +952,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } } vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) + statedb.SetLogger(tracer) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 695480f86b1e..8dbcacb3bc72 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -145,6 +145,7 @@ 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) if err != nil { @@ -360,6 +361,7 @@ func TestInternals(t *testing.T) { Balance: big.NewInt(500000000000000), }, }, false) + statedb.SetLogger(tc.tracer) evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ To: &to, diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index dc3cdde26173..4f191b1487d8 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -107,6 +107,7 @@ 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) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 93839ef3beab..8f6edd8e80c5 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -114,6 +114,7 @@ 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) if err != nil { diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 89692591cfa7..3f98de306dec 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -176,6 +176,19 @@ func (*AccessListTracer) CaptureTxStart(tx *types.Transaction) {} func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt) {} +func (*AccessListTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {} + +func (*AccessListTracer) OnNonceChange(a common.Address, prev, new uint64) {} + +func (*AccessListTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (*AccessListTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {} + +func (*AccessListTracer) OnLog(log *types.Log) {} + +func (*AccessListTracer) OnNewAccount(a common.Address) {} + // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 709fe6462991..b06e8d0d0304 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -271,6 +271,19 @@ func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) { l.usedGas = receipt.GasUsed } +func (l *StructLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} + +func (l *StructLogger) OnNonceChange(a common.Address, prev, new uint64) {} + +func (l *StructLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (l *StructLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} + +func (l *StructLogger) OnLog(log *types.Log) {} + +func (l *StructLogger) OnNewAccount(a common.Address) {} + // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -404,6 +417,19 @@ func (*mdLogger) CaptureTxStart(tx *types.Transaction) {} func (*mdLogger) CaptureTxEnd(receipt *types.Receipt) {} +func (*mdLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} + +func (*mdLogger) OnNonceChange(a common.Address, prev, new uint64) {} + +func (*mdLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (*mdLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} + +func (*mdLogger) OnLog(log *types.Log) {} + +func (*mdLogger) OnNewAccount(a common.Address) {} + // 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/logger/logger_json.go b/eth/tracers/logger/logger_json.go index f91ef2bb4be5..99620a9f1699 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -106,3 +106,16 @@ func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} func (l *JSONLogger) CaptureTxStart(tx *types.Transaction) {} func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt) {} + +func (*JSONLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} + +func (*JSONLogger) OnNonceChange(a common.Address, prev, new uint64) {} + +func (*JSONLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (*JSONLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} + +func (*JSONLogger) OnLog(log *types.Log) {} + +func (*JSONLogger) OnNewAccount(a common.Address) {} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index a3b3fb788ce4..f3a6eca1bbe2 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -103,6 +103,7 @@ type callTracer struct { callstack []callFrame config callTracerConfig gasLimit uint64 + depth int interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } @@ -149,51 +150,11 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { // 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) { - // skip if the previous op caused an error - if err != nil { - return - } - // Only logs need to be captured via opcode processing - if !t.config.WithLog { - return - } - // Avoid processing nested calls when only caring about top call - if t.config.OnlyTopCall && depth > 0 { - return - } - // Skip if tracing was interrupted - if t.interrupt.Load() { - return - } - switch op { - case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: - size := int(op - vm.LOG0) - - stack := scope.Stack - stackData := stack.Data() - - // Don't modify the stack - mStart := stackData[len(stackData)-1] - mSize := stackData[len(stackData)-2] - topics := make([]common.Hash, size) - for i := 0; i < size; i++ { - topic := stackData[len(stackData)-2-(i+1)] - topics[i] = common.Hash(topic.Bytes32()) - } - - data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) - if err != nil { - // mSize was unrealistically large - return - } - - log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)} - t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log) - } } // 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) { + t.depth++ if t.config.OnlyTopCall { return } @@ -217,6 +178,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. // CaptureExit 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) { + t.depth-- if t.config.OnlyTopCall { return } @@ -246,6 +208,22 @@ func (t *callTracer) CaptureTxEnd(receipt *types.Receipt) { } } +func (t *callTracer) OnLog(log *types.Log) { + // Only logs need to be captured via opcode processing + if !t.config.WithLog { + return + } + // Avoid processing nested calls when only caring about top call + if t.config.OnlyTopCall && t.depth > 0 { + return + } + // Skip if tracing was interrupted + if t.interrupt.Load() { + return + } + t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, callLog{Address: log.Address, Topics: log.Topics, Data: log.Data}) +} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *callTracer) GetResult() (json.RawMessage, error) { @@ -257,7 +235,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { if err != nil { return nil, err } - return json.RawMessage(res), t.reason + return res, t.reason } // Stop terminates execution of the tracer at the first opportune moment. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 583930ed7783..9abbea31527c 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -128,6 +128,42 @@ func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt) { } } +func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int) { + for _, t := range t.tracers { + t.OnBalanceChange(a, prev, new) + } +} + +func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) { + for _, t := range t.tracers { + 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) + } +} + +func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { + for _, t := range t.tracers { + t.OnStorageChange(a, k, prev, new) + } +} + +func (t *muxTracer) OnLog(log *types.Log) { + for _, t := range t.tracers { + t.OnLog(log) + } +} + +func (t *muxTracer) OnNewAccount(a common.Address) { + for _, t := range t.tracers { + t.OnNewAccount(a) + } +} + // GetResult returns an empty json object. func (t *muxTracer) GetResult() (json.RawMessage, error) { resObject := make(map[string]json.RawMessage) diff --git a/eth/tracers/noop.go b/eth/tracers/noop.go index d15e1b23a950..082717c3fe25 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/noop.go @@ -73,6 +73,19 @@ func (*NoopTracer) CaptureTxStart(tx *types.Transaction) {} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {} +func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {} + +func (*NoopTracer) OnNonceChange(a common.Address, prev, new uint64) {} + +func (*NoopTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (*NoopTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {} + +func (*NoopTracer) OnLog(log *types.Log) {} + +func (*NoopTracer) OnNewAccount(a common.Address) {} + // GetResult returns an empty json object. func (t *NoopTracer) GetResult() (json.RawMessage, error) { return json.RawMessage(`{}`), nil diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 7b43b7cf834a..c82fcf92acea 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -24,6 +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" ) @@ -36,10 +37,13 @@ type Context struct { TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) } -// Tracer interface extends vm.EVMLogger and additionally -// allows collecting the tracing result. +// The set of methods that must be exposed by a tracer +// 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) // Stop terminates execution of the tracer at the first opportune moment. Stop(err error) From 54171ee4a8b89daac1ae9441eeb32027ab421d57 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 28 Jun 2023 21:58:38 +0200 Subject: [PATCH 014/100] pass env in TxStart --- core/state_processor.go | 2 +- core/vm/evm.go | 6 +-- core/vm/logger.go | 4 +- eth/tracers/api.go | 4 +- .../internal/tracetest/calltrace_test.go | 23 ++++---- .../internal/tracetest/flat_calltrace_test.go | 2 +- .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/goja.go | 25 +++++---- eth/tracers/logger/access_list_tracer.go | 4 +- eth/tracers/logger/logger.go | 12 ++--- eth/tracers/logger/logger_json.go | 7 +-- eth/tracers/native/4byte.go | 13 +++-- eth/tracers/native/call.go | 4 +- eth/tracers/native/call_flat.go | 14 ++--- eth/tracers/native/mux.go | 8 +-- eth/tracers/native/prestate.go | 53 +++++++++---------- eth/tracers/noop.go | 4 +- eth/tracers/printer.go | 4 +- 18 files changed, 97 insertions(+), 94 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index d306d68cf915..d2f1505403cf 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -112,7 +112,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { var receipt *types.Receipt if evm.Config.Tracer != nil { - evm.Config.Tracer.CaptureTxStart(tx) + evm.Config.Tracer.CaptureTxStart(evm, tx) defer func() { evm.Config.Tracer.CaptureTxEnd(receipt) }() diff --git a/core/vm/evm.go b/core/vm/evm.go index 30cfd2b9a8c1..26ad3b444e20 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -192,7 +192,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Calling a non existing account, don't do anything, but ping the tracer if debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureEnd(ret, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -208,7 +208,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Capture the tracer start/end events in debug mode if debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) defer func(startGas uint64) { // Lazy evaluation of the parameters evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) }(gas) @@ -456,7 +456,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Tracer != nil { if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) + evm.Config.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) } else { evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 4f67b87d1592..b7b0fc4d8e20 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -30,10 +30,10 @@ import ( // if you need to retain them beyond the current call. type EVMLogger interface { // Transaction level - CaptureTxStart(tx *types.Transaction) + CaptureTxStart(evm *EVM, tx *types.Transaction) CaptureTxEnd(receipt *types.Receipt) // Top call frame - CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) + CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) CaptureEnd(output []byte, gasUsed uint64, err error) // Rest of call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 479ca58de637..7df7e7526af5 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -790,7 +790,7 @@ 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(tx) + vmConf.Tracer.CaptureTxStart(vmenv, tx) vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) if writer != nil { @@ -973,7 +973,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - tracer.CaptureTxStart(tx) + tracer.CaptureTxStart(vmenv, tx) res, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)) if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 8dbcacb3bc72..dd33469edfcd 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -151,7 +151,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(tx) + tracer.CaptureTxStart(evm, tx) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { t.Fatalf("failed to execute transaction: %v", err) @@ -266,17 +266,13 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { func TestInternals(t *testing.T) { var ( - config = params.AllEthashProtocolChanges + config = params.MainnetChainConfig to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") originHex = "0x71562b71999873db5b286df957af199ec94617f7" origin = common.HexToAddress(originHex) signer = types.LatestSigner(config) key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - txContext = vm.TxContext{ - Origin: origin, - GasPrice: big.NewInt(1), - } - context = vm.BlockContext{ + context = vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, Coinbase: common.Address{}, @@ -284,6 +280,7 @@ func TestInternals(t *testing.T) { Time: 5, Difficulty: big.NewInt(0x30000), GasLimit: uint64(6000000), + BaseFee: new(big.Int), } ) mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer { @@ -349,7 +346,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)), - want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52640350"}}`, originHex), + want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, } { _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), @@ -362,21 +359,25 @@ func TestInternals(t *testing.T) { }, }, false) statedb.SetLogger(tc.tracer) - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ To: &to, Value: big.NewInt(0), Gas: 50000, - GasPrice: big.NewInt(0), + GasPrice: new(big.Int), }) if err != nil { t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } + txContext := vm.TxContext{ + Origin: origin, + GasPrice: tx.GasPrice(), + } + evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer}) 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(tx) + tc.tracer.CaptureTxStart(evm, tx) 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 4f191b1487d8..dac3ef06cf84 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -114,7 +114,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(tx) + tracer.CaptureTxStart(evm, tx) 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 8f6edd8e80c5..9366bc418fb2 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -120,7 +120,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(tx) + tracer.CaptureTxStart(evm, tx) 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/goja.go b/eth/tracers/js/goja.go index 2d086a8157cd..e4a06195f892 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -107,7 +107,6 @@ type jsTracer struct { activePrecompiles []common.Address // List of active precompiles at current block traceStep bool // True if tracer object exposes a `step()` method traceFrame bool // True if tracer object exposes the `enter()` and `exit()` methods - gasLimit uint64 // Amount of gas bought for the whole tx err error // Any error that should stop tracing obj *goja.Object // Trace object @@ -215,8 +214,17 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer // CaptureTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(tx *types.Transaction) { - t.gasLimit = tx.Gas() +func (t *jsTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + 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) + t.activePrecompiles = vm.ActivePrecompiles(rules) + t.ctx["block"] = t.vm.ToValue(t.env.Context.BlockNumber.Uint64()) + t.ctx["gasPrice"] = t.vm.ToValue(t.env.TxContext.GasPrice) + t.ctx["gas"] = t.vm.ToValue(tx.Gas()) } // CaptureTxEnd implements the Tracer interface and is invoked at the end of @@ -226,10 +234,7 @@ func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt) { } // CaptureStart implements the Tracer interface to initialize the tracing operation. -func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env - db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} - t.dbValue = db.setupObject() +func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { if create { t.ctx["type"] = t.vm.ToValue("CREATE") } else { @@ -238,18 +243,12 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr t.ctx["from"] = t.vm.ToValue(from.Bytes()) t.ctx["to"] = t.vm.ToValue(to.Bytes()) t.ctx["input"] = t.vm.ToValue(input) - t.ctx["gas"] = t.vm.ToValue(t.gasLimit) - t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) valueBig, err := t.toBig(t.vm, value.String()) if err != nil { t.err = err return } t.ctx["value"] = valueBig - t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64()) - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) } // CaptureState implements the Tracer interface to trace a single step of VM execution. diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 3f98de306dec..c5d3ec329997 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -132,7 +132,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (a *AccessListTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. @@ -172,7 +172,7 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*AccessListTracer) CaptureTxStart(tx *types.Transaction) {} +func (*AccessListTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt) {} diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index b06e8d0d0304..d1d995424eec 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -139,8 +139,7 @@ func (l *StructLogger) Reset() { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - l.env = env +func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } // CaptureState logs a new structured log message and pushes it out to the environment @@ -265,7 +264,9 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(tx *types.Transaction) {} +func (l *StructLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + l.env = env +} func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) { l.usedGas = receipt.GasUsed @@ -356,8 +357,7 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env +func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { if !create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", from.String(), to.String(), @@ -413,7 +413,7 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (*mdLogger) CaptureTxStart(tx *types.Transaction) {} +func (*mdLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} func (*mdLogger) CaptureTxEnd(receipt *types.Receipt) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 99620a9f1699..845549b63b88 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -43,8 +43,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - l.env = env +func (l *JSONLogger) CaptureStart(from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { } func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { @@ -103,7 +102,9 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} -func (l *JSONLogger) CaptureTxStart(tx *types.Transaction) {} +func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + l.env = env +} func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 0699ac887d7e..25152a098eb2 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -23,6 +23,7 @@ import ( "sync/atomic" "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" ) @@ -47,6 +48,7 @@ func init() { // } type fourByteTracer struct { tracers.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 @@ -78,13 +80,16 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + t.env = env // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + rules := t.env.ChainConfig().Rules(t.env.Context.BlockNumber, t.env.Context.Random != nil, t.env.Context.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) +} - // Save the outer calldata also +// 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) } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index f3a6eca1bbe2..87a7bbf95834 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -128,7 +128,7 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +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, @@ -196,7 +196,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(tx *types.Transaction) { +func (t *callTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { t.gasLimit = tx.Gas() } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 51183cff6f62..9e07c2515519 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -146,11 +146,8 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *flatCallTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.tracer.CaptureStart(env, from, to, create, input, gas, value) - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) +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. @@ -203,8 +200,11 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *flatCallTracer) CaptureTxStart(tx *types.Transaction) { - t.tracer.CaptureTxStart(tx) +func (t *flatCallTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + t.tracer.CaptureTxStart(env, tx) + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + t.activePrecompiles = vm.ActivePrecompiles(rules) } func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt) { diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 9abbea31527c..3d41a1ebebea 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -60,9 +60,9 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, er } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +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(env, from, to, create, input, gas, value) + t.CaptureStart(from, to, create, input, gas, value) } } @@ -116,9 +116,9 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *muxTracer) CaptureTxStart(tx *types.Transaction) { +func (t *muxTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { for _, t := range t.tracers { - t.CaptureTxStart(tx) + t.CaptureTxStart(env, tx) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index e9ca93b0a492..63536db1a724 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -19,6 +19,7 @@ package native import ( "bytes" "encoding/json" + "fmt" "math/big" "sync/atomic" @@ -61,7 +62,6 @@ type prestateTracer struct { post state create bool to common.Address - gasLimit uint64 // Amount of gas bought for the whole tx config prestateTracerConfig interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -90,31 +90,7 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env - t.create = create - t.to = to - - t.lookupAccount(from) - t.lookupAccount(to) - t.lookupAccount(env.Context.Coinbase) - - // The recipient balance includes the value transferred. - toBal := new(big.Int).Sub(t.pre[to].Balance, value) - t.pre[to].Balance = toBal - - // The sender balance is after reducing: value and gasLimit. - // We need to re-add them to get the pre-tx balance. - fromBal := new(big.Int).Set(t.pre[from].Balance) - gasPrice := env.TxContext.GasPrice - consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) - fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) - t.pre[from].Balance = fromBal - t.pre[from].Nonce-- - - if create && t.config.DiffMode { - t.created[to] = true - } +func (t *prestateTracer) 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. @@ -175,8 +151,29 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -func (t *prestateTracer) CaptureTxStart(tx *types.Transaction) { - t.gasLimit = tx.Gas() +func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { + t.env = env + signer := types.MakeSigner(env.ChainConfig(), env.Context.BlockNumber, env.Context.Time) + from, err := types.Sender(signer, tx) + if err != nil { + t.Stop(fmt.Errorf("could not recover sender address: %v", err)) + return + } + if tx.To() == nil { + t.create = true + t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) + } else { + t.to = *tx.To() + t.create = false + } + + t.lookupAccount(from) + t.lookupAccount(t.to) + t.lookupAccount(env.Context.Coinbase) + + if t.create && t.config.DiffMode { + t.created[t.to] = true + } } func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt) { diff --git a/eth/tracers/noop.go b/eth/tracers/noop.go index 082717c3fe25..e33570d9019e 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/noop.go @@ -39,7 +39,7 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (Tracer, error) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *NoopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +func (t *NoopTracer) 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. @@ -69,7 +69,7 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*NoopTracer) CaptureTxStart(tx *types.Transaction) {} +func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {} diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 50e6ec58ab9b..15060cf7578a 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -16,7 +16,7 @@ func NewPrinter() *Printer { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (p *Printer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +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=%v, gas=%v, value=%v\n", from, to, create, input, gas, value) } @@ -49,7 +49,7 @@ func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) { fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err) } -func (p *Printer) CaptureTxStart(tx *types.Transaction) { +func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { fmt.Printf("CaptureTxStart: tx=%v\n", tx) } From 3cabef4c66575f641858ff5ce63120288f1cab44 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 30 Jun 2023 15:29:38 +0200 Subject: [PATCH 015/100] capture block end errors --- core/blockchain.go | 8 ++++++-- core/state_processor.go | 21 ++++++++++++++++----- eth/tracers/printer.go | 12 ++++++++---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index a5f122883bce..a3c2fa648437 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -158,8 +158,9 @@ var defaultCacheConfig = &CacheConfig{ type BlockchainLogger interface { vm.EVMLogger state.StateLogger - CaptureBlockStart(*types.Block) - CaptureBlockEnd() + OnBlockStart(*types.Block) + OnBlockEnd(td *big.Int, err error) + OnBlockValidationError(block *types.Block, err error) OnGenesisBlock(*types.Block) } @@ -1785,6 +1786,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) followupInterrupt.Store(true) + if bc.logger != nil { + bc.logger.OnBlockValidationError(block, err) + } return it.index, err } vtime := time.Since(vstart) diff --git a/core/state_processor.go b/core/state_processor.go index d2f1505403cf..5e1bceb9f78d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -66,10 +66,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockNumber = block.Number() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) + err error ) if p.bc.logger != nil { - p.bc.logger.CaptureBlockStart(block) - defer p.bc.logger.CaptureBlockEnd() + p.bc.logger.OnBlockStart(block) + defer func() { + var td *big.Int + if err == nil { + td = p.bc.GetTd(block.ParentHash(), block.NumberU64()-1) + td.Add(td, block.Difficulty()) + } + p.bc.logger.OnBlockEnd(td, err) + }() } // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { @@ -82,13 +90,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - msg, err := TransactionToMessage(tx, signer, header.BaseFee) + var msg *Message + msg, err = TransactionToMessage(tx, signer, header.BaseFee) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + var receipt *types.Receipt + receipt, err = applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if vmenv.Config.Tracer != nil { vmenv.Config.Tracer.CaptureTxEnd(receipt) } @@ -101,7 +111,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Fail if Shanghai not enabled and len(withdrawals) is non-zero. withdrawals := block.Withdrawals() if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) { - return nil, nil, 0, errors.New("withdrawals before shanghai") + err = errors.New("withdrawals before shanghai") + return nil, nil, 0, err } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 15060cf7578a..42855de9bd3c 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -58,12 +58,16 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt) { fmt.Printf("CaptureTxEnd: receipt=%v\n", receipt) } -func (p *Printer) CaptureBlockStart(b *types.Block) { - fmt.Printf("CaptureBlockStart: b=%v\n", b.NumberU64()) +func (p *Printer) OnBlockStart(b *types.Block) { + fmt.Printf("OnBlockStart: b=%v\n", b.NumberU64()) } -func (p *Printer) CaptureBlockEnd() { - fmt.Printf("CaptureBlockEnd\n") +func (p *Printer) OnBlockEnd(td *big.Int, err error) { + fmt.Printf("OnBlockEnd: td=%v, err=%v\n", td, err) +} + +func (p *Printer) OnBlockValidationError(block *types.Block, err error) { + fmt.Printf("OnBlockValidationError: b=%v, err=%v\n", block.NumberU64(), err) } func (p *Printer) OnGenesisBlock(b *types.Block) { From f1bd4151c18b9f8f404013255ff1fd46d717a9e9 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 10 Jul 2023 17:32:54 +0200 Subject: [PATCH 016/100] rm extra CaptureTxEnd --- core/state_processor.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 5e1bceb9f78d..7a4fd35e16bb 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -99,9 +99,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg var receipt *types.Receipt receipt, err = applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) - if vmenv.Config.Tracer != nil { - vmenv.Config.Tracer.CaptureTxEnd(receipt) - } if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } From d799c68159c30996f94fa7886b267c041e832478 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 10 Jul 2023 17:53:19 +0200 Subject: [PATCH 017/100] nicer printer output --- eth/tracers/printer.go | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 42855de9bd3c..4c481cce3a79 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -1,10 +1,12 @@ package tracers 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/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -17,12 +19,12 @@ func NewPrinter() *Printer { // 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=%v, gas=%v, value=%v\n", from, to, create, input, gas, value) + 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) { - fmt.Printf("CaptureEnd: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err) + 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. @@ -40,22 +42,32 @@ 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=%v, gas=%v, value=%v\n", typ, from, to, input, gas, value) + 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) { - fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err) + fmt.Printf("CaptureExit: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err) } func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { - fmt.Printf("CaptureTxStart: tx=%v\n", tx) + 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) { - fmt.Printf("CaptureTxEnd: receipt=%v\n", receipt) + 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) { @@ -83,7 +95,7 @@ func (p *Printer) OnNonceChange(a common.Address, prev, new uint64) { } 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=%v, codeHash=%v, code=%v\n", a, prevCodeHash, prev, codeHash, code) + 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) { @@ -91,7 +103,12 @@ func (p *Printer) OnStorageChange(a common.Address, k, prev, new common.Hash) { } func (p *Printer) OnLog(l *types.Log) { - fmt.Printf("OnLog: l=%v\n", l) + 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) { From add825e9c94dd17ecad5cc523e1834fa7a826f65 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 10 Jul 2023 19:01:55 +0200 Subject: [PATCH 018/100] fix BlockEnd in case of err --- core/blockchain.go | 19 +++++++++++++++++-- core/state_processor.go | 12 +----------- eth/tracers/printer.go | 4 ---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index a3c2fa648437..42e35b3fa622 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -160,7 +160,6 @@ type BlockchainLogger interface { state.StateLogger OnBlockStart(*types.Block) OnBlockEnd(td *big.Int, err error) - OnBlockValidationError(block *types.Block, err error) OnGenesisBlock(*types.Block) } @@ -1774,10 +1773,17 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // Process block using the parent state as reference point pstart := time.Now() + + if bc.logger != nil { + bc.logger.OnBlockStart(block) + } receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) followupInterrupt.Store(true) + if bc.logger != nil { + bc.logger.OnBlockEnd(new(big.Int), err) + } return it.index, err } ptime := time.Since(pstart) @@ -1787,7 +1793,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) bc.reportBlock(block, receipts, err) followupInterrupt.Store(true) if bc.logger != nil { - bc.logger.OnBlockValidationError(block, err) + bc.logger.OnBlockEnd(new(big.Int), err) } return it.index, err } @@ -1823,6 +1829,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } followupInterrupt.Store(true) if err != nil { + if bc.logger != nil { + bc.logger.OnBlockEnd(new(big.Int), err) + } return it.index, err } // Update the metrics touched during block commit @@ -1841,6 +1850,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) dirty, _ := bc.triedb.Size() stats.report(chain, it.index, dirty, setHead) + if bc.logger != nil { + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + td.Add(td, block.Difficulty()) + bc.logger.OnBlockEnd(td, nil) + } + if !setHead { // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time diff --git a/core/state_processor.go b/core/state_processor.go index 7a4fd35e16bb..a5972f371b92 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -68,17 +68,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg gp = new(GasPool).AddGas(block.GasLimit()) err error ) - if p.bc.logger != nil { - p.bc.logger.OnBlockStart(block) - defer func() { - var td *big.Int - if err == nil { - td = p.bc.GetTd(block.ParentHash(), block.NumberU64()-1) - td.Add(td, block.Difficulty()) - } - p.bc.logger.OnBlockEnd(td, err) - }() - } + // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 4c481cce3a79..98c741783124 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -78,10 +78,6 @@ func (p *Printer) OnBlockEnd(td *big.Int, err error) { fmt.Printf("OnBlockEnd: td=%v, err=%v\n", td, err) } -func (p *Printer) OnBlockValidationError(block *types.Block, err error) { - fmt.Printf("OnBlockValidationError: b=%v, err=%v\n", block.NumberU64(), err) -} - func (p *Printer) OnGenesisBlock(b *types.Block) { fmt.Printf("OnGenesisBlock: b=%v\n", b.NumberU64()) } From 0aeec7f1b5de951832c3e03411181e360e8fbdf4 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 12 Jul 2023 16:44:00 +0200 Subject: [PATCH 019/100] mv td to OnBlockStart --- core/blockchain.go | 21 +++++++++++---------- eth/tracers/printer.go | 8 ++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 42e35b3fa622..6db5be78e8bf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -158,9 +158,11 @@ var defaultCacheConfig = &CacheConfig{ type BlockchainLogger interface { vm.EVMLogger state.StateLogger - OnBlockStart(*types.Block) - OnBlockEnd(td *big.Int, err error) - OnGenesisBlock(*types.Block) + // OnBlockStart is called before executing `block`. + // `td` is the total difficulty prior to `block`. + OnBlockStart(block *types.Block, td *big.Int) + OnBlockEnd(err error) + OnGenesisBlock(genesis *types.Block) } // BlockChain represents the canonical chain given a database with a genesis @@ -1775,14 +1777,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) pstart := time.Now() if bc.logger != nil { - bc.logger.OnBlockStart(block) + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + bc.logger.OnBlockStart(block, td) } receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) followupInterrupt.Store(true) if bc.logger != nil { - bc.logger.OnBlockEnd(new(big.Int), err) + bc.logger.OnBlockEnd(err) } return it.index, err } @@ -1793,7 +1796,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) bc.reportBlock(block, receipts, err) followupInterrupt.Store(true) if bc.logger != nil { - bc.logger.OnBlockEnd(new(big.Int), err) + bc.logger.OnBlockEnd(err) } return it.index, err } @@ -1830,7 +1833,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) followupInterrupt.Store(true) if err != nil { if bc.logger != nil { - bc.logger.OnBlockEnd(new(big.Int), err) + bc.logger.OnBlockEnd(err) } return it.index, err } @@ -1851,9 +1854,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) stats.report(chain, it.index, dirty, setHead) if bc.logger != nil { - td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - td.Add(td, block.Difficulty()) - bc.logger.OnBlockEnd(td, nil) + bc.logger.OnBlockEnd(nil) } if !setHead { diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 98c741783124..f9ecf3b1dcfd 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -70,12 +70,12 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt) { fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) } -func (p *Printer) OnBlockStart(b *types.Block) { - fmt.Printf("OnBlockStart: b=%v\n", b.NumberU64()) +func (p *Printer) OnBlockStart(b *types.Block, td *big.Int) { + fmt.Printf("OnBlockStart: b=%v, td=%v\n", b.NumberU64(), td) } -func (p *Printer) OnBlockEnd(td *big.Int, err error) { - fmt.Printf("OnBlockEnd: td=%v, err=%v\n", td, err) +func (p *Printer) OnBlockEnd(err error) { + fmt.Printf("OnBlockEnd: err=%v\n", err) } func (p *Printer) OnGenesisBlock(b *types.Block) { From b692a68a3bff62041905ee4c7c8768477dd575be Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 12 Jul 2023 17:22:52 +0200 Subject: [PATCH 020/100] add final & safe headers to BlockStart --- core/blockchain.go | 4 ++-- eth/tracers/printer.go | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 6db5be78e8bf..4abf32ed801a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -160,7 +160,7 @@ type BlockchainLogger interface { state.StateLogger // OnBlockStart is called before executing `block`. // `td` is the total difficulty prior to `block`. - OnBlockStart(block *types.Block, td *big.Int) + OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header) OnBlockEnd(err error) OnGenesisBlock(genesis *types.Block) } @@ -1778,7 +1778,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if bc.logger != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td) + bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) } receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index f9ecf3b1dcfd..ce38f3b1a3b3 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -70,8 +70,12 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt) { fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) } -func (p *Printer) OnBlockStart(b *types.Block, td *big.Int) { - fmt.Printf("OnBlockStart: b=%v, td=%v\n", b.NumberU64(), td) +func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { + 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) { From 2a59d24b7368085d357aff00369203dd2af0c9c0 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 12 Jul 2023 17:38:19 +0200 Subject: [PATCH 021/100] add genesis alloc to hook --- core/blockchain.go | 2 +- core/genesis.go | 2 +- eth/tracers/printer.go | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 4abf32ed801a..b72917f7b369 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -162,7 +162,7 @@ type BlockchainLogger interface { // `td` is the total difficulty prior to `block`. OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header) OnBlockEnd(err error) - OnGenesisBlock(genesis *types.Block) + OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) } // BlockChain represents the canonical chain given a database with a genesis diff --git a/core/genesis.go b/core/genesis.go index 2d84efcfdedb..c5f615210bde 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -485,7 +485,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc return nil, errors.New("can't start clique chain without signers") } if bcLogger != nil { - bcLogger.OnGenesisBlock(block) + bcLogger.OnGenesisBlock(block, g.Alloc) } // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index ce38f3b1a3b3..3dcf2c1098c8 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -7,6 +7,7 @@ import ( "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/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -82,8 +83,8 @@ func (p *Printer) OnBlockEnd(err error) { fmt.Printf("OnBlockEnd: err=%v\n", err) } -func (p *Printer) OnGenesisBlock(b *types.Block) { - fmt.Printf("OnGenesisBlock: b=%v\n", b.NumberU64()) +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) { From 4370527cf924dbdf8665238fcb1d01eb027d1cb5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 24 Jul 2023 18:46:58 +0200 Subject: [PATCH 022/100] fix prefetcher double emit --- core/blockchain.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index b72917f7b369..e0985e9728dd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1763,7 +1763,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { - bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) + vmCfg := bc.vmConfig + vmCfg.Tracer = nil + bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) if followupInterrupt.Load() { From 5466fa313307c18b988211dd0535db83da3d9d2e Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Wed, 26 Jul 2023 04:49:04 -0400 Subject: [PATCH 023/100] Capture balance reason (#12) --- accounts/abi/bind/backends/simulated.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 10 +++--- consensus/beacon/consensus.go | 6 ++-- consensus/ethash/consensus.go | 6 ++-- consensus/misc/dao.go | 4 +-- core/evm.go | 5 +-- core/genesis.go | 4 +-- core/genesis_test.go | 2 +- core/headerchain_test.go | 2 +- core/state/state_object.go | 34 ++++++++++++++---- core/state/state_test.go | 14 ++++---- core/state/statedb.go | 14 ++++---- core/state/statedb_test.go | 46 ++++++++++++------------- core/state/sync_test.go | 2 +- core/state/trie_prefetcher_test.go | 6 ++-- core/state_transition.go | 7 ++-- core/txpool/txpool2_test.go | 12 +++---- core/txpool/txpool_test.go | 12 +++---- core/vm/evm.go | 3 +- core/vm/instructions.go | 3 +- core/vm/interface.go | 5 +-- eth/api_debug_test.go | 2 +- eth/filters/filter_test.go | 2 +- eth/tracers/js/tracer_test.go | 10 +++--- eth/tracers/logger/logger.go | 4 ++- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/native/mux.go | 5 +-- eth/tracers/native/prestate.go | 14 ++++---- eth/tracers/noop.go | 4 ++- internal/ethapi/api.go | 2 +- les/odr_test.go | 4 +-- light/odr_test.go | 2 +- tests/state_test_util.go | 4 +-- 33 files changed, 142 insertions(+), 112 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 83b91f7f8d59..8ff9351712cb 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -647,7 +647,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) + from.SetBalance(math.MaxBig256, 0x0) // Execute the call. msg := &core.Message{ diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index f8652b485049..396e760fd050 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -183,7 +183,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) - tracer.CaptureTxStart(tx) + tracer.CaptureTxStart(evm, tx) // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { @@ -258,15 +258,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) + statedb.AddBalance(ommer.Address, reward, state.BalanceChangeRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, minerReward) + statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceChangeRewardMineBlock) } // 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) + statedb.AddBalance(w.Address, amount, state.BalanceChangeWithdrawal) } // Commit block root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) @@ -299,7 +299,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) + statedb.SetBalance(addr, a.Balance, state.BalanceChangeGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index c5d2a12a7b26..4ac1c87726bc 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -340,9 +340,9 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine and processes withdrawals on top. -func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { +func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, stateDB *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { if !beacon.IsPoSHeader(header) { - beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) + beacon.ethone.Finalize(chain, header, stateDB, txs, uncles, nil) return } // Withdrawals processing. @@ -350,7 +350,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)) - state.AddBalance(w.Address, amount) + stateDB.AddBalance(w.Address, amount, state.BalanceChangeWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index ad36f21ca948..c537365ace06 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -546,7 +546,7 @@ var ( // AccumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. -func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) { +func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) { // Select the correct block reward based on chain progression blockReward := FrontierBlockReward if config.IsByzantium(header.Number) { @@ -563,10 +563,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, big8) - state.AddBalance(uncle.Coinbase, r) + stateDB.AddBalance(uncle.Coinbase, r, state.BalanceChangeRewardMineUncle) r.Div(blockReward, big32) reward.Add(reward, r) } - state.AddBalance(header.Coinbase, reward) + stateDB.AddBalance(header.Coinbase, reward, state.BalanceChangeRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index 96995616de56..7f0895eb26bb 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -80,7 +80,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)) - statedb.SetBalance(addr, new(big.Int)) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceChangeDaoRefundContract) + statedb.SetBalance(addr, new(big.Int), state.BalanceChangeDaoAdjustBalance) } } diff --git a/core/evm.go b/core/evm.go index b7ff7790295b..07c592f72c49 100644 --- a/core/evm.go +++ b/core/evm.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -125,6 +126,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) - db.AddBalance(recipient, amount) + db.SubBalance(sender, amount, state.BalanceChangeTransfer) + db.AddBalance(recipient, amount, state.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index c5f615210bde..691ae1c04c12 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -125,7 +125,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { return common.Hash{}, err } for addr, account := range *ga { - statedb.AddBalance(addr, account.Balance) + statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) for key, value := range account.Storage { @@ -145,7 +145,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas return err } for addr, account := range *ga { - statedb.AddBalance(addr, account.Balance) + statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) for key, value := range account.Storage { diff --git a/core/genesis_test.go b/core/genesis_test.go index 723d1e476bf1..12df82194ec3 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -36,7 +36,7 @@ func TestInvalidCliqueConfig(t *testing.T) { block := DefaultGoerliGenesisBlock() block.ExtraData = []byte{} db := rawdb.NewMemoryDatabase() - if _, err := block.Commit(db, trie.NewDatabase(db)); err == nil { + if _, err := block.Commit(db, trie.NewDatabase(db), nil); err == nil { t.Fatal("Expected error on invalid clique config") } } diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 08d19f695072..f58e31588ad9 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - gspec.Commit(db, trie.NewDatabase(db)) + gspec.Commit(db, trie.NewDatabase(db), nil) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) diff --git a/core/state/state_object.go b/core/state/state_object.go index 5ffae5df02aa..cd63d2e5b02e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -54,6 +54,28 @@ func (s Storage) Copy() Storage { return cpy } +// BalanceChangeReason is used to indicate the reason for a balance change, useful +// for tracing and reporting. +type BalanceChangeReason byte + +const ( + BalanceChangeUnspecified BalanceChangeReason = iota + BalanceChangeRewardMineUncle + BalanceChangeRewardMineBlock + BalanceChangeDaoRefundContract + BalanceChangeDaoAdjustBalance + BalanceChangeTransfer + BalanceChangeGenesisBalance + BalanceChangeGasBuy + BalanceChangeRewardTransactionFee + BalanceChangeGasRefund + BalanceChangeTouchAccount + BalanceChangeSuicideRefund + BalanceChangeSuicideWithdraw + BalanceChangeBurn + BalanceChangeWithdrawal +) + // stateObject represents an Ethereum account which is being modified. // // The usage pattern is as follows: @@ -376,7 +398,7 @@ func (s *stateObject) commitTrie(db Database) (*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) { +func (s *stateObject) AddBalance(amount *big.Int, reason 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 { @@ -385,25 +407,25 @@ func (s *stateObject) AddBalance(amount *big.Int) { } return } - s.SetBalance(new(big.Int).Add(s.Balance(), amount)) + s.SetBalance(new(big.Int).Add(s.Balance(), amount), reason) } // 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) { +func (s *stateObject) SubBalance(amount *big.Int, reason BalanceChangeReason) { if amount.Sign() == 0 { return } - s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) + s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason) } -func (s *stateObject) SetBalance(amount *big.Int) { +func (s *stateObject) SetBalance(amount *big.Int, reason BalanceChangeReason) { s.db.journal.append(balanceChange{ account: &s.address, prev: new(big.Int).Set(s.data.Balance), }) if s.db.logger != nil { - s.db.logger.OnBalanceChange(s.address, s.Balance(), amount) + s.db.logger.OnBalanceChange(s.address, s.Balance(), amount, reason) } s.setBalance(amount) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 15e603726578..1d4f7ecd4ade 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -48,11 +48,11 @@ func TestDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22)) + obj1.AddBalance(big.NewInt(22), 0x0) 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)) + obj3.SetBalance(big.NewInt(44), 0x0) // write some of them to the trie s.state.updateStateObject(obj1) @@ -100,13 +100,13 @@ func TestIterativeDump(t *testing.T) { // generate a few entries obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(big.NewInt(22)) + obj1.AddBalance(big.NewInt(22), 0x0) 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)) + obj3.SetBalance(big.NewInt(44), 0x0) obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) - obj4.AddBalance(big.NewInt(1337)) + obj4.AddBalance(big.NewInt(1337), 0x0) // write some of them to the trie s.state.updateStateObject(obj1) @@ -201,7 +201,7 @@ func TestSnapshot2(t *testing.T) { // db, trie are already non-empty values so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(big.NewInt(42)) + so0.SetBalance(big.NewInt(42), 0x0) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.suicided = false @@ -213,7 +213,7 @@ func TestSnapshot2(t *testing.T) { // and one with deleted == true so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(big.NewInt(52)) + so1.SetBalance(big.NewInt(52), 0x0) so1.SetNonce(53) so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) so1.suicided = true diff --git a/core/state/statedb.go b/core/state/statedb.go index 67b6da597227..2f7657b4633e 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -58,7 +58,7 @@ func (n *proofList) Delete(key []byte) error { // 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) + 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) @@ -417,25 +417,25 @@ func (s *StateDB) HasSuicided(addr common.Address) bool { */ // AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { +func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.AddBalance(amount) + stateObject.AddBalance(amount, reason) } } // SubBalance subtracts amount from the account associated with addr. -func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { +func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.SubBalance(amount) + stateObject.SubBalance(amount, reason) } } -func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) { +func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { - stateObject.SetBalance(amount) + stateObject.SetBalance(amount, reason) } } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 82118fc5f4ff..16d88b6a0844 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -47,7 +47,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))) + state.AddBalance(addr, big.NewInt(int64(11*i)), 0x0) 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})) @@ -80,7 +80,7 @@ func TestIntermediateLeaks(t *testing.T) { finalState, _ := New(types.EmptyRootHash, NewDatabase(finalDb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { - state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) + state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), 0x0) state.SetNonce(addr, uint64(42*i+tweak)) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) @@ -156,7 +156,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))) + obj.AddBalance(big.NewInt(int64(i)), 0x0) orig.updateStateObject(obj) } orig.Finalise(false) @@ -173,9 +173,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))) - copyObj.AddBalance(big.NewInt(3 * int64(i))) - ccopyObj.AddBalance(big.NewInt(4 * int64(i))) + origObj.AddBalance(big.NewInt(2*int64(i)), 0x0) + copyObj.AddBalance(big.NewInt(3*int64(i)), 0x0) + ccopyObj.AddBalance(big.NewInt(4*int64(i)), 0x0) orig.updateStateObject(origObj) copy.updateStateObject(copyObj) @@ -255,14 +255,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])) + s.SetBalance(addr, big.NewInt(a.args[0]), 0x0) }, args: make([]int64, 1), }, { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, big.NewInt(a.args[0])) + s.AddBalance(addr, big.NewInt(a.args[0]), 0x0) }, args: make([]int64, 1), }, @@ -490,7 +490,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)) + s.state.AddBalance(common.Address{}, new(big.Int), 0x0) if len(s.state.journal.dirties) != 1 { t.Fatal("expected one dirty state object") @@ -506,7 +506,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)) + state.SetBalance(addr, big.NewInt(42), 0x0) if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { t.Fatalf("1st copy fail, expected 42, got %v", got) @@ -528,9 +528,9 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // 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), 0x0) // 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) @@ -600,9 +600,9 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // 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), 0x0) // 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) @@ -686,7 +686,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)) + state.SetBalance(addr, big.NewInt(1), 0x0) root, _ := state.Commit(false) state, _ = New(root, state.db, state.snaps) @@ -696,7 +696,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.Finalise(true) id := state.Snapshot() - state.SetBalance(addr, big.NewInt(2)) + state.SetBalance(addr, big.NewInt(2), 0x0) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state @@ -719,10 +719,10 @@ func TestMissingTrieNodes(t *testing.T) { state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) { - state.SetBalance(addr, big.NewInt(1)) + state.SetBalance(addr, big.NewInt(1), 0x0) state.SetCode(addr, []byte{1, 2, 3}) a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, big.NewInt(100)) + state.SetBalance(a2, big.NewInt(100), 0x0) state.SetCode(a2, []byte{1, 2, 4}) root, _ = state.Commit(false) t.Logf("root: %x", root) @@ -747,7 +747,7 @@ func TestMissingTrieNodes(t *testing.T) { t.Errorf("expected %d, got %d", exp, got) } // Modify the state - state.SetBalance(addr, big.NewInt(2)) + state.SetBalance(addr, big.NewInt(2), 0x0) root, err := state.Commit(false) if err == nil { t.Fatalf("expected error, got root :%x", root) @@ -1014,13 +1014,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)) + state.SetBalance(addr, big.NewInt(1), 0x0) 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)) + state.SetBalance(addr, big.NewInt(2), 0x0) state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) root, _ := state.Commit(true) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 6e9d9342ee80..9530c37a176a 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -51,7 +51,7 @@ func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) acc := &testAccount{address: common.BytesToAddress([]byte{i})} - obj.AddBalance(big.NewInt(int64(11 * i))) + obj.AddBalance(big.NewInt(int64(11*i)), 0x0) 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 b190567e92bc..79a0f7f3c32c 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -34,9 +34,9 @@ func filledStateDB() *StateDB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // 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), 0x0) // 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_transition.go b/core/state_transition.go index 87772b7b96bb..c78e6629f9ec 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -23,6 +23,7 @@ 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/params" @@ -245,7 +246,7 @@ func (st *StateTransition) buyGas() error { st.gasRemaining += st.msg.GasLimit st.initialGas = st.msg.GasLimit - st.state.SubBalance(st.msg.From, mgval) + st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) return nil } @@ -392,7 +393,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) + st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceChangeRewardTransactionFee) } return &ExecutionResult{ @@ -412,7 +413,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { // 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) + st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) // Also return remaining gas to the block gas counter so it is // available for the next transaction. diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go index b679050562d6..018e362fe8b8 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/txpool2_test.go @@ -49,7 +49,7 @@ func fillPool(t testing.TB, pool *TxPool) { nonExecutableTxs := types.Transactions{} for i := 0; i < 384; i++ { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), 0x0) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -90,7 +90,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() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) 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)) @@ -126,7 +126,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() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) 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)) @@ -179,7 +179,7 @@ func TestTransactionZAttack(t *testing.T) { for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.AddRemotesSync(futureTxs) } @@ -187,7 +187,7 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -223,7 +223,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) futureTxs := types.Transactions{} for n := 0; n < b.N; n++ { diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 319e25bead8b..971bb030ed34 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -221,7 +221,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)) + c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), 0x0) *c.trigger = false } return stdb, nil @@ -241,7 +241,7 @@ func TestStateChangeDuringReset(t *testing.T) { ) // setup pool with 2 transaction in it - statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) + statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), 0x0) blockchain := &testChain{newTestBlockChain(1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) @@ -274,7 +274,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *TxPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, amount) + pool.currentState.AddBalance(addr, amount, 0x0) pool.mu.Unlock() } @@ -435,7 +435,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)) + statedb.AddBalance(addr, big.NewInt(100000000000000), 0x0) pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -464,7 +464,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)) + statedb.AddBalance(addr, big.NewInt(100000000000000), 0x0) pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2569,7 +2569,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)) + pool.currentState.AddBalance(account, big.NewInt(1000000), 0x0) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/evm.go b/core/vm/evm.go index 26ad3b444e20..7ad0f2ad893b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -21,6 +21,7 @@ import ( "sync/atomic" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -368,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, big0) + evm.StateDB.AddBalance(addr, big0, state.BalanceChangeTouchAccount) // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 65f8ea1930e3..6d054bccaeee 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -18,6 +18,7 @@ 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/params" @@ -822,7 +823,7 @@ 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) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceChangeSuicideRefund) interpreter.evm.StateDB.Suicide(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) diff --git a/core/vm/interface.go b/core/vm/interface.go index b83f78307eb7..51af040144dd 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ 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/params" ) @@ -28,8 +29,8 @@ import ( type StateDB interface { CreateAccount(common.Address) - SubBalance(common.Address, *big.Int) - AddBalance(common.Address, *big.Int) + SubBalance(common.Address, *big.Int, state.BalanceChangeReason) + AddBalance(common.Address, *big.Int, state.BalanceChangeReason) GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index dec1b34ddc1f..b25314c758f4 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -78,7 +78,7 @@ func TestAccountRange(t *testing.T) { hash := common.HexToHash(fmt.Sprintf("%x", i)) addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes()) addrs[i] = addr - state.SetBalance(addrs[i], big.NewInt(1)) + state.SetBalance(addrs[i], big.NewInt(1), 0x0) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 8eea0a267892..6e8f2ce01d7a 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -180,7 +180,7 @@ func TestFilters(t *testing.T) { // Hack: GenerateChainWithGenesis creates a new db. // Commit the genesis manually and use GenerateChain. - _, err = gspec.Commit(db, trie.NewDatabase(db)) + _, err = gspec.Commit(db, trie.NewDatabase(db), nil) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 0031b0cb3c17..c2273b5f08f4 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -74,8 +74,8 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon contract.Code = contractCode } - tracer.CaptureTxStart(types.NewTx(&types.LegacyTx{Gas: gasLimit})) - tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) + tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{Gas: gasLimit})) + 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) // Rest gas assumes no refund @@ -181,11 +181,10 @@ func TestHaltBetweenSteps(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } - tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0)) + 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") tracer.Stop(timeout) @@ -205,8 +204,7 @@ 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.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) + tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index d1d995424eec..c0cb5e1638a2 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -28,6 +28,7 @@ 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/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -272,7 +273,8 @@ func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) { l.usedGas = receipt.GasUsed } -func (l *StructLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} +func (l *StructLogger) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +} func (l *StructLogger) OnNonceChange(a common.Address, prev, new uint64) {} diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 3192a15cbab8..4a7db6e72fc9 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -60,7 +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.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil) + logger.CaptureStart(common.Address{}, contract.Address(), false, nil, 0, nil) _, err := env.Interpreter().Run(contract, []byte{}, false) if err != nil { t.Fatal(err) diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 3d41a1ebebea..d85a3f2c991e 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -21,6 +21,7 @@ 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" @@ -128,9 +129,9 @@ func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt) { } } -func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int) { +func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { for _, t := range t.tracers { - t.OnBalanceChange(a, prev, new) + t.OnBalanceChange(a, prev, new, reason) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 63536db1a724..79bfa337a1fd 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -37,7 +37,7 @@ func init() { tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) } -type state = map[common.Address]*account +type stateMap = map[common.Address]*account type account struct { Balance *big.Int `json:"balance,omitempty"` @@ -58,8 +58,8 @@ type accountMarshaling struct { type prestateTracer struct { tracers.NoopTracer env *vm.EVM - pre state - post state + pre stateMap + post stateMap create bool to common.Address config prestateTracerConfig @@ -81,8 +81,8 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace } } return &prestateTracer{ - pre: state{}, - post: state{}, + pre: stateMap{}, + post: stateMap{}, config: config, created: make(map[common.Address]bool), deleted: make(map[common.Address]bool), @@ -246,8 +246,8 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) { var err error if t.config.DiffMode { res, err = json.Marshal(struct { - Post state `json:"post"` - Pre state `json:"pre"` + Post stateMap `json:"post"` + Pre stateMap `json:"pre"` }{t.post, t.pre}) } else { res, err = json.Marshal(t.pre) diff --git a/eth/tracers/noop.go b/eth/tracers/noop.go index e33570d9019e..fc68ad8b80e5 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/noop.go @@ -21,6 +21,7 @@ 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" ) @@ -73,7 +74,8 @@ func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {} -func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {} +func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +} func (*NoopTracer) OnNonceChange(a common.Address, prev, new uint64) {} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 80756b64b80d..7e0df21349e8 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -917,7 +917,7 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { } // Override account balance. if account.Balance != nil { - state.SetBalance(addr, (*big.Int)(*account.Balance)) + state.SetBalance(addr, (*big.Int)(*account.Balance), 0x0) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) diff --git a/les/odr_test.go b/les/odr_test.go index 2db9acd4335e..62f5951695a1 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -130,7 +130,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai if err == nil { from := statedb.GetOrNewStateObject(bankAddr) - from.SetBalance(math.MaxBig256) + from.SetBalance(math.MaxBig256, 0x0) msg := &core.Message{ From: from.Address(), @@ -156,7 +156,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai } else { header := lc.GetHeaderByHash(bhash) state := light.NewState(ctx, header, lc.Odr()) - state.SetBalance(bankAddr, math.MaxBig256) + state.SetBalance(bankAddr, math.MaxBig256, 0x0) msg := &core.Message{ From: bankAddr, To: &testContractAddr, diff --git a/light/odr_test.go b/light/odr_test.go index 0df1fbf2f5b2..5e4c38a6d1b9 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -199,7 +199,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } // Perform read-only call. - st.SetBalance(testBankAddress, math.MaxBig256) + st.SetBalance(testBankAddress, math.MaxBig256, 0x0) msg := &core.Message{ From: testBankAddress, To: &testContractAddr, diff --git a/tests/state_test_util.go b/tests/state_test_util.go index eec91b67a7d4..7f6b6c23f334 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -273,7 +273,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - the coinbase suicided, 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)) + statedb.AddBalance(block.Coinbase(), new(big.Int), 0x0) // Commit block statedb.Commit(config.IsEIP158(block.Number())) // And _now_ get the state root @@ -291,7 +291,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) + statedb.SetBalance(addr, a.Balance, 0x0) for k, v := range a.Storage { statedb.SetState(addr, k, v) } From 2faf3dbfd6fd51fd568391a81bdf3bd4e179e78a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 26 Jul 2023 20:07:13 +0200 Subject: [PATCH 024/100] emit err on tx validation failure --- cmd/evm/internal/t8ntool/execution.go | 3 ++- core/state_processor.go | 7 +++++-- core/vm/logger.go | 2 +- core/vm/runtime/runtime.go | 9 +++++++++ core/vm/runtime/runtime_test.go | 4 ++-- eth/tracers/api.go | 5 +++-- eth/tracers/internal/tracetest/calltrace_test.go | 4 ++-- eth/tracers/internal/tracetest/flat_calltrace_test.go | 2 +- eth/tracers/internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/goja.go | 9 ++++++++- eth/tracers/js/tracer_test.go | 6 +++++- eth/tracers/logger/access_list_tracer.go | 2 +- eth/tracers/logger/logger.go | 11 +++++++++-- eth/tracers/logger/logger_json.go | 2 +- eth/tracers/native/call.go | 6 +++++- eth/tracers/native/call_flat.go | 4 ++-- eth/tracers/native/mux.go | 4 ++-- eth/tracers/native/prestate.go | 5 ++++- eth/tracers/noop.go | 2 +- eth/tracers/printer.go | 6 +++++- 20 files changed, 69 insertions(+), 26 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 396e760fd050..ebdbff895882 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -191,6 +191,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) + tracer.CaptureTxEnd(nil, err) continue } includedTxs = append(includedTxs, tx) @@ -232,7 +233,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) - tracer.CaptureTxEnd(receipt) + tracer.CaptureTxEnd(receipt, nil) } txIndex++ diff --git a/core/state_processor.go b/core/state_processor.go index a5972f371b92..75df98e71bb4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -108,11 +108,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { - var receipt *types.Receipt + var ( + receipt *types.Receipt + err error + ) if evm.Config.Tracer != nil { evm.Config.Tracer.CaptureTxStart(evm, tx) defer func() { - evm.Config.Tracer.CaptureTxEnd(receipt) + evm.Config.Tracer.CaptureTxEnd(receipt, err) }() } // Create a new context to be used in the EVM environment. diff --git a/core/vm/logger.go b/core/vm/logger.go index b7b0fc4d8e20..04084115000a 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -31,7 +31,7 @@ import ( type EVMLogger interface { // Transaction level CaptureTxStart(evm *EVM, tx *types.Transaction) - CaptureTxEnd(receipt *types.Receipt) + 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(output []byte, gasUsed uint64, err error) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index a3e75c67212c..d6a3a5508aac 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -116,6 +116,9 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { sender = vm.AccountRef(cfg.Origin) 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})) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) @@ -149,6 +152,9 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { sender = vm.AccountRef(cfg.Origin) 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})) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) @@ -177,6 +183,9 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er statedb = cfg.State 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})) + } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 7b521a2ead59..f411a67f8d9f 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -811,7 +811,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.PUSH1), 0, byte(vm.RETURN), } - depressedCode := []byte{ + suicideCode := []byte{ byte(vm.PUSH1), 0xaa, byte(vm.SELFDESTRUCT), } @@ -824,7 +824,7 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) statedb.SetCode(common.HexToAddress("0xdd"), calleeCode) statedb.SetCode(common.HexToAddress("0xee"), calleeCode) - statedb.SetCode(common.HexToAddress("0xff"), depressedCode) + statedb.SetCode(common.HexToAddress("0xff"), suicideCode) tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 7df7e7526af5..fd786231c05c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -792,7 +792,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block statedb.SetTxContext(tx.Hash(), i) vmConf.Tracer.CaptureTxStart(vmenv, tx) vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) - vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) + vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) if writer != nil { writer.Flush() } @@ -976,10 +976,11 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor tracer.CaptureTxStart(vmenv, tx) res, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)) if err != nil { + tracer.CaptureTxEnd(nil, err) return nil, fmt.Errorf("tracing failed: %w", err) } r := &types.Receipt{GasUsed: res.UsedGas} - tracer.CaptureTxEnd(r) + tracer.CaptureTxEnd(r, nil) return tracer.GetResult() } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index dd33469edfcd..6f32be31bf47 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -156,7 +156,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) + tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil) // Retrieve the trace result and compare against the expected. res, err := tracer.GetResult() if err != nil { @@ -382,7 +382,7 @@ func TestInternals(t *testing.T) { if err != nil { t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) } - tc.tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) + tc.tracer.CaptureTxEnd(&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 dac3ef06cf84..9d339dcf52e6 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -119,7 +119,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) + tracer.CaptureTxEnd(&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 9366bc418fb2..74d5492d5214 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -125,7 +125,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to execute transaction: %v", err) } - tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}) + tracer.CaptureTxEnd(&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 e4a06195f892..8ed55ef1c6d0 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -229,7 +229,14 @@ func (t *jsTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { // CaptureTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. -func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt) { +func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) { + if err != nil { + // Don't override vm error + if _, ok := t.ctx["error"]; !ok { + t.ctx["error"] = t.vm.ToValue(err.Error()) + } + return + } t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed) } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index c2273b5f08f4..4a7d6c5bcdc8 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -79,7 +79,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, err) // Rest gas assumes no refund - tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}) + tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) if err != nil { return nil, err } @@ -184,6 +184,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{})) 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") @@ -204,6 +206,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{})) tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index c5d3ec329997..ff7715f2eea4 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -174,7 +174,7 @@ func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) { func (*AccessListTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} -func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt) {} +func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} func (*AccessListTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {} diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c0cb5e1638a2..2a9e1926bb48 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -269,7 +269,14 @@ func (l *StructLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { l.env = env } -func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) { +func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt, err error) { + if err != nil { + // Don't override vm error + if l.err == nil { + l.err = err + } + return + } l.usedGas = receipt.GasUsed } @@ -417,7 +424,7 @@ func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} func (*mdLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} -func (*mdLogger) CaptureTxEnd(receipt *types.Receipt) {} +func (*mdLogger) CaptureTxEnd(receipt *types.Receipt, err error) {} func (*mdLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 845549b63b88..c1e25a1c3a7f 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -106,7 +106,7 @@ func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { l.env = env } -func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt) {} +func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt, err error) {} func (*JSONLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 87a7bbf95834..3af18cd3ce53 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -200,7 +200,11 @@ func (t *callTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { t.gasLimit = tx.Gas() } -func (t *callTracer) CaptureTxEnd(receipt *types.Receipt) { +func (t *callTracer) CaptureTxEnd(receipt *types.Receipt, err error) { + // Error happened during tx validation. + if err != nil { + return + } t.callstack[0].GasUsed = receipt.GasUsed if t.config.WithLog { // Logs are not emitted when the call fails diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 9e07c2515519..d63ca8536266 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -207,8 +207,8 @@ func (t *flatCallTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { t.activePrecompiles = vm.ActivePrecompiles(rules) } -func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt) { - t.tracer.CaptureTxEnd(receipt) +func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt, err error) { + t.tracer.CaptureTxEnd(receipt, err) } // GetResult returns an empty json object. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index d85a3f2c991e..2dcb8f2b2d99 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -123,9 +123,9 @@ func (t *muxTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { } } -func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt) { +func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt, err error) { for _, t := range t.tracers { - t.CaptureTxEnd(receipt) + t.CaptureTxEnd(receipt, err) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 79bfa337a1fd..52c975ce666b 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -176,10 +176,13 @@ func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { } } -func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt) { +func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt, err error) { if !t.config.DiffMode { return } + if err != nil { + return + } for addr, state := range t.pre { // The deleted account's state is pruned from `post` but kept in `pre` diff --git a/eth/tracers/noop.go b/eth/tracers/noop.go index fc68ad8b80e5..695c99c84b5f 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/noop.go @@ -72,7 +72,7 @@ func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} -func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {} +func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { } diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go index 3dcf2c1098c8..a07a7ea02bb7 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/printer.go @@ -62,7 +62,11 @@ func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { } -func (p *Printer) CaptureTxEnd(receipt *types.Receipt) { +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) From f9f377d64f6a9cc35053fcaabe8b796da8b32955 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 27 Jul 2023 21:57:40 +0200 Subject: [PATCH 025/100] capture call validation errors --- core/vm/evm.go | 120 ++++++++---------- eth/tracers/api_test.go | 1 - .../internal/tracetest/flat_calltrace_test.go | 2 +- .../testdata/call_tracer/inner_instafail.json | 12 +- .../callcode_precompiled_fail_hide.json | 17 ++- .../call_tracer_flat/inner_instafail.json | 16 ++- .../nested_create_inerror.json | 15 ++- .../call_tracer_flat/selfdestruct.json | 17 ++- .../skip_no_balance_error.json | 15 ++- 9 files changed, 138 insertions(+), 77 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 9f5c18b44b22..beadc501f1e0 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -174,6 +174,21 @@ func (evm *EVM) SetBlockContext(blockCtx BlockContext) { // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. 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 { + if evm.depth == 0 { + evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + defer func(startGas uint64) { // Lazy evaluation of the parameters + evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) + }(gas) + } else { + // Handle tracer events for entering and exiting a call frame + evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) + defer func(startGas uint64) { + evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -184,42 +199,16 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } snapshot := evm.StateDB.Snapshot() p, isPrecompile := evm.precompile(addr) - debug := evm.Config.Tracer != nil if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { - // Calling a non existing account, don't do anything, but ping the tracer - if debug { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) - evm.Config.Tracer.CaptureEnd(ret, 0, nil) - } else { - evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) - evm.Config.Tracer.CaptureExit(ret, 0, nil) - } - } + // Calling a non-existing account, don't do anything. return nil, gas, nil } evm.StateDB.CreateAccount(addr) } evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) - // Capture the tracer start/end events in debug mode - if debug { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) - defer func(startGas uint64) { // Lazy evaluation of the parameters - evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) - }(gas) - } else { - // Handle tracer events for entering and exiting a call frame - evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } - } - if isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { @@ -239,7 +228,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } } // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally + // above we revert to the snapshot and consume any gas remaining. Additionally, // when we're in homestead this also counts for code storage gas errors. if err != nil { evm.StateDB.RevertToSnapshot(snapshot) @@ -261,6 +250,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. 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.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) + defer func(startGas uint64) { + evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -274,14 +270,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } var snapshot = evm.StateDB.Snapshot() - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { - evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } - // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) @@ -309,12 +297,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth - } - var snapshot = evm.StateDB.Snapshot() - // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { // NOTE: caller must, at all times be a contract. It should never happen @@ -326,6 +308,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + var snapshot = evm.StateDB.Snapshot() // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { @@ -352,6 +339,13 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. 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.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) + defer func(startGas uint64) { + evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + }(gas) + } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -369,14 +363,6 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // future scenarios evm.StateDB.AddBalance(addr, big0, state.BalanceChangeTouchAccount) - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { - evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } - if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { @@ -416,7 +402,20 @@ 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) ([]byte, common.Address, uint64, error) { +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 { + if evm.depth == 0 { + evm.Config.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) + defer func() { + evm.Config.Tracer.CaptureEnd(ret, gas-leftoverGas, err) + }() + } else { + evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) + defer func() { + evm.Config.Tracer.CaptureExit(ret, gas-leftoverGas, err) + }() + } + } // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { @@ -453,15 +452,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.Config.Tracer != nil { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) - } else { - evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) - } - } - - ret, err := evm.interpreter.Run(contract, nil, false) + ret, err = evm.interpreter.Run(contract, nil, false) // Check whether the max code size has been exceeded, assign err if the case. if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { @@ -487,7 +478,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally + // above we revert to the snapshot and consume any gas remaining. Additionally, // when we're in homestead this also counts for code storage gas errors. if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) @@ -496,13 +487,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if evm.Config.Tracer != nil { - if evm.depth == 0 { - evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) - } else { - evm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err) - } - } return ret, address, contract.Gas, err } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 02f973fa0a64..d4eaf56e7a13 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -562,7 +562,6 @@ func TestTracingWithOverrides(t *testing.T) { From: &accounts[0].addr, // BLOCKNUMBER PUSH1 MSTORE Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")), - //&hexutil.Bytes{0x43}, // blocknumber }, config: &TraceCallConfig{ BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 9d339dcf52e6..f8ca10331463 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -131,7 +131,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to unmarshal trace result: %v", err) } if !jsonEqualFlat(ret, test.Result) { - t.Logf("tracer name: %s", tracerName) + t.Logf("test %s failed", filename) // uncomment this for easier debugging // have, _ := json.MarshalIndent(ret, "", " ") diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 9b45b52fe9ad..ed3688a942e1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -56,6 +56,16 @@ "value": "0x0", "gas": "0x1f97e", "gasUsed": "0x72de", - "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000" + "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", + "calls": [{ + "from":"0x6c06b16512b332e6cd8293a2974872674716ce18", + "gas":"0x8fc", + "gasUsed":"0x0", + "to":"0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "input":"0x", + "error":"insufficient balance for transfer", + "value":"0x14d1120d7b160000", + "type":"CALL" + }] } } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index c796804a4bcd..a2386ea9c713 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -63,12 +63,27 @@ "address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224" }, "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 74, "transactionHash": "0x5ef60b27ac971c22a7d484e546e50093ca62300c8986d165154e47773764b6a4", "blockNumber": 1555279, "blockHash": "0xd6c98d1b87dfa92a210d99bad2873adaf0c9e51fe43addc63fd9cca03a5c6f46", "time": "209.346µs" + }, + { + "action": { + "balance": "0x0", + "callType": "callcode", + "from": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224", + "gas": "0xaf64", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x13" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json index 4de08f2ccaf1..611e50e2c046 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -64,9 +64,23 @@ "gasUsed": "0x72de", "output": "0x" }, - "subtraces": 0, + "subtraces": 1, "traceAddress": [], "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x6c06b16512b332e6cd8293a2974872674716ce18", + "gas": "0x8fc", + "to": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "value": "0x14d1120d7b160000" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "call" } ] } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json index 28e96684b2df..f3a7d9a94610 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -70,12 +70,25 @@ "output": "0x" }, "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 26, "transactionHash": "0xcb1090fa85d2a3da8326b75333e92b3dca89963c895d9c981bfdaa64643135e4", "blockNumber": 839247, "blockHash": "0xce7ff7d84ca97f0f89d6065e2c12409a795c9f607cdb14aef0713cad5d7e311c", "time": "182.267µs" + }, + { + "action": { + "from": "0x76554b33410b6d90b7dc889bfed0451ad195f27e", + "gas": "0x25a18", + "init": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0xa" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" } ] } \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json index 74fd87cc6c4d..3c5d6d9f2b07 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -63,13 +63,26 @@ "address": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca" }, "traceAddress": [], - "subtraces": 1, + "subtraces": 2, "transactionPosition": 14, "transactionHash": "0xdd76f02407e2f8329303ba688e111cae4f7008ad0d14d6e42c5698424ea36d79", "blockNumber": 1555146, "blockHash": "0xafb4f1dd27b9054c805acb81a88ed04384788cb31d84164c21874935c81e5c7e", "time": "187.145µs" }, + { + "action": { + "from": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca", + "gas": "0x50ac", + "init": "0x5a", + "value": "0x1" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" + }, { "type": "suicide", "action": { @@ -79,7 +92,7 @@ }, "result": null, "traceAddress": [ - 0 + 1 ], "subtraces": 0, "transactionPosition": 14, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index 96060d554539..6911ed4b32af 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -59,12 +59,25 @@ }, "error": "out of gas", "traceAddress": [], - "subtraces": 0, + "subtraces": 1, "transactionPosition": 16, "transactionHash": "0x384487e5ae8d2997aece8e28403d393cb9752425e6de358891bed981c5af1c05", "blockNumber": 1555285, "blockHash": "0x93231d8e9662adb4c5c703583a92c7b3112cd5448f43ab4fa1f0f00a0183ed3f", "time": "665.278µs" + }, + { + "action": { + "from": "0xf84bf5189ccd19f5897739756d214fa0dc099e0d", + "gas": "0x1d5c", + "init": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0xc350" + }, + "error": "insufficient balance for transfer", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" } ] } \ No newline at end of file From b7ff5738866eb4ed03e049d64f33dd625df8a2ad Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:01:56 +0200 Subject: [PATCH 026/100] minor refactor Co-authored-by: Delweng --- core/blockchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index fbd86e636fb4..3ee20a9aa300 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -256,7 +256,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if vmConfig.Tracer != nil { l, ok := vmConfig.Tracer.(BlockchainLogger) if !ok { - return nil, fmt.Errorf("only extended tracers are supported for live mode") + return nil, errors.New("only extended tracers are supported for live mode") } logger = l } From 00a19d3c57829402eaa88aad2668150fd0e4df75 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Wed, 2 Aug 2023 15:35:21 -0400 Subject: [PATCH 027/100] Fixed tests compilation (#13) --- core/txpool/blobpool/blobpool_test.go | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index d1980b042351..f3bed54fa4dc 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -507,17 +507,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)) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), 0x0) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000)) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), 0x0) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000)) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000)) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -632,7 +632,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)) + statedb.AddBalance(addr, big.NewInt(1_000_000_000), 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -732,9 +732,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)) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -812,9 +812,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)) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1205,7 +1205,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)) + statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), 0x0) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store From 216a4b0f5a44504ef24a6e844a6cde058f4d82dc Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Wed, 30 Aug 2023 07:45:00 -0400 Subject: [PATCH 028/100] Added writing of `genesis.Alloc` on bootstrap (#15) --- core/blockchain.go | 15 +++++++++++ core/genesis.go | 63 ++++++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 3ee20a9aa300..107b0ad9cc38 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -406,6 +406,21 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } + if bc.logger != nil { + if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { + alloc, err := getGenesisState(bc.db, block.Hash()) + if err != nil { + return nil, fmt.Errorf("failed to get genesis state: %w", err) + } + + if alloc == nil { + return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") + } + + bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) + } + } + // Load any existing snapshot, regenerating it if loading failed if bc.cacheConfig.SnapshotLimit > 0 { // If the chain was rewound past the snapshot persistent layer (causing diff --git a/core/genesis.go b/core/genesis.go index e274f5a79b98..54ec15cba42d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -176,36 +176,49 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas return nil } -// CommitGenesisState loads the stored genesis state with the given block -// hash and commits it into the provided trie database. -func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { - var alloc GenesisAlloc +func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc GenesisAlloc, err error) { blob := rawdb.ReadGenesisStateSpec(db, blockhash) if len(blob) != 0 { if err := alloc.UnmarshalJSON(blob); err != nil { - return err - } - } else { - // Genesis allocation is missing and there are several possibilities: - // the node is legacy which doesn't persist the genesis allocation or - // the persisted allocation is just lost. - // - supported networks(mainnet, testnets), recover with defined allocations - // - private network, can't recover - var genesis *Genesis - switch blockhash { - case params.MainnetGenesisHash: - genesis = DefaultGenesisBlock() - case params.GoerliGenesisHash: - genesis = DefaultGoerliGenesisBlock() - case params.SepoliaGenesisHash: - genesis = DefaultSepoliaGenesisBlock() - } - if genesis != nil { - alloc = genesis.Alloc - } else { - return errors.New("not found") + return nil, err } + + return alloc, nil + } + + // Genesis allocation is missing and there are several possibilities: + // the node is legacy which doesn't persist the genesis allocation or + // the persisted allocation is just lost. + // - supported networks(mainnet, testnets), recover with defined allocations + // - private network, can't recover + var genesis *Genesis + switch blockhash { + case params.MainnetGenesisHash: + genesis = DefaultGenesisBlock() + case params.GoerliGenesisHash: + genesis = DefaultGoerliGenesisBlock() + case params.SepoliaGenesisHash: + genesis = DefaultSepoliaGenesisBlock() + } + if genesis != nil { + return genesis.Alloc, nil } + + return nil, nil +} + +// CommitGenesisState loads the stored genesis state with the given block +// hash and commits it into the provided trie database. +func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { + alloc, err := getGenesisState(db, blockhash) + if err != nil { + return err + } + + if alloc == nil { + return errors.New("not found") + } + return alloc.flush(db, triedb, blockhash, nil) } From 659043a1d91e194a1157a27b282fc78701576b5d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 30 Aug 2023 18:14:06 +0200 Subject: [PATCH 029/100] pass tracer name via cli --- cmd/utils/flags.go | 16 ++++++++++------ eth/backend.go | 4 ---- eth/ethconfig/config.go | 3 --- eth/tracers/{ => live}/printer.go | 13 +++++++++---- 4 files changed, 19 insertions(+), 17 deletions(-) rename eth/tracers/{ => live}/printer.go (95%) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c05e76e1a5dd..c8d77192b80e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -54,6 +54,7 @@ import ( "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" + liveTracers "github.com/ethereum/go-ethereum/eth/tracers/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/remotedb" "github.com/ethereum/go-ethereum/ethstats" @@ -518,9 +519,9 @@ var ( Usage: "Record information useful for VM and contract debugging", Category: flags.VMCategory, } - VMTraceFlag = &cli.BoolFlag{ + VMTraceFlag = &cli.StringFlag{ Name: "vmtrace", - Usage: "Record internal VM operations (costly)", + Usage: "Name of tracer which should record internal VM operations (costly)", Category: flags.VMCategory, } @@ -1723,9 +1724,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } - if ctx.IsSet(VMTraceFlag.Name) { - cfg.LiveTrace = ctx.Bool(VMTraceFlag.Name) - } if ctx.IsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) @@ -2143,7 +2141,13 @@ 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) { - vmcfg.Tracer = tracers.NewPrinter() + if name := ctx.String(VMTraceFlag.Name); name != "" { + t, err := liveTracers.New(name) + if err != nil { + Fatalf("Failed to create tracer %q: %v", name, err) + } + vmcfg.Tracer = t + } } // Disable transaction indexing/unindexing by default. chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) diff --git a/eth/backend.go b/eth/backend.go index 6cb5611d32b3..667200bcedda 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -44,7 +44,6 @@ 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" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -194,9 +193,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Preimages: config.Preimages, } ) - if config.LiveTrace { - vmConfig.Tracer = tracers.NewPrinter() - } // 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 55dd56316e30..4bc8b8dc6c6e 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -140,9 +140,6 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool - // LiveTrace will enable tracing during normal chain processing. - LiveTrace bool - // Miscellaneous options DocRoot string `toml:"-"` diff --git a/eth/tracers/printer.go b/eth/tracers/live/printer.go similarity index 95% rename from eth/tracers/printer.go rename to eth/tracers/live/printer.go index a07a7ea02bb7..8d9952fb5f76 100644 --- a/eth/tracers/printer.go +++ b/eth/tracers/live/printer.go @@ -1,4 +1,4 @@ -package tracers +package live import ( "encoding/json" @@ -8,14 +8,19 @@ import ( "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" ) +func init() { + register("printer", newPrinter) +} + type Printer struct{} -func NewPrinter() *Printer { - return &Printer{} +func newPrinter() (core.BlockchainLogger, error) { + return &Printer{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -91,7 +96,7 @@ 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) { +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) } From 9c999c36ff02dc49c120e3795d147959687fe6fb Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 31 Aug 2023 16:31:30 +0200 Subject: [PATCH 030/100] Use noopTracer as base for loggers --- cmd/utils/flags.go | 4 +- eth/tracers/api.go | 19 +++--- eth/tracers/directory/live.go | 30 +++++++++ eth/tracers/{ => directory}/noop.go | 2 +- eth/tracers/{ => directory}/tracers.go | 32 ++-------- eth/tracers/directory/util.go | 47 ++++++++++++++ eth/tracers/directory/util_test.go | 60 +++++++++++++++++ .../internal/tracetest/calltrace_test.go | 12 ++-- .../internal/tracetest/flat_calltrace_test.go | 6 +- .../internal/tracetest/prestate_test.go | 4 +- eth/tracers/js/goja.go | 18 +++--- eth/tracers/js/tracer_test.go | 16 ++--- eth/tracers/live/printer.go | 3 +- eth/tracers/logger/access_list_tracer.go | 38 +---------- eth/tracers/logger/logger.go | 64 +------------------ eth/tracers/logger/logger_json.go | 31 +-------- eth/tracers/logger/logger_test.go | 1 + eth/tracers/native/4byte.go | 8 +-- eth/tracers/native/call.go | 8 +-- eth/tracers/native/call_flat.go | 20 +++--- eth/tracers/native/mux.go | 12 ++-- eth/tracers/native/prestate.go | 10 +-- eth/tracers/tracers_test.go | 38 ----------- 23 files changed, 220 insertions(+), 263 deletions(-) create mode 100644 eth/tracers/directory/live.go rename eth/tracers/{ => directory}/noop.go (99%) rename eth/tracers/{ => directory}/tracers.go (80%) create mode 100644 eth/tracers/directory/util.go create mode 100644 eth/tracers/directory/util_test.go diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c8d77192b80e..6a2d788a4aff 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -54,7 +54,7 @@ import ( "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" - liveTracers "github.com/ethereum/go-ethereum/eth/tracers/live" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/remotedb" "github.com/ethereum/go-ethereum/ethstats" @@ -2142,7 +2142,7 @@ 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 := liveTracers.New(name) + t, err := directory.LiveDirectory.New(name) if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 1d3c57dc7c1a..69fe38ba205a 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -37,6 +37,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" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -272,7 +273,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // Trace all the transactions contained within for i, tx := range task.block.Transactions() { msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee()) - txctx := &Context{ + txctx := &directory.Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), TxIndex: i, @@ -591,7 +592,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // process that generates states in one thread and traces txes // in separate worker threads. if config != nil && config.Tracer != nil && *config.Tracer != "" { - if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS { + if isJS := directory.DefaultDirectory.IsJS(*config.Tracer); isJS { return api.traceBlockParallel(ctx, block, statedb, config) } } @@ -607,7 +608,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac for i, tx := range txs { // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txctx := &Context{ + txctx := &directory.Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: i, @@ -650,7 +651,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // Fetch and execute the next transaction trace tasks for task := range jobs { msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee()) - txctx := &Context{ + txctx := &directory.Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: task.index, @@ -859,7 +860,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * return nil, err } - txctx := &Context{ + txctx := &directory.Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: int(index), @@ -927,15 +928,15 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, tx, msg, new(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, tx *types.Transaction, message *core.Message, txctx *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 Tracer + tracer directory.Tracer err error timeout = defaultTraceTimeout txContext = core.NewEVMTxContext(message) @@ -946,7 +947,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor // Default tracer is the struct logger tracer = logger.NewStructLogger(config.Config) if config.Tracer != nil { - tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) + tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } diff --git a/eth/tracers/directory/live.go b/eth/tracers/directory/live.go new file mode 100644 index 000000000000..dc6927b14228 --- /dev/null +++ b/eth/tracers/directory/live.go @@ -0,0 +1,30 @@ +package directory + +import ( + "errors" + + "github.com/ethereum/go-ethereum/core" +) + +type ctorFunc func() (core.BlockchainLogger, error) + +// LiveDirectory is the collection of tracers which can be used +// during normal block import operations. +var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)} + +type liveDirectory struct { + elems map[string]ctorFunc +} + +// Register registers a tracer constructor by name. +func (d *liveDirectory) Register(name string, f ctorFunc) { + d.elems[name] = f +} + +// New instantiates a tracer by name. +func (d *liveDirectory) New(name string) (core.BlockchainLogger, error) { + if f, ok := d.elems[name]; ok { + return f() + } + return nil, errors.New("not found") +} diff --git a/eth/tracers/noop.go b/eth/tracers/directory/noop.go similarity index 99% rename from eth/tracers/noop.go rename to eth/tracers/directory/noop.go index 695c99c84b5f..06902061f41c 100644 --- a/eth/tracers/noop.go +++ b/eth/tracers/directory/noop.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package tracers +package directory import ( "encoding/json" diff --git a/eth/tracers/tracers.go b/eth/tracers/directory/tracers.go similarity index 80% rename from eth/tracers/tracers.go rename to eth/tracers/directory/tracers.go index c82fcf92acea..b16d9d2fe69d 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/directory/tracers.go @@ -14,13 +14,13 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package tracers is a manager for transaction tracing engines. -package tracers +// Package directory provides functionality to lookup tracers by name. +// It also includes utility functions that are imported by the other +// tracing packages. +package directory import ( "encoding/json" - "errors" - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -101,27 +101,3 @@ func (d *directory) IsJS(name string) bool { // JS eval will execute JS code return true } - -const ( - memoryPadLimit = 1024 * 1024 -) - -// 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) { - 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 - } - paddingNeeded := int(offset+size) - m.Len() - 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)) - } - return cpy, nil -} diff --git a/eth/tracers/directory/util.go b/eth/tracers/directory/util.go new file mode 100644 index 000000000000..92de735291d1 --- /dev/null +++ b/eth/tracers/directory/util.go @@ -0,0 +1,47 @@ +// 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 directory + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/core/vm" +) + +const ( + memoryPadLimit = 1024 * 1024 +) + +// 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) { + 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 + } + paddingNeeded := int(offset+size) - m.Len() + 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)) + } + return cpy, nil +} diff --git a/eth/tracers/directory/util_test.go b/eth/tracers/directory/util_test.go new file mode 100644 index 000000000000..c72096708da3 --- /dev/null +++ b/eth/tracers/directory/util_test.go @@ -0,0 +1,60 @@ +// 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 directory + +import ( + "testing" + + "github.com/ethereum/go-ethereum/core/vm" +) + +func TestMemCopying(t *testing.T) { + for i, tc := range []struct { + memsize int64 + offset int64 + size int64 + wantErr string + wantSize int + }{ + {0, 0, 100, "", 100}, // Should pad up to 100 + {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 + + } { + mem := vm.NewMemory() + mem.Resize(uint64(tc.memsize)) + cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) + if want := tc.wantErr; want != "" { + if err == nil { + t.Fatalf("test %d: want '%v' have no error", i, want) + } + if have := err.Error(); want != have { + t.Fatalf("test %d: want '%v' have '%v'", i, want, have) + } + continue + } + if err != nil { + t.Fatalf("test %d: unexpected error: %v", i, err) + } + if want, have := tc.wantSize, len(cpy); have != want { + t.Fatalf("test %d: want %v have %v", i, want, have) + } + } +} diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index a0001118a86e..d342f2109d17 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -33,7 +33,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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" @@ -141,7 +141,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) + tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } @@ -247,7 +247,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil) + tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), nil) if err != nil { b.Fatalf("failed to create call tracer: %v", err) } @@ -283,8 +283,8 @@ func TestInternals(t *testing.T) { BaseFee: new(big.Int), } ) - mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer { - tr, err := tracers.DefaultDirectory.New(name, nil, cfg) + 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) } @@ -294,7 +294,7 @@ func TestInternals(t *testing.T) { for _, tc := range []struct { name string code []byte - tracer tracers.Tracer + tracer directory.Tracer want string }{ { diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index f8ca10331463..be552ccfd5ff 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -16,11 +16,9 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "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/rlp" "github.com/ethereum/go-ethereum/tests" - - // Force-load the native, to trigger registration - "github.com/ethereum/go-ethereum/eth/tracers" ) // flatCallTrace is the result of a callTracerParity run. @@ -103,7 +101,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) // Create the tracer, the EVM environment and run it - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) + tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) if err != nil { return fmt.Errorf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 74d5492d5214..dc2e7293b969 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/tests" ) @@ -110,7 +110,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) + 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/js/goja.go b/eth/tracers/js/goja.go index 8ed55ef1c6d0..c21b01525a51 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -24,12 +24,12 @@ 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/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" ) @@ -42,16 +42,16 @@ func init() { if err != nil { panic(err) } - type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) + type ctorFn = func(*directory.Context, json.RawMessage) (directory.Tracer, error) lookup := func(code string) ctorFn { - return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + return func(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { return newJsTracer(code, ctx, cfg) } } for name, code := range assetTracers { - tracers.DefaultDirectory.Register(name, lookup(code), true) + directory.DefaultDirectory.Register(name, lookup(code), true) } - tracers.DefaultDirectory.RegisterJSEval(newJsTracer) + directory.DefaultDirectory.RegisterJSEval(newJsTracer) } // bigIntProgram is compiled once and the exported function mostly invoked to convert @@ -96,7 +96,7 @@ 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 { - tracers.NoopTracer + directory.NoopTracer vm *goja.Runtime env *vm.EVM @@ -136,7 +136,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 *tracers.Context, cfg json.RawMessage) (tracers.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()) @@ -145,7 +145,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer ctx: make(map[string]goja.Value), } if ctx == nil { - ctx = new(tracers.Context) + ctx = new(directory.Context) } if ctx.BlockHash != (common.Hash{}) { t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) @@ -576,7 +576,7 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { if end < begin || begin < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } - slice, err := tracers.GetMemoryCopyPadded(mo.memory, begin, end-begin) + slice, err := directory.GetMemoryCopyPadded(mo.memory, begin, end-begin) if err != nil { return nil, err } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 4a7d6c5bcdc8..0706690c89c2 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -28,7 +28,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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/params" ) @@ -61,7 +61,7 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer tracers.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}) gasLimit uint64 = 31000 @@ -264,14 +264,14 @@ func TestIsPrecompile(t *testing.T) { func TestEnterExit(t *testing.T) { // test that either both or none of enter() and exit() are defined - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(directory.Context), nil); err == nil { t.Fatal("tracer creation should've failed without exit() definition") } - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(directory.Context), nil); err != nil { t.Fatal(err) } // test that the enter and exit method are correctly invoked and the values passed - tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil) + tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(directory.Context), nil) if err != nil { t.Fatal(err) } @@ -293,7 +293,7 @@ func TestEnterExit(t *testing.T) { func TestSetup(t *testing.T) { // Test empty config - _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil) + _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(directory.Context), nil) if err != nil { t.Error(err) } @@ -303,12 +303,12 @@ func TestSetup(t *testing.T) { t.Fatal(err) } // Test no setup func - _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg) + _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(directory.Context), cfg) if err != nil { t.Fatal(err) } // Test config value - tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg) + tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(directory.Context), cfg) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 8d9952fb5f76..3542c632936c 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -11,10 +11,11 @@ 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" ) func init() { - register("printer", newPrinter) + directory.LiveDirectory.Register("printer", newPrinter) } type Printer struct{} diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index ff7715f2eea4..7df66066b55b 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -17,11 +17,10 @@ package logger import ( - "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" ) // accessList is an accumulator for the set of accounts and storage slots an EVM @@ -103,6 +102,7 @@ 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 } @@ -132,9 +132,6 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } -func (a *AccessListTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { -} - // 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 @@ -158,37 +155,6 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6 } } -func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -func (*AccessListTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -func (*AccessListTracer) OnGasConsumed(gas, amount uint64) {} - -func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} - -func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} - -func (*AccessListTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} - -func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} - -func (*AccessListTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {} - -func (*AccessListTracer) OnNonceChange(a common.Address, prev, new uint64) {} - -func (*AccessListTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { -} - -func (*AccessListTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {} - -func (*AccessListTracer) OnLog(log *types.Log) {} - -func (*AccessListTracer) OnNewAccount(a common.Address) {} - // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 5885782474ba..22294252afc0 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -28,9 +28,9 @@ 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/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" "github.com/holiman/uint256" ) @@ -107,6 +107,7 @@ 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 *vm.EVM @@ -139,10 +140,6 @@ func (l *StructLogger) Reset() { l.err = nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { -} - // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. @@ -211,16 +208,6 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s l.logs = append(l.logs, log) } -// CaptureFault implements the EVMLogger interface to trace an execution fault -// while running an opcode. -func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -func (l *StructLogger) OnGasConsumed(gas, amount uint64) {} - // CaptureEnd is called after the call finishes to finalize the tracing. func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.output = output @@ -233,12 +220,6 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { } } -func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) { -} - func (l *StructLogger) GetResult() (json.RawMessage, error) { // Tracing aborted if l.reason != nil { @@ -280,20 +261,6 @@ func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt, err error) { l.usedGas = receipt.GasUsed } -func (l *StructLogger) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { -} - -func (l *StructLogger) OnNonceChange(a common.Address, prev, new uint64) {} - -func (l *StructLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { -} - -func (l *StructLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} - -func (l *StructLogger) OnLog(log *types.Log) {} - -func (l *StructLogger) OnNewAccount(a common.Address) {} - // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -351,6 +318,7 @@ func WriteLogs(writer io.Writer, logs []*types.Log) { } type mdLogger struct { + directory.NoopTracer out io.Writer cfg *Config env *vm.EVM @@ -408,37 +376,11 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } -func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -func (t *mdLogger) OnGasConsumed(gas, amount uint64) {} - func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) } -func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} - -func (*mdLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} - -func (*mdLogger) CaptureTxEnd(receipt *types.Receipt, err error) {} - -func (*mdLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} - -func (*mdLogger) OnNonceChange(a common.Address, prev, new uint64) {} - -func (*mdLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { -} - -func (*mdLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} - -func (*mdLogger) OnLog(log *types.Log) {} - -func (*mdLogger) OnNewAccount(a common.Address) {} - // 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/logger/logger_json.go b/eth/tracers/logger/logger_json.go index c1e25a1c3a7f..1ea014a0d6ea 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -19,15 +19,16 @@ package logger import ( "encoding/json" "io" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "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 *vm.EVM @@ -43,9 +44,6 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger { return l } -func (l *JSONLogger) CaptureStart(from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { -} - func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { // TODO: Add rData to this interface as well l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) @@ -78,11 +76,6 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco l.encoder.Encode(log) } -// CaptureKeccakPreimage is called during the KECCAK256 opcode. -func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {} - -func (l *JSONLogger) OnGasConsumed(gas, amount uint64) {} - // CaptureEnd is triggered at end of execution. func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { type endLog struct { @@ -97,26 +90,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} - func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { l.env = env } - -func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt, err error) {} - -func (*JSONLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {} - -func (*JSONLogger) OnNonceChange(a common.Address, prev, new uint64) {} - -func (*JSONLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { -} - -func (*JSONLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {} - -func (*JSONLogger) OnLog(log *types.Log) {} - -func (*JSONLogger) OnNewAccount(a common.Address) {} diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 4a7db6e72fc9..e6c3be41cd07 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -60,6 +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, nil) 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/native/4byte.go b/eth/tracers/native/4byte.go index 25152a098eb2..b25ff06ae2b2 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -25,11 +25,11 @@ import ( "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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" ) func init() { - tracers.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false) + directory.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false) } // fourByteTracer searches for 4byte-identifiers, and collects them for post-processing. @@ -47,7 +47,7 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { - tracers.NoopTracer + directory.NoopTracer env *vm.EVM ids map[string]int // ids aggregates the 4byte ids found interrupt atomic.Bool // Atomic flag to signal execution interruption @@ -57,7 +57,7 @@ type fourByteTracer struct { // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { +func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (directory.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 3af18cd3ce53..bb2ea19b54d4 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -27,13 +27,13 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/directory" ) //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go func init() { - tracers.DefaultDirectory.Register("callTracer", newCallTracer, false) + directory.DefaultDirectory.Register("callTracer", newCallTracer, false) } type callLog struct { @@ -99,7 +99,7 @@ type callFrameMarshaling struct { } type callTracer struct { - tracers.NoopTracer + directory.NoopTracer callstack []callFrame config callTracerConfig gasLimit uint64 @@ -115,7 +115,7 @@ type callTracerConfig struct { // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { +func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) { var config callTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 084df593a82d..d5aebc00fd21 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -27,14 +27,14 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/directory" ) //go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go //go:generate go run github.com/fjl/gencodec -type flatCallResult -field-override flatCallResultMarshaling -out gen_flatcallresult_json.go func init() { - tracers.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false) + directory.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false) } var parityErrorMapping = map[string]string{ @@ -109,12 +109,12 @@ 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 { - tracers.NoopTracer + directory.NoopTracer tracer *callTracer config flatCallTracerConfig - ctx *tracers.Context // Holds tracer context data - reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on CaptureStart based on given rules + ctx *directory.Context // Holds tracer context data + reason error // Textual reason for the interruption + activePrecompiles []common.Address // Updated on CaptureStart based on given rules } type flatCallTracerConfig struct { @@ -123,7 +123,7 @@ type flatCallTracerConfig struct { } // newFlatCallTracer returns a new flatCallTracer. -func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.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,7 +133,7 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace // Create inner call tracer with default configuration, don't forward // the OnlyTopCall or WithLog to inner for now - tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil) + tracer, err := directory.DefaultDirectory.New("callTracer", ctx, nil) if err != nil { return nil, err } @@ -244,7 +244,7 @@ func (t *flatCallTracer) isPrecompiled(addr common.Address) bool { return false } -func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) { +func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *directory.Context) (output []flatCallFrame, err error) { var frame *flatCallFrame switch input.Type { case vm.CREATE, vm.CREATE2: @@ -343,7 +343,7 @@ func newFlatSelfdestruct(input *callFrame) *flatCallFrame { } } -func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *tracers.Context) { +func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *directory.Context) { if ctx == nil { return } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 2dcb8f2b2d99..880aca888da2 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -24,32 +24,32 @@ 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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" ) func init() { - tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false) + directory.DefaultDirectory.Register("muxTracer", newMuxTracer, false) } // muxTracer is a go implementation of the Tracer interface which // runs multiple tracers in one go. type muxTracer struct { names []string - tracers []tracers.Tracer + tracers []directory.Tracer } // newMuxTracer returns a new mux tracer. -func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.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([]tracers.Tracer, 0, len(config)) + objects := make([]directory.Tracer, 0, len(config)) names := make([]string, 0, len(config)) for k, v := range config { - t, err := tracers.DefaultDirectory.New(k, ctx, v) + t, err := directory.DefaultDirectory.New(k, ctx, v) if err != nil { return nil, err } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 9375279cb430..71cd7ce79112 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -28,14 +28,14 @@ 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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/log" ) //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go func init() { - tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) + directory.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) } type stateMap = map[common.Address]*account @@ -57,7 +57,7 @@ type accountMarshaling struct { } type prestateTracer struct { - tracers.NoopTracer + directory.NoopTracer env *vm.EVM pre stateMap post stateMap @@ -74,7 +74,7 @@ type prestateTracerConfig struct { DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications } -func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.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 { @@ -143,7 +143,7 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] - init, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(offset.Uint64()), int64(size.Uint64())) + init, err := directory.GetMemoryCopyPadded(scope.Memory, 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 diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 759e3a4dd38e..b9c0ac526d32 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -109,41 +109,3 @@ func BenchmarkTransactionTrace(b *testing.B) { tracer.Reset() } } - -func TestMemCopying(t *testing.T) { - for i, tc := range []struct { - memsize int64 - offset int64 - size int64 - wantErr string - wantSize int - }{ - {0, 0, 100, "", 100}, // Should pad up to 100 - {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 - - } { - mem := vm.NewMemory() - mem.Resize(uint64(tc.memsize)) - cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) - if want := tc.wantErr; want != "" { - if err == nil { - t.Fatalf("test %d: want '%v' have no error", i, want) - } - if have := err.Error(); want != have { - t.Fatalf("test %d: want '%v' have '%v'", i, want, have) - } - continue - } - if err != nil { - t.Fatalf("test %d: unexpected error: %v", i, err) - } - if want, have := tc.wantSize, len(cpy); have != want { - t.Fatalf("test %d: want %v have %v", i, want, have) - } - } -} From 0be6e22eafa003d12d2407ab4f2c6e1488cd85b7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 31 Aug 2023 16:35:43 +0200 Subject: [PATCH 031/100] add comment to statedb logger --- core/state/statedb.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3f52b9f7360d..b3ee524fc1b6 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -56,6 +56,8 @@ func (n *proofList) Delete(key []byte) error { // 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 { From abd880712babb5c251c4d4cb31ea7aed26b4c47c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 31 Aug 2023 18:46:45 +0200 Subject: [PATCH 032/100] use defer for OnBlockEnd --- core/blockchain.go | 203 ++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 103 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 107b0ad9cc38..75c4e3f9bf81 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1774,119 +1774,116 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // Process block using the parent state as reference point pstart := time.Now() - if bc.logger != nil { - td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) - } - receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) - if err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) + // The traced section of block import. + err, stop := func() (blockEndErr error, _ bool) { if bc.logger != nil { - bc.logger.OnBlockEnd(err) + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) + defer func() { + bc.logger.OnBlockEnd(blockEndErr) + }() } - return it.index, err - } - ptime := time.Since(pstart) + receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + if err != nil { + bc.reportBlock(block, receipts, err) + followupInterrupt.Store(true) + return err, true + } + ptime := time.Since(pstart) - vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - if bc.logger != nil { - bc.logger.OnBlockEnd(err) + vstart := time.Now() + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + bc.reportBlock(block, receipts, err) + followupInterrupt.Store(true) + return err, true } - return it.index, err - } - vtime := time.Since(vstart) - proctime := time.Since(start) // processing + validation - - // Update the metrics touched during block processing and validation - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) - accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) - storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) - triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing - trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update - trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read - trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read - blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing - blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation - - // Write the block to the chain and get the status. - var ( - wstart = time.Now() - status WriteStatus - ) - if !setHead { - // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, receipts, statedb) - } else { - status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) - } - followupInterrupt.Store(true) - if err != nil { - if bc.logger != nil { - bc.logger.OnBlockEnd(err) + vtime := time.Since(vstart) + proctime := time.Since(start) // processing + validation + + // Update the metrics touched during block processing and validation + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) + snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) + snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) + accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) + storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) + triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing + trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update + trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read + trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing + blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation + + // Write the block to the chain and get the status. + var ( + wstart = time.Now() + status WriteStatus + ) + if !setHead { + // Don't set the head, only insert the block + err = bc.writeBlockWithState(block, receipts, statedb) + } else { + status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) } - return it.index, err - } - // Update the metrics touched during block commit - accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them - storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them - snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - - blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) - blockInsertTimer.UpdateSince(start) - - // Report the import stats before returning the various results - stats.processed++ - stats.usedGas += usedGas - - dirty, _ := bc.triedb.Size() - stats.report(chain, it.index, dirty, setHead) - - if bc.logger != nil { - bc.logger.OnBlockEnd(nil) - } - - if !setHead { - // After merge we expect few side chains. Simply count - // all blocks the CL gives us for GC processing time - bc.gcproc += proctime + followupInterrupt.Store(true) + if err != nil { + return err, true + } + // Update the metrics touched during block commit + accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them + storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them + snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them + triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - return it.index, nil // Direct block insertion of a single block - } - switch status { - case CanonStatTy: - log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), - "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), - "elapsed", common.PrettyDuration(time.Since(start)), - "root", block.Root()) + blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) + blockInsertTimer.UpdateSince(start) - lastCanon = block + // Report the import stats before returning the various results + stats.processed++ + stats.usedGas += usedGas - // Only count canonical blocks for GC processing time - bc.gcproc += proctime + dirty, _ := bc.triedb.Size() + stats.report(chain, it.index, dirty, setHead) - case SideStatTy: - log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) + if !setHead { + // After merge we expect few side chains. Simply count + // all blocks the CL gives us for GC processing time + bc.gcproc += proctime - default: - // This in theory is impossible, but lets be nice to our future selves and leave - // a log, instead of trying to track down blocks imports that don't emit logs. - log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) + return nil, true // Direct block insertion of a single block + } + switch status { + case CanonStatTy: + log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), + "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), + "elapsed", common.PrettyDuration(time.Since(start)), + "root", block.Root()) + + lastCanon = block + + // Only count canonical blocks for GC processing time + bc.gcproc += proctime + + case SideStatTy: + log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) + + default: + // This in theory is impossible, but lets be nice to our future selves and leave + // a log, instead of trying to track down blocks imports that don't emit logs. + log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) + } + return nil, false + }() + if err != nil || stop { + return it.index, err } } From f7ca31eb78e9b995a3ebd4be481d4135997c355a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 4 Sep 2023 17:51:42 +0200 Subject: [PATCH 033/100] fix import cycle in blockchain test --- core/blockchain_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 1b4b569575a5..b5b9ff4e4880 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -36,7 +36,6 @@ 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/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -3024,7 +3023,7 @@ func TestDeleteRecreateSlots(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout), + //Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -3101,7 +3100,7 @@ func TestDeleteRecreateAccount(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Tracer: logger.NewJSONLogger(nil, os.Stdout), + //Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -4307,7 +4306,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)*/ }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } From 651c4386212a8576da52e4b89c7ddd4f71b011b2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 4 Sep 2023 17:55:01 +0200 Subject: [PATCH 034/100] fix runtime tests --- core/vm/runtime/runtime_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index f411a67f8d9f..51d8cbe62f31 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -32,7 +32,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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/params" @@ -330,7 +330,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { - tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil) + tracer, err := directory.DefaultDirectory.New(tracerCode, new(directory.Context), nil) if err != nil { b.Fatal(err) } @@ -826,7 +826,7 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xee"), calleeCode) statedb.SetCode(common.HexToAddress("0xff"), suicideCode) - tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) + tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil) if err != nil { t.Fatal(err) } @@ -861,7 +861,7 @@ func TestJSTracerCreateTx(t *testing.T) { code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) + tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil) if err != nil { t.Fatal(err) } From 74c1f30811a82dcbb0335a8e1a503f7cb8d5917c Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 12 Sep 2023 08:10:22 -0400 Subject: [PATCH 035/100] Fixed `BlockchainLogger` tracer not being correctly set up up to `Blockchain` object (#17) --- cmd/geth/config.go | 13 +++++++++++++ eth/backend.go | 1 + eth/ethconfig/config.go | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index b6c8004665ec..0c90cbd66bf7 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -36,6 +36,7 @@ import ( ethcatalyst "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" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/version" @@ -176,6 +177,18 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { v := ctx.Uint64(utils.OverrideVerkle.Name) cfg.Eth.OverrideVerkle = &v } + + if ctx.IsSet(utils.VMTraceFlag.Name) { + if name := ctx.String(utils.VMTraceFlag.Name); name != "" { + t, err := directory.LiveDirectory.New(name) + if err != nil { + utils.Fatalf("Failed to create tracer %q: %v", name, err) + } + + cfg.Eth.VMTracer = t + } + } + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Configure log filter RPC API. diff --git a/eth/backend.go b/eth/backend.go index 667200bcedda..bca91051d55a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -182,6 +182,7 @@ 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, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 4bc8b8dc6c6e..9e8be3522038 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -29,6 +29,7 @@ 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/ethdb" @@ -140,6 +141,9 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool + // Enables VM tracing + VMTracer vm.EVMLogger + // Miscellaneous options DocRoot string `toml:"-"` From ff3c15ff90c005fd90d78859d43158de06398fac Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 12 Sep 2023 11:19:15 -0400 Subject: [PATCH 036/100] Full OnGasConsumed loop and added `GasChangeReason` (#16) --- core/state_transition.go | 16 +++++- core/vm/contract.go | 6 +-- core/vm/contracts.go | 2 +- core/vm/evm.go | 95 +++++++++++++++++++++++------------ core/vm/instructions.go | 34 ++++++++++++- core/vm/interpreter.go | 9 +++- core/vm/logger.go | 62 ++++++++++++++++++++++- core/vm/operations_acl.go | 2 +- eth/tracers/directory/noop.go | 4 +- eth/tracers/live/printer.go | 4 +- eth/tracers/native/mux.go | 4 +- 11 files changed, 189 insertions(+), 49 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 645fe669f245..e82297963dd4 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -263,6 +263,11 @@ func (st *StateTransition) buyGas() error { if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } + + if st.evm.Config.Tracer != nil { + st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance) + } + st.gasRemaining += st.msg.GasLimit st.initialGas = st.msg.GasLimit @@ -386,7 +391,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.OnGasConsumed(st.gasRemaining, gas) + t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, vm.GasChangeTxIntrinsicGas) } st.gasRemaining -= gas @@ -452,12 +457,21 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { if refund > st.state.GetRefund() { refund = st.state.GetRefund() } + + if st.evm.Config.Tracer != nil && refund > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, vm.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.BalanceChangeGasRefund) + if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) + } + // Also return remaining gas to the block gas counter so it is // available for the next transaction. st.gp.AddGas(st.gasRemaining) diff --git a/core/vm/contract.go b/core/vm/contract.go index 1d88b0e1b98b..8a194bb12a9f 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -159,12 +159,12 @@ 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) (ok bool) { +func (c *Contract) UseGas(gas uint64, logger EVMLogger, reason GasChangeReason) (ok bool) { if c.Gas < gas { return false } - if logger != nil { - logger.OnGasConsumed(c.Gas, gas) + if logger != nil && reason != GasChangeIgnored { + logger.OnGasChange(c.Gas, c.Gas-gas, reason) } c.Gas -= gas return true diff --git a/core/vm/contracts.go b/core/vm/contracts.go index cb4cc76c02e9..7c1cf888bb31 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -174,7 +174,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin return nil, 0, ErrOutOfGas } if logger != nil { - logger.OnGasConsumed(suppliedGas, gasCost) + logger.OnGasChange(suppliedGas, suppliedGas-gasCost, GasChangeCallPrecompiledContract) } suppliedGas -= gasCost output, err := p.Run(input) diff --git a/core/vm/evm.go b/core/vm/evm.go index beadc501f1e0..cf8dbb158160 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -176,18 +176,10 @@ func (evm *EVM) SetBlockContext(blockCtx BlockContext) { 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 { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) - defer func(startGas uint64) { // Lazy evaluation of the parameters - evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) - }(gas) - } else { - // Handle tracer events for entering and exiting a call frame - evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) - defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) - }(gas) - } + 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) + }(gas) } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { @@ -233,6 +225,10 @@ 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) + } + gas = 0 } // TODO: consider clearing up unused snapshots: @@ -252,9 +248,9 @@ 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.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) + evm.captureBegin(false, CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + evm.captureEnd(false, CALLCODE, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -285,6 +281,10 @@ 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) + } + gas = 0 } } @@ -303,9 +303,9 @@ 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.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value) + evm.captureBegin(false, DELEGATECALL, caller.Address(), addr, input, gas, parent.value) defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + evm.captureEnd(false, DELEGATECALL, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -328,6 +328,10 @@ 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) + } + gas = 0 } } @@ -341,9 +345,9 @@ 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.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) + evm.captureBegin(false, STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { - evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) + evm.captureEnd(false, STATICCALL, startGas, leftOverGas, ret, err) }(gas) } // Fail if we're trying to execute above the call depth limit @@ -383,6 +387,10 @@ 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) + } + gas = 0 } } @@ -402,19 +410,12 @@ 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) { +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 { - if evm.depth == 0 { - evm.Config.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) - defer func() { - evm.Config.Tracer.CaptureEnd(ret, gas-leftoverGas, err) - }() - } else { - evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) - defer func() { - evm.Config.Tracer.CaptureExit(ret, gas-leftoverGas, err) - }() - } + 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) + }(gas) } // Depth check execution. Fail if we're trying to execute above the // limit. @@ -437,6 +438,10 @@ 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) + } + return nil, common.Address{}, 0, ErrContractAddressCollision } // Create a new account on the state @@ -470,7 +475,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) { + if contract.UseGas(createDataGas, evm.Config.Tracer, GasChangeCallCodeStorage) { evm.StateDB.SetCode(address, ret) } else { err = ErrCodeStoreOutOfGas @@ -483,7 +488,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) + contract.UseGas(contract.Gas, evm.Config.Tracer, GasChangeCallFailedExecution) } } @@ -508,3 +513,29 @@ 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) { + 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) + } + + tracer.OnGasChange(0, startGas, 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 isRoot { + tracer.CaptureEnd(ret, startGas-leftOverGas, err) + } else { + tracer.CaptureExit(ret, startGas-leftOverGas, err) + } +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2e5fa9903cbb..cba48aa5595e 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -592,7 +592,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) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation) //TODO: use uint256.Int instead of converting with toBig() var bigVal = big0 if !value.IsZero() { @@ -612,6 +612,11 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b stackvalue.SetBytes(addr.Bytes()) } 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) + } + scope.Contract.Gas += returnGas if suberr == ErrExecutionReverted { @@ -635,7 +640,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] ) // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size //TODO: use uint256.Int instead of converting with toBig() @@ -652,6 +657,11 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } 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) + } + scope.Contract.Gas += returnGas if suberr == ErrExecutionReverted { @@ -697,6 +707,11 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + + if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + } + scope.Contract.Gas += returnGas interpreter.returnData = ret @@ -732,6 +747,11 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + + if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + } + scope.Contract.Gas += returnGas interpreter.returnData = ret @@ -760,6 +780,11 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + + if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + } + scope.Contract.Gas += returnGas interpreter.returnData = ret @@ -788,6 +813,11 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) if err == nil || err == ErrExecutionReverted { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + + if interpreter.evm.Config.Tracer != nil && returnGas > 0 { + interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded) + } + scope.Contract.Gas += returnGas interpreter.returnData = ret diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 14aa9cee2112..82f1e187ac7b 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -185,9 +185,10 @@ 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) { + if !contract.UseGas(cost, in.evm.Config.Tracer, GasChangeIgnored) { return nil, ErrOutOfGas } + if operation.dynamicGas != nil { // All ops with a dynamic memory usage also has a dynamic gas cost. var memorySize uint64 @@ -211,11 +212,13 @@ 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) { + if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, 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, err) logged = true } @@ -223,9 +226,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( 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, err) logged = true } + // execute the operation res, err = operation.execute(&pc, in, callContext) if err != nil { diff --git a/core/vm/logger.go b/core/vm/logger.go index 04084115000a..a675563821b1 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -43,5 +43,65 @@ type EVMLogger interface { CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) CaptureKeccakPreimage(hash common.Hash, data []byte) // Misc - OnGasConsumed(gas, amount uint64) + 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 6dcd02bc0518..55c9bf34b952 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -169,7 +169,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) { + if !contract.UseGas(coldCost, evm.Config.Tracer, GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } } diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 06902061f41c..973b1abb4735 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -58,8 +58,8 @@ func (t *NoopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ * // CaptureKeccakPreimage is called during the KECCAK256 opcode. func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {} -// OnGasConsumed is called when gas is consumed. -func (t *NoopTracer) OnGasConsumed(gas, amount uint64) {} +// OnGasChange is called when gas is either consumed or refunded. +func (t *NoopTracer) OnGasChange(old, new uint64, reason vm.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) { diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 3542c632936c..1f51a6fc3f10 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -126,6 +126,6 @@ func (p *Printer) OnNewAccount(a common.Address) { fmt.Printf("OnNewAccount: a=%v\n", a) } -func (p *Printer) OnGasConsumed(gas, amount uint64) { - fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount) +func (p *Printer) OnGasChange(old, new uint64, reason vm.GasChangeReason) { + fmt.Printf("OnGasChange: old=%v, new=%v, diff=%v\n", old, new, new-old) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 880aca888da2..dab284a3a318 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -96,9 +96,9 @@ func (t *muxTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) { } // CaptureGasConsumed is called when gas is consumed. -func (t *muxTracer) OnGasConsumed(gas, amount uint64) { +func (t *muxTracer) OnGasChange(old, new uint64, reason vm.GasChangeReason) { for _, t := range t.tracers { - t.OnGasConsumed(gas, amount) + t.OnGasChange(old, new, reason) } } From 1914bc6ed068d5fde08d4876a00ad1c5493a4fb8 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 27 Oct 2023 11:49:52 -0400 Subject: [PATCH 037/100] error code for VM failures (#18) * Experimental: EVMLogger fixed error code * First pass of review * Move error to `core/vm/errors.go`, ensure also we strictly implement `rpc.Error` (without depending on it) --- core/state/statedb_test.go | 2 +- core/vm/errors.go | 123 +++++++++++++++++++++++++++++++++++++ core/vm/evm.go | 4 +- core/vm/interpreter.go | 8 +-- 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 4be95bb7ff04..15842fa86d0b 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -1148,7 +1148,7 @@ func TestDeleteStorage(t *testing.T) { addr = common.HexToAddress("0x1") ) // Initialize account and populate storage - state.SetBalance(addr, big.NewInt(1)) + state.SetBalance(addr, big.NewInt(1), 0x0) state.CreateAccount(addr) for i := 0; i < 1000; i++ { slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) diff --git a/core/vm/errors.go b/core/vm/errors.go index fbbf19e178bf..f6e4b6acd0eb 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -19,6 +19,7 @@ package vm import ( "errors" "fmt" + "math" ) // List evm execution errors @@ -71,3 +72,125 @@ type ErrInvalidOpCode struct { } func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) } + +// rpcError is the same interface as the one defined in rpc/errors.go +// but we do not want to depend on rpc package here so we redefine it. +// +// It's used to ensure that the VMError implements the RPC error interface. +type rpcError interface { + Error() string // returns the message + ErrorCode() int // returns the code +} + +var _ rpcError = (*VMError)(nil) + +// VMError wraps a VM error with an additional stable error code. The error +// field is the original error that caused the VM error and must be one of the +// VM error defined at the top of this file. +// +// If the error is not one of the known error above, the error code will be +// set to VMErrorCodeUnknown. +type VMError struct { + error + code int +} + +func VMErrorFromErr(err error) error { + if err == nil { + return nil + } + + return &VMError{ + error: err, + code: vmErrorCodeFromErr(err), + } +} + +func (e *VMError) Error() string { + return e.error.Error() +} + +func (e *VMError) Unwrap() error { + return errors.Unwrap(e.error) +} + +func (e *VMError) ErrorCode() int { + return e.code +} + +const ( + // We start the error code at 1 so that we can use 0 later for some possible extension. There + // is no unspecified value for the code today because it should always be set to a valid value + // that could be VMErrorCodeUnknown if the error is not mapped to a known error code. + + VMErrorCodeOutOfGas = 1 + iota + VMErrorCodeCodeStoreOutOfGas + VMErrorCodeDepth + VMErrorCodeInsufficientBalance + VMErrorCodeContractAddressCollision + VMErrorCodeExecutionReverted + VMErrorCodeMaxInitCodeSizeExceeded + VMErrorCodeMaxCodeSizeExceeded + VMErrorCodeInvalidJump + VMErrorCodeWriteProtection + VMErrorCodeReturnDataOutOfBounds + VMErrorCodeGasUintOverflow + VMErrorCodeInvalidCode + VMErrorCodeNonceUintOverflow + VMErrorCodeStackUnderflow + VMErrorCodeStackOverflow + VMErrorCodeInvalidOpCode + + // VMErrorCodeUnknown explicitly marks an error as unknown, this is useful when error is converted + // from an actual `error` in which case if the mapping is not known, we can use this value to indicate that. + VMErrorCodeUnknown = math.MaxInt - 1 +) + +func vmErrorCodeFromErr(err error) int { + switch { + case errors.Is(err, ErrOutOfGas): + return VMErrorCodeOutOfGas + case errors.Is(err, ErrCodeStoreOutOfGas): + return VMErrorCodeCodeStoreOutOfGas + case errors.Is(err, ErrDepth): + return VMErrorCodeDepth + case errors.Is(err, ErrInsufficientBalance): + return VMErrorCodeInsufficientBalance + case errors.Is(err, ErrContractAddressCollision): + return VMErrorCodeContractAddressCollision + case errors.Is(err, ErrExecutionReverted): + return VMErrorCodeExecutionReverted + case errors.Is(err, ErrMaxInitCodeSizeExceeded): + return VMErrorCodeMaxInitCodeSizeExceeded + case errors.Is(err, ErrMaxCodeSizeExceeded): + return VMErrorCodeMaxCodeSizeExceeded + case errors.Is(err, ErrInvalidJump): + return VMErrorCodeInvalidJump + case errors.Is(err, ErrWriteProtection): + return VMErrorCodeWriteProtection + case errors.Is(err, ErrReturnDataOutOfBounds): + return VMErrorCodeReturnDataOutOfBounds + case errors.Is(err, ErrGasUintOverflow): + return VMErrorCodeGasUintOverflow + case errors.Is(err, ErrInvalidCode): + return VMErrorCodeInvalidCode + case errors.Is(err, ErrNonceUintOverflow): + return VMErrorCodeNonceUintOverflow + + default: + // Dynamic errors + if v := (*ErrStackUnderflow)(nil); errors.As(err, &v) { + return VMErrorCodeStackUnderflow + } + + if v := (*ErrStackOverflow)(nil); errors.As(err, &v) { + return VMErrorCodeStackOverflow + } + + if v := (*ErrInvalidOpCode)(nil); errors.As(err, &v) { + return VMErrorCodeInvalidOpCode + } + + return VMErrorCodeUnknown + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 5824c4628e1c..fbb3428b5db5 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -534,8 +534,8 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas } if isRoot { - tracer.CaptureEnd(ret, startGas-leftOverGas, err) + tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err)) } else { - tracer.CaptureExit(ret, startGas-leftOverGas, err) + tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err)) } } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 82f1e187ac7b..34f13f55bf28 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -158,9 +158,9 @@ 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, err) + 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, err) + in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) } } }() @@ -219,7 +219,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // 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, err) + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } if memorySize > 0 { @@ -227,7 +227,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } } 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, err) + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true } From e65f14afa73538328461959c9777f361b1b619b7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 2 Nov 2023 17:09:54 +0100 Subject: [PATCH 038/100] update state processor --- core/state_processor.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index ff253e887c82..19c4e019cb87 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -66,7 +66,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockNumber = block.Number() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) - err error ) // Mutate the block and state according to any hard-fork specs @@ -83,15 +82,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - var msg *Message - msg, err = TransactionToMessage(tx, signer, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, header.BaseFee) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - var receipt *types.Receipt - receipt, err = applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -101,8 +98,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Fail if Shanghai not enabled and len(withdrawals) is non-zero. withdrawals := block.Withdrawals() if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) { - err = errors.New("withdrawals before shanghai") - return nil, nil, 0, err + return nil, nil, 0, errors.New("withdrawals before shanghai") } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) @@ -110,11 +106,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { - var ( - receipt *types.Receipt - err error - ) +func applyTransaction(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) defer func() { From e4399a672a1a5e4faf6a51c7a3e6a4f9fb3bd79d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 3 Nov 2023 16:59:24 +0100 Subject: [PATCH 039/100] Use applyTransaction in tracer instead of applyMessage --- core/state_processor.go | 9 ++++++--- eth/tracers/api.go | 22 ++++++---------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 19c4e019cb87..1517e2c0c9ed 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -88,7 +88,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } statedb.SetTxContext(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -106,7 +106,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(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) { +// ApplyTransactionWithEVM attempts to apply a transaction to the given state database +// and uses the input parameters for its environment similar to ApplyTransaction. However, +// this method takes an already created EVM instance as input. +func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *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) defer func() { @@ -175,7 +178,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo blockContext := NewEVMBlockContext(header, bc, author) txContext := NewEVMTxContext(msg) vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg) - return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) + return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root diff --git a/eth/tracers/api.go b/eth/tracers/api.go index b41c3d5d5bc0..c1fb506e3845 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -284,8 +284,6 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} } // Tracing state is used up, queue it for de-referencing. Note the @@ -599,7 +597,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac var ( txs = block.Transactions() blockHash = block.Hash() - is158 = api.backend.ChainConfig().IsEIP158(block.Number()) blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*txTraceResult, len(txs)) @@ -618,9 +615,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac return nil, err } results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} - // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(is158) } return results, nil } @@ -935,10 +929,10 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // be tracer dependent. 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 - txContext = core.NewEVMTxContext(message) + tracer directory.Tracer + err error + timeout = defaultTraceTimeout + usedGas uint64 ) if config == nil { config = &TraceConfig{} @@ -951,7 +945,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor return nil, err } } - vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) statedb.SetLogger(tracer) // Define a meaningful timeout of a single transaction trace @@ -973,14 +967,10 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - tracer.CaptureTxStart(vmenv, tx) - res, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)) + _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv) if err != nil { - tracer.CaptureTxEnd(nil, err) return nil, fmt.Errorf("tracing failed: %w", err) } - r := &types.Receipt{GasUsed: res.UsedGas} - tracer.CaptureTxEnd(r, nil) return tracer.GetResult() } From 14d603b009b861758a6ee04ee14f58a946f88cbd Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 3 Nov 2023 17:20:15 +0100 Subject: [PATCH 040/100] add comment re newAccount precompile --- core/state/statedb.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 7111a208594b..1ea386876fce 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -59,6 +59,8 @@ type StateLogger interface { 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) + // OnNewAccount is called when a new account is created. + // Note: it will be even invoked when precompiled contracts are populated. OnNewAccount(addr common.Address) } From 023ade6d3d7d908317201d75028e85e91721cdbf Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 3 Nov 2023 17:26:52 +0100 Subject: [PATCH 041/100] instrument when inserting known block --- core/blockchain.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index 45b08926939f..f24170194778 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1802,6 +1802,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } stats.processed++ + if bc.logger != nil { + bc.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) + bc.logger.OnBlockEnd(nil) + } // We can assume that logs are empty here, since the only way for consecutive // Clique blocks to have the same state is if there are no transactions. From ee58cc79d9dd4631e87cad30338543324434f20d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 7 Nov 2023 15:41:58 +0300 Subject: [PATCH 042/100] statedb: precompile check before onNewAccount --- cmd/geth/chaincmd.go | 2 +- core/state/statedb.go | 20 ++++++++++++++++++-- core/state_processor.go | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 2627c6caf369..587856b2bf5d 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -215,7 +215,7 @@ func initGenesis(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false) defer triedb.Close() - _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) + _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides, nil) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 1ea386876fce..112f10478362 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -123,6 +123,9 @@ 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 @@ -179,6 +182,7 @@ 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(), @@ -656,9 +660,12 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) newobj = newObject(s, addr, nil) if prev == nil { s.journal.append(createObjectChange{account: &addr}) - // TODO: add isPrecompile check if s.logger != nil { - s.logger.OnNewAccount(addr) + // 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) + } } } else { // The original account should be marked as destructed and all cached @@ -1372,6 +1379,15 @@ 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) { + s.precompiles = make(map[common.Address]struct{}) + 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 1517e2c0c9ed..e2e2fe1a024f 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -75,11 +75,13 @@ 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) } + 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) From dc1175e3e1e18d8f498a5f9301ed53029bab22fb Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:35:13 +0300 Subject: [PATCH 043/100] rm unnecessary line Co-authored-by: Delweng --- eth/tracers/native/prestate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 71cd7ce79112..f3298e7599f9 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -169,7 +169,6 @@ func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) } else { t.to = *tx.To() - t.create = false } t.lookupAccount(from) From da8b36276f22453e26751b730d197dcecf4debc2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 7 Nov 2023 22:40:44 +0300 Subject: [PATCH 044/100] minor --- core/blockchain.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index f24170194778..80107d495a4f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -293,7 +293,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // 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. - // TODO: pass in blockchainLogger here to catch genesis block and allocs chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, logger) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr From 0d268b796cc8a01533b8eaa46ac1607050660c58 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 8 Nov 2023 19:28:42 +0300 Subject: [PATCH 045/100] fix TxStart for traceCall --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/state_processor.go | 2 +- core/vm/logger.go | 4 +++- core/vm/runtime/runtime.go | 6 +++--- eth/tracers/api.go | 2 +- eth/tracers/directory/noop.go | 2 +- eth/tracers/internal/tracetest/calltrace_test.go | 4 ++-- eth/tracers/internal/tracetest/flat_calltrace_test.go | 2 +- eth/tracers/internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/goja.go | 2 +- eth/tracers/js/tracer_test.go | 6 +++--- eth/tracers/live/printer.go | 2 +- eth/tracers/logger/logger.go | 2 +- eth/tracers/logger/logger_json.go | 2 +- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/native/4byte.go | 2 +- eth/tracers/native/call.go | 2 +- eth/tracers/native/call_flat.go | 4 ++-- eth/tracers/native/mux.go | 4 ++-- eth/tracers/native/prestate.go | 9 +-------- 20 files changed, 29 insertions(+), 34 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 4dc9aa264d41..532e36fd1e1a 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -234,7 +234,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) - tracer.CaptureTxStart(evm, tx) + tracer.CaptureTxStart(evm, tx, msg.From) // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { diff --git a/core/state_processor.go b/core/state_processor.go index e2e2fe1a024f..d2740a1bdc03 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -113,7 +113,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(evm, tx) + evm.Config.Tracer.CaptureTxStart(evm, tx, msg.From) defer func() { evm.Config.Tracer.CaptureTxEnd(receipt, err) }() diff --git a/core/vm/logger.go b/core/vm/logger.go index a675563821b1..94c499b0a418 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -30,7 +30,9 @@ import ( // if you need to retain them beyond the current call. type EVMLogger interface { // Transaction level - CaptureTxStart(evm *EVM, tx *types.Transaction) + // 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) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 57b367a5290e..37bf38303c11 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -122,7 +122,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.EVMConfig.Tracer.CaptureTxStart(vmenv, 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) @@ -158,7 +158,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.EVMConfig.Tracer.CaptureTxStart(vmenv, 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) @@ -189,7 +189,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.EVMConfig.Tracer.CaptureTxStart(vmenv, 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/eth/tracers/api.go b/eth/tracers/api.go index c1fb506e3845..9278bb74a15c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -784,7 +784,7 @@ 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, tx) + vmConf.Tracer.CaptureTxStart(vmenv, 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 { diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 973b1abb4735..f02884e33b5e 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -70,7 +70,7 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } -func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {} +func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) {} func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt, err error) {} diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 6a17693a40f0..4c30cddf0929 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -153,7 +153,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx) + tracer.CaptureTxStart(evm, 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) @@ -401,7 +401,7 @@ func TestInternals(t *testing.T) { if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) } - tc.tracer.CaptureTxStart(evm, tx) + tc.tracer.CaptureTxStart(evm, 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 dcd59d25667f..4b56dfd6b9b1 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -113,7 +113,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx) + tracer.CaptureTxStart(evm, 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 1a371d2715ee..9a9189e3994d 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -122,7 +122,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - tracer.CaptureTxStart(evm, tx) + tracer.CaptureTxStart(evm, 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/goja.go b/eth/tracers/js/goja.go index c21b01525a51..021ae9d10482 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -214,7 +214,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (dire // CaptureTxStart implements the Tracer interface and is invoked at the beginning of // transaction processing. -func (t *jsTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (t *jsTracer) CaptureTxStart(env *vm.EVM, 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} diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 0706690c89c2..a247b993187a 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -74,7 +74,7 @@ func runTrace(tracer directory.Tracer, vmctx *vmContext, chaincfg *params.ChainC contract.Code = contractCode } - tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{Gas: gasLimit})) + tracer.CaptureTxStart(env, 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) @@ -185,7 +185,7 @@ func TestHaltBetweenSteps(t *testing.T) { 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{})) + tracer.CaptureTxStart(env, 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") @@ -207,7 +207,7 @@ func TestNoStepExec(t *testing.T) { 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{})) + tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 1f51a6fc3f10..27657ae56e9a 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -58,7 +58,7 @@ func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) { fmt.Printf("CaptureExit: output=%s, gasUsed=%v, err=%v\n", hexutil.Bytes(output), gasUsed, err) } -func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +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) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 22294252afc0..6ca12846ad51 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -246,7 +246,7 @@ func (l *StructLogger) Stop(err error) { l.interrupt.Store(true) } -func (l *StructLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (l *StructLogger) CaptureTxStart(env *vm.EVM, 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 1ea014a0d6ea..96d6f1a1010d 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -90,6 +90,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } -func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (l *JSONLogger) CaptureTxStart(env *vm.EVM, 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 e6c3be41cd07..a244e3f9ca1b 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -60,7 +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, nil) + logger.CaptureTxStart(env, 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/native/4byte.go b/eth/tracers/native/4byte.go index b25ff06ae2b2..c7c45cfaa429 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -80,7 +80,7 @@ func (t *fourByteTracer) store(id []byte, size int) { t.ids[key] += 1 } -func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (t *fourByteTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { t.env = env // 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) diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index bb2ea19b54d4..6f1654d3f12b 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -196,7 +196,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (t *callTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (t *callTracer) CaptureTxStart(env *vm.EVM, 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 d5aebc00fd21..dbbe6901a348 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -200,8 +200,8 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *flatCallTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { - t.tracer.CaptureTxStart(env, tx) +func (t *flatCallTracer) CaptureTxStart(env *vm.EVM, 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) t.activePrecompiles = vm.ActivePrecompiles(rules) diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index dab284a3a318..c39d84087667 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -117,9 +117,9 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } } -func (t *muxTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (t *muxTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { for _, t := range t.tracers { - t.CaptureTxStart(env, tx) + t.CaptureTxStart(env, tx, from) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index f3298e7599f9..a53a42ab1b93 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -19,7 +19,6 @@ package native import ( "bytes" "encoding/json" - "fmt" "math/big" "sync/atomic" @@ -156,14 +155,8 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) { +func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { t.env = env - signer := types.MakeSigner(env.ChainConfig(), env.Context.BlockNumber, env.Context.Time) - from, err := types.Sender(signer, tx) - if err != nil { - t.Stop(fmt.Errorf("could not recover sender address: %v", err)) - return - } if tx.To() == nil { t.create = true t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) From cc6b68eb3b5e1675277b2a7d6551865d44a25eba Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Sat, 11 Nov 2023 16:29:50 +0300 Subject: [PATCH 046/100] Fix prestate create issue, add test --- .../internal/tracetest/calltrace_test.go | 2 +- eth/tracers/native/prestate.go | 102 ++++++++---------- 2 files changed, 44 insertions(+), 60 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 4c30cddf0929..f569817aca6e 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -368,7 +368,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("prestateTracer", nil), - want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"},"0x91ff9a805d36f54e3e272e230f3e3f5c1b330804":{"balance":"0x0"}}`, originHex), + want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex), }, } { t.Run(tc.name, func(t *testing.T) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index a53a42ab1b93..b59834ff5d08 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -44,6 +44,7 @@ type account struct { Code []byte `json:"code,omitempty"` Nonce uint64 `json:"nonce,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + empty bool } func (a *account) exists() bool { @@ -89,25 +90,6 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (directory.T }, nil } -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *prestateTracer) 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 *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - if t.config.DiffMode { - return - } - - if t.create { - // Keep existing account prior to contract creation at that address - if s := t.pre[t.to]; s != nil && !s.exists() { - // Exclude newly created contract. - delete(t.pre, t.to) - } - } -} - // 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) { if err != nil { @@ -158,8 +140,8 @@ 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) { t.env = env if tx.To() == nil { - t.create = true t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from)) + t.created[t.to] = true } else { t.to = *tx.To() } @@ -167,20 +149,50 @@ func (t *prestateTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from t.lookupAccount(from) t.lookupAccount(t.to) t.lookupAccount(env.Context.Coinbase) - - if t.create && t.config.DiffMode { - t.created[t.to] = true - } } func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt, err error) { - if !t.config.DiffMode { + if err != nil { return } + if t.config.DiffMode { + t.processDiffState() + } + // the new created contracts' prestate were empty, so delete them + for a := range t.created { + // the created contract maybe exists in statedb before the creating tx + if s := t.pre[a]; s != nil && s.empty { + delete(t.pre, a) + } + } +} + +// GetResult returns the json-encoded nested list of call traces, and any +// error arising from the encoding or forceful termination (via `Stop`). +func (t *prestateTracer) GetResult() (json.RawMessage, error) { + var res []byte + var err error + if t.config.DiffMode { + res, err = json.Marshal(struct { + Post stateMap `json:"post"` + Pre stateMap `json:"pre"` + }{t.post, t.pre}) + } else { + res, err = json.Marshal(t.pre) + } if err != nil { - return + return nil, err } + return json.RawMessage(res), t.reason +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *prestateTracer) Stop(err error) { + t.reason = err + t.interrupt.Store(true) +} +func (t *prestateTracer) processDiffState() { for addr, state := range t.pre { // The deleted account's state is pruned from `post` but kept in `pre` if _, ok := t.deleted[addr]; ok { @@ -230,38 +242,6 @@ func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt, err error) { delete(t.pre, addr) } } - // the new created contracts' prestate were empty, so delete them - for a := range t.created { - // the created contract maybe exists in statedb before the creating tx - if s := t.pre[a]; s != nil && !s.exists() { - delete(t.pre, a) - } - } -} - -// GetResult returns the json-encoded nested list of call traces, and any -// error arising from the encoding or forceful termination (via `Stop`). -func (t *prestateTracer) GetResult() (json.RawMessage, error) { - var res []byte - var err error - if t.config.DiffMode { - res, err = json.Marshal(struct { - Post stateMap `json:"post"` - Pre stateMap `json:"pre"` - }{t.post, t.pre}) - } else { - res, err = json.Marshal(t.pre) - } - if err != nil { - return nil, err - } - return json.RawMessage(res), t.reason -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *prestateTracer) Stop(err error) { - t.reason = err - t.interrupt.Store(true) } // lookupAccount fetches details of an account and adds it to the prestate @@ -271,12 +251,16 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { return } - t.pre[addr] = &account{ + acc := &account{ Balance: t.env.StateDB.GetBalance(addr), Nonce: t.env.StateDB.GetNonce(addr), Code: t.env.StateDB.GetCode(addr), Storage: make(map[common.Hash]common.Hash), } + if !acc.exists() { + acc.empty = true + } + t.pre[addr] = acc } // lookupStorage fetches the requested storage slot and adds From 6b8d2165789d2bed938379b76b871d7ca37e7ed8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 13 Nov 2023 12:17:17 +0300 Subject: [PATCH 047/100] fix setBalance reasons --- accounts/abi/bind/backends/simulated.go | 2 +- core/state/state_test.go | 8 ++--- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_test.go | 40 +++++++++++------------ core/state/trie_prefetcher_test.go | 6 ++-- core/txpool/legacypool/legacypool_test.go | 4 +-- eth/api_debug_test.go | 2 +- internal/ethapi/api.go | 14 ++++---- light/odr_test.go | 2 +- tests/state_test_util.go | 2 +- 10 files changed, 41 insertions(+), 41 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 9667077c64b4..3bb0e8651b91 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -681,7 +681,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, 0x0) + from.SetBalance(math.MaxBig256, state.BalanceChangeUnspecified) // Execute the call. msg := &core.Message{ diff --git a/core/state/state_test.go b/core/state/state_test.go index d1d618640545..08968a6cc16a 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -53,7 +53,7 @@ func TestDump(t *testing.T) { 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), 0x0) + obj3.SetBalance(big.NewInt(44), BalanceChangeUnspecified) // write some of them to the trie s.state.updateStateObject(obj1) @@ -107,7 +107,7 @@ func TestIterativeDump(t *testing.T) { 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), 0x0) + obj3.SetBalance(big.NewInt(44), BalanceChangeUnspecified) obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00})) obj4.AddBalance(big.NewInt(1337), 0x0) @@ -205,7 +205,7 @@ func TestSnapshot2(t *testing.T) { // db, trie are already non-empty values so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(big.NewInt(42), 0x0) + so0.SetBalance(big.NewInt(42), BalanceChangeUnspecified) so0.SetNonce(43) so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) so0.selfDestructed = false @@ -217,7 +217,7 @@ func TestSnapshot2(t *testing.T) { // and one with deleted == true so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(big.NewInt(52), 0x0) + so1.SetBalance(big.NewInt(52), 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 e2524b4b1373..592d34b466c5 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -60,7 +60,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]), 0) + s.SetBalance(addr, big.NewInt(a.args[0]), BalanceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 15842fa86d0b..4f4c7b3b2ede 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -91,7 +91,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)), 0x0) + state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i+tweak)) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) @@ -266,7 +266,7 @@ 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]), 0x0) + s.SetBalance(addr, big.NewInt(a.args[0]), BalanceChangeUnspecified) }, args: make([]int64, 1), }, @@ -554,7 +554,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), 0x0) + state.SetBalance(addr, big.NewInt(42), BalanceChangeUnspecified) if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { t.Fatalf("1st copy fail, expected 42, got %v", got) @@ -577,9 +577,9 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), 0x0) // 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), 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 +650,9 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), 0x0) // 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), 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 +719,9 @@ func TestCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), 0) // 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), 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 +768,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), 0x0) + state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) root, _ := state.Commit(0, false) state, _ = New(root, state.db, state.snaps) @@ -778,7 +778,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.Finalise(true) id := state.Snapshot() - state.SetBalance(addr, big.NewInt(2), 0x0) + state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state @@ -820,10 +820,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), 0x0) + state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) state.SetCode(addr, []byte{1, 2, 3}) a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, big.NewInt(100), 0x0) + state.SetBalance(a2, big.NewInt(100), BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}) root, _ = state.Commit(0, false) t.Logf("root: %x", root) @@ -848,7 +848,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), 0x0) + state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) root, err := state.Commit(0, false) if err == nil { t.Fatalf("expected error, got root :%x", root) @@ -1116,13 +1116,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), 0x0) + state.SetBalance(addr, big.NewInt(1), 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), 0x0) + state.SetBalance(addr, big.NewInt(2), BalanceChangeUnspecified) state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) root, _ := state.Commit(0, true) @@ -1148,7 +1148,7 @@ func TestDeleteStorage(t *testing.T) { addr = common.HexToAddress("0x1") ) // Initialize account and populate storage - state.SetBalance(addr, big.NewInt(1), 0x0) + state.SetBalance(addr, big.NewInt(1), BalanceChangeUnspecified) state.CreateAccount(addr) for i := 0; i < 1000; i++ { slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 79a0f7f3c32c..a376c790c3d7 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -34,9 +34,9 @@ func filledStateDB() *StateDB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42), 0x0) // 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), 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/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 6de0e0e7f6d1..9621f5eb17dc 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -255,7 +255,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), 0x0) + c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), state.BalanceChangeUnspecified) *c.trigger = false } return stdb, nil @@ -275,7 +275,7 @@ func TestStateChangeDuringReset(t *testing.T) { ) // setup pool with 2 transaction in it - statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), 0x0) + statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), state.BalanceChangeUnspecified) blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index f6df9733f585..b93afbab06f2 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -72,7 +72,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), 0x0) + sdb.SetBalance(addrs[i], big.NewInt(1), state.BalanceChangeUnspecified) if _, ok := m[addr]; ok { t.Fatalf("bad") } else { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c1fa84a8d36..4f792260ede3 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -945,41 +945,41 @@ type OverrideAccount struct { type StateOverride map[common.Address]OverrideAccount // Apply overrides the fields of specified accounts into the given state. -func (diff *StateOverride) Apply(state *state.StateDB) error { +func (diff *StateOverride) Apply(statedb *state.StateDB) error { if diff == nil { return nil } for addr, account := range *diff { // Override account nonce. if account.Nonce != nil { - state.SetNonce(addr, uint64(*account.Nonce)) + statedb.SetNonce(addr, uint64(*account.Nonce)) } // Override account(contract) code. if account.Code != nil { - state.SetCode(addr, *account.Code) + statedb.SetCode(addr, *account.Code) } // Override account balance. if account.Balance != nil { - state.SetBalance(addr, (*big.Int)(*account.Balance), 0x0) + statedb.SetBalance(addr, (*big.Int)(*account.Balance), state.BalanceChangeUnspecified) } if account.State != nil && account.StateDiff != nil { return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) } // Replace entire state if caller requires. if account.State != nil { - state.SetStorage(addr, *account.State) + statedb.SetStorage(addr, *account.State) } // Apply state diff into specified accounts. if account.StateDiff != nil { for key, value := range *account.StateDiff { - state.SetState(addr, key, value) + statedb.SetState(addr, key, value) } } } // Now finalize the changes. Finalize is normally performed between transactions. // By using finalize, the overrides are semantically behaving as // if they were created in a transaction just before the tracing occur. - state.Finalise(false) + statedb.Finalise(false) return nil } diff --git a/light/odr_test.go b/light/odr_test.go index 72571cd8ed12..44450fc2ff74 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -201,7 +201,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } // Perform read-only call. - st.SetBalance(testBankAddress, math.MaxBig256, 0x0) + st.SetBalance(testBankAddress, math.MaxBig256, state.BalanceChangeUnspecified) msg := &core.Message{ From: testBankAddress, To: &testContractAddr, diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 05e19ed742a2..1478eb3d28a4 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -322,7 +322,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, 0x0) + statedb.SetBalance(addr, a.Balance, state.BalanceChangeUnspecified) for k, v := range a.Storage { statedb.SetState(addr, k, v) } From b80aa1efb8c02bf262d5cc20c2d02848da6ef319 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 12:35:20 +0330 Subject: [PATCH 048/100] fix double-allocation --- core/state/statedb.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 112f10478362..7460a0f67067 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1382,7 +1382,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d // 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) { - s.precompiles = make(map[common.Address]struct{}) for _, addr := range precompiles { s.precompiles[addr] = struct{}{} } From 1d136450d8ea7ef49daa62a49ba61cb3c86319e3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 12:39:47 +0330 Subject: [PATCH 049/100] move balance reason to metadata file --- core/state/metadata.go | 39 ++++++++++++++++++++++++++++++++++++++ core/state/state_object.go | 22 --------------------- 2 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 core/state/metadata.go diff --git a/core/state/metadata.go b/core/state/metadata.go new file mode 100644 index 000000000000..9e78e6816f5a --- /dev/null +++ b/core/state/metadata.go @@ -0,0 +1,39 @@ +// 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 = iota + BalanceChangeRewardMineUncle + BalanceChangeRewardMineBlock + BalanceChangeDaoRefundContract + BalanceChangeDaoAdjustBalance + BalanceChangeTransfer + BalanceChangeGenesisBalance + BalanceChangeGasBuy + BalanceChangeRewardTransactionFee + BalanceChangeGasRefund + BalanceChangeTouchAccount + BalanceChangeSuicideRefund + BalanceChangeSuicideWithdraw + BalanceChangeBurn + BalanceChangeWithdrawal +) diff --git a/core/state/state_object.go b/core/state/state_object.go index 9480bb83ff7b..f9cc0109a286 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -54,28 +54,6 @@ func (s Storage) Copy() Storage { return cpy } -// BalanceChangeReason is used to indicate the reason for a balance change, useful -// for tracing and reporting. -type BalanceChangeReason byte - -const ( - BalanceChangeUnspecified BalanceChangeReason = iota - BalanceChangeRewardMineUncle - BalanceChangeRewardMineBlock - BalanceChangeDaoRefundContract - BalanceChangeDaoAdjustBalance - BalanceChangeTransfer - BalanceChangeGenesisBalance - BalanceChangeGasBuy - BalanceChangeRewardTransactionFee - BalanceChangeGasRefund - BalanceChangeTouchAccount - BalanceChangeSuicideRefund - BalanceChangeSuicideWithdraw - BalanceChangeBurn - BalanceChangeWithdrawal -) - // stateObject represents an Ethereum account which is being modified. // // The usage pattern is as follows: From 856c0791a6aab7b079c4e410c21b9c39801d4df1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 14:37:29 +0330 Subject: [PATCH 050/100] move traced block processing to own func --- core/blockchain.go | 233 ++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 110 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 80107d495a4f..b427f06c258c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1848,124 +1848,56 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } } - // Process block using the parent state as reference point - pstart := time.Now() - // The traced section of block import. - err, stop := func() (blockEndErr error, _ bool) { - if bc.logger != nil { - td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) - defer func() { - bc.logger.OnBlockEnd(blockEndErr) - }() - } - receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) - if err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return err, true - } - ptime := time.Since(pstart) + err, stop, res := bc.processBlock(block, statedb, followupInterrupt, start, setHead) + if err != nil || stop { + return it.index, err + } + // Report the import stats before returning the various results + stats.processed++ + stats.usedGas += res.usedGas - vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { - bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return err, true - } - vtime := time.Since(vstart) - proctime := time.Since(start) // processing + validation - - // Update the metrics touched during block processing and validation - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) - accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) - storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) - triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing - trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update - trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read - trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read - blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing - blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation - - // Write the block to the chain and get the status. - var ( - wstart = time.Now() - status WriteStatus - ) - if !setHead { - // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, receipts, statedb) - } else { - status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) - } - followupInterrupt.Store(true) - if err != nil { - return err, true - } - // Update the metrics touched during block commit - accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them - storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them - snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them + var snapDiffItems, snapBufItems common.StorageSize + if bc.snaps != nil { + snapDiffItems, snapBufItems = bc.snaps.Size() + } + trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() + stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, setHead) - blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) - blockInsertTimer.UpdateSince(start) + if !setHead { + // After merge we expect few side chains. Simply count + // all blocks the CL gives us for GC processing time + bc.gcproc += res.procTime + bc.logger.OnBlockEnd(nil) + return it.index, nil // Direct block insertion of a single block + } + switch res.status { + case CanonStatTy: + log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), + "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), + "elapsed", common.PrettyDuration(time.Since(start)), + "root", block.Root()) - // Report the import stats before returning the various results - stats.processed++ - stats.usedGas += usedGas + lastCanon = block - var snapDiffItems, snapBufItems common.StorageSize - if bc.snaps != nil { - snapDiffItems, snapBufItems = bc.snaps.Size() - } - trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() - stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, setHead) + // Only count canonical blocks for GC processing time + bc.gcproc += res.procTime - if !setHead { - // After merge we expect few side chains. Simply count - // all blocks the CL gives us for GC processing time - bc.gcproc += proctime + case SideStatTy: + log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) - return nil, true // Direct block insertion of a single block - } - switch status { - case CanonStatTy: - log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), - "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), - "elapsed", common.PrettyDuration(time.Since(start)), - "root", block.Root()) - - lastCanon = block - - // Only count canonical blocks for GC processing time - bc.gcproc += proctime - - case SideStatTy: - log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) - - default: - // This in theory is impossible, but lets be nice to our future selves and leave - // a log, instead of trying to track down blocks imports that don't emit logs. - log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) - } - return nil, false - }() - if err != nil || stop { - return it.index, err + default: + // This in theory is impossible, but lets be nice to our future selves and leave + // a log, instead of trying to track down blocks imports that don't emit logs. + log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(), + "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), + "root", block.Root()) } + bc.logger.OnBlockEnd(nil) } // Any blocks remaining here? The only ones we care about are the future ones @@ -1987,6 +1919,87 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return it.index, err } +// blockProcessingResult is a summary of block processing +// used for updating the stats. +type blockProcessingResult struct { + usedGas uint64 + procTime time.Duration + status WriteStatus +} + +// 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, followupInterrupt atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { + if bc.logger != nil { + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) + bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) + defer func() { + bc.logger.OnBlockEnd(blockEndErr) + }() + } + + // Process block using the parent state as reference point + pstart := time.Now() + receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) + if err != nil { + bc.reportBlock(block, receipts, err) + followupInterrupt.Store(true) + return err, true, nil + } + ptime := time.Since(pstart) + + vstart := time.Now() + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + bc.reportBlock(block, receipts, err) + followupInterrupt.Store(true) + return err, true, nil + } + vtime := time.Since(vstart) + proctime := time.Since(start) // processing + validation + + // Update the metrics touched during block processing and validation + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) + snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) + snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) + accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) + storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) + triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing + trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update + trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read + trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing + blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation + + // Write the block to the chain and get the status. + var ( + wstart = time.Now() + status WriteStatus + ) + if !setHead { + // Don't set the head, only insert the block + err = bc.writeBlockWithState(block, receipts, statedb) + } else { + status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) + } + followupInterrupt.Store(true) + if err != nil { + return err, true, &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status} + } + // Update the metrics touched during block commit + accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them + storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them + snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them + triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them + + blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) + blockInsertTimer.UpdateSince(start) + + return nil, false, &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status} +} + // insertSideChain is called when an import batch hits upon a pruned ancestor // error, which happens when a sidechain with a sufficiently old fork-block is // found. From 379b8d3423cd42b8d4fd2f66279bea63b3c5f92b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 16:21:40 +0330 Subject: [PATCH 051/100] fix atomic followupInterrupt --- core/blockchain.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 7ec99f308228..17df15f8cb39 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1849,7 +1849,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } // The traced section of block import. - err, stop, res := bc.processBlock(block, statedb, followupInterrupt, start, setHead) + err, stop, res := bc.processBlock(block, statedb, &followupInterrupt, start, setHead) if err != nil || stop { return it.index, err } @@ -1933,7 +1933,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, followupInterrupt atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { +func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, followupInterrupt *atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { if bc.logger != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) From 56600e911b540c0c6ad7015bac4e0fab3f70e2e1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 18:17:57 +0330 Subject: [PATCH 052/100] fix VMError.Unwrap --- core/vm/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/errors.go b/core/vm/errors.go index f6e4b6acd0eb..9f6605f030f5 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -111,7 +111,7 @@ func (e *VMError) Error() string { } func (e *VMError) Unwrap() error { - return errors.Unwrap(e.error) + return e.error } func (e *VMError) ErrorCode() int { From 8a1f67c7c87e7293832bb12f04ab293cf6aa9370 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 18:21:12 +0330 Subject: [PATCH 053/100] forgot prestate testcase --- .../prestate_tracer/create_create.json | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json new file mode 100644 index 000000000000..909a1eabe38e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json @@ -0,0 +1,62 @@ +{ + "genesis": { + "baseFeePerGas": "875000000", + "difficulty": "0", + "extraData": "0xd983010d05846765746888676f312e32312e318664617277696e", + "gasLimit": "11511229", + "hash": "0xd462585c6c5a3b3bf14850ebcde71b6615b9aaf6541403f9a0457212dd0502e0", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xfa51e868d6a7c0728f18800e4cc8d4cc1c87430cc9975e947eb6c9c03599b4e2", + "nonce": "0x0000000000000000", + "number": "1", + "stateRoot": "0xd2ebe0a7f3572ffe3e5b4c78147376d3fca767f236e4dd23f9151acfec7cb0d1", + "timestamp": "1699617692", + "totalDifficulty": "0", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x5208" + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "0x8ac7230489e80000" + } + }, + "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, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "isDev": true + } + }, + "context": { + "number": "2", + "difficulty": "0", + "timestamp": "1699617847", + "gasLimit": "11522469", + "miner": "0x0000000000000000000000000000000000000000" + }, + "input": "0x02f902b48205398084b2d05e0085011b1f3f8083031ca88080b90258608060405234801561001057600080fd5b5060405161001d906100e3565b604051809103906000f080158015610039573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691821781556040517fc66247bafd1305823857fb4c3e651e684d918df8554ef560bbbcb025fdd017039190a26000546040516360fe47b160e01b8152600560048201526001600160a01b03909116906360fe47b190602401600060405180830381600087803b1580156100c657600080fd5b505af11580156100da573d6000803e3d6000fd5b505050506100ef565b60ca8061018e83390190565b6091806100fd6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806380de699314602d575b600080fd5b600054603f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220dab781465e7f4cf20304cc388130a763508e20edd25b4bc8ea8f57743a0de8da64736f6c634300081700336080604052348015600f57600080fd5b5060ac8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146049575b600080fd5b60476042366004605e565b600055565b005b60005460405190815260200160405180910390f35b600060208284031215606f57600080fd5b503591905056fea264697066735822122049e09da6320793487d58eaa7b97f802618a062cbc35f08ca1ce92c17349141f864736f6c63430008170033c080a01d4fce93ad08bf413052645721f20e6136830cf5a2759fa57e76a134e90899a7a0399a72832d52118991dc04c4f9e1c0fec3d5e441ad7d4b055f0cf03130d8f815", + "result": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x5208" + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "0x8ac7230489e80000" + } + } +} \ No newline at end of file From 5bc3f626474e9f4294afd75b9cef6804a31acdad Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 18:29:27 +0330 Subject: [PATCH 054/100] move makeTest to own file --- eth/tracers/internal/tracetest/README.md | 10 ++++ eth/tracers/internal/tracetest/makeTest.js | 48 ++++++++++++++++++++ eth/tracers/internal/tracetest/util.go | 53 ---------------------- 3 files changed, 58 insertions(+), 53 deletions(-) create mode 100644 eth/tracers/internal/tracetest/README.md create mode 100644 eth/tracers/internal/tracetest/makeTest.js diff --git a/eth/tracers/internal/tracetest/README.md b/eth/tracers/internal/tracetest/README.md new file mode 100644 index 000000000000..8c3d5d275f2c --- /dev/null +++ b/eth/tracers/internal/tracetest/README.md @@ -0,0 +1,10 @@ +# Filling test cases + +To fill test cases for the built-in tracers, the `makeTest.js` script can be used. Given a transaction on a dev/test network, `makeTest.js` will fetch its prestate and then traces with the given configuration. +In the Geth console do: + +```terminal +let tx = '0x...' +loadScript('makeTest.js') +makeTest(tx, { tracer: 'callTracer' }) +``` \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js new file mode 100644 index 000000000000..306f10719009 --- /dev/null +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -0,0 +1,48 @@ +// makeTest generates a test for the configured tracer by running +// a prestate reassembled and a call trace run, assembling all the +// gathered information into a test case. +var makeTest = function(tx, traceConfig) { + // Generate the genesis block from the block, transaction and prestate data + var block = eth.getBlock(eth.getTransaction(tx).blockHash); + var genesis = eth.getBlock(block.parentHash); + + delete genesis.gasUsed; + delete genesis.logsBloom; + delete genesis.parentHash; + delete genesis.receiptsRoot; + delete genesis.sha3Uncles; + delete genesis.size; + delete genesis.transactions; + delete genesis.transactionsRoot; + delete genesis.uncles; + + genesis.gasLimit = genesis.gasLimit.toString(); + genesis.number = genesis.number.toString(); + genesis.timestamp = genesis.timestamp.toString(); + + genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer"}); + for (var key in genesis.alloc) { + var nonce = genesis.alloc[key].nonce; + if (nonce) { + genesis.alloc[key].nonce = nonce.toString(); + } + } + genesis.config = admin.nodeInfo.protocols.eth.config; + + // Generate the call trace and produce the test input + var result = debug.traceTransaction(tx, traceConfig); + delete result.time; + + console.log(JSON.stringify({ + genesis: genesis, + context: { + number: block.number.toString(), + difficulty: block.difficulty, + timestamp: block.timestamp.toString(), + gasLimit: block.gasLimit.toString(), + miner: block.miner, + }, + input: eth.getRawTransaction(tx), + result: result, + }, null, 2)); +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 95d292c9240b..1913f352ddb7 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -9,59 +9,6 @@ import ( _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) -// To generate a new callTracer test, copy paste the makeTest method below into -// a Geth console and call it with a transaction hash you which to export. - -/* -// makeTest generates a callTracer test by running a prestate reassembled and a -// call trace run, assembling all the gathered information into a test case. -var makeTest = function(tx, rewind) { - // Generate the genesis block from the block, transaction and prestate data - var block = eth.getBlock(eth.getTransaction(tx).blockHash); - var genesis = eth.getBlock(block.parentHash); - - delete genesis.gasUsed; - delete genesis.logsBloom; - delete genesis.parentHash; - delete genesis.receiptsRoot; - delete genesis.sha3Uncles; - delete genesis.size; - delete genesis.transactions; - delete genesis.transactionsRoot; - delete genesis.uncles; - - genesis.gasLimit = genesis.gasLimit.toString(); - genesis.number = genesis.number.toString(); - genesis.timestamp = genesis.timestamp.toString(); - - genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); - for (var key in genesis.alloc) { - var nonce = genesis.alloc[key].nonce; - if (nonce) { - genesis.alloc[key].nonce = nonce.toString(); - } - } - genesis.config = admin.nodeInfo.protocols.eth.config; - - // Generate the call trace and produce the test input - var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); - delete result.time; - - console.log(JSON.stringify({ - genesis: genesis, - context: { - number: block.number.toString(), - difficulty: block.difficulty, - timestamp: block.timestamp.toString(), - gasLimit: block.gasLimit.toString(), - miner: block.miner, - }, - input: eth.getRawTransaction(tx), - result: result, - }, null, 2)); -} -*/ - // camel converts a snake cased input string into a camel cased output. func camel(str string) string { pieces := strings.Split(str, "_") From cd8c4c589ff8bc8985286385175a2e84526edcd6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 18:39:09 +0330 Subject: [PATCH 055/100] force load live tracer set --- cmd/geth/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index be203be7bbc0..c5fa1d7657f0 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -43,6 +43,7 @@ import ( // Force-load the tracer engines to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/live" _ "github.com/ethereum/go-ethereum/eth/tracers/native" "github.com/urfave/cli/v2" From 8610f8f68cc5ec8f3ee10b0b11d7478b5e703b78 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 24 Nov 2023 19:08:42 +0330 Subject: [PATCH 056/100] add hooks for beacon block root processing --- core/blockchain.go | 2 ++ core/chain_makers.go | 2 +- core/state_processor.go | 10 ++++++++-- eth/tracers/live/printer.go | 3 +++ miner/worker.go | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 17df15f8cb39..d66ca0de0a35 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -195,6 +195,8 @@ type BlockchainLogger interface { 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) + OnBeaconBlockRootEnd() } // BlockChain represents the canonical chain given a database with a genesis diff --git a/core/chain_makers.go b/core/chain_makers.go index 8f7728d66bb3..f0d21e9c45dd 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) + ProcessBeaconBlockRoot(root, vmenv, b.statedb, nil) } // addTx adds a transaction to the generated block. If no coinbase has diff --git a/core/state_processor.go b/core/state_processor.go index d2740a1bdc03..b468dce3afdb 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -79,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) + ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb, p.bc.logger) } statedb.PrepareBlock(vm.ActivePrecompiles(rules)) // Iterate over and process the individual transactions @@ -185,7 +185,13 @@ 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) { +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/printer.go b/eth/tracers/live/printer.go index 27657ae56e9a..62129d29399a 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -58,6 +58,9 @@ func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) { 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 { diff --git a/miner/worker.go b/miner/worker.go index 95190d5c5d69..a5ea9571a9c8 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) + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state, nil) } return env, nil } From 00ee953593a5b327061ddc2d568b9b1969a2a914 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 28 Nov 2023 14:40:20 +0330 Subject: [PATCH 057/100] rm comment --- core/state/statedb.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index b6f0b17320da..8740d7df6fa9 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -60,7 +60,6 @@ type StateLogger interface { OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) OnLog(log *types.Log) // OnNewAccount is called when a new account is created. - // Note: it will be even invoked when precompiled contracts are populated. OnNewAccount(addr common.Address) } From 72410c399d6529e338743a7ed3ff9f9d05f9daaf Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Thu, 30 Nov 2023 10:35:38 -0500 Subject: [PATCH 058/100] Fixed `BlockchainLogger.OnBlockEnd` called too much times (#19) The `processBlock` is already doing the work to call `OnBlockEnd`, no need to call it anymore afterwards. --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/blockchain.go | 6 ------ core/vm/contracts_fuzz_test.go | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 532e36fd1e1a..1ba3c26a8cba 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -187,7 +187,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) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb, nil) } var blobGasUsed uint64 diff --git a/core/blockchain.go b/core/blockchain.go index d66ca0de0a35..c496f677a93f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1870,9 +1870,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time bc.gcproc += res.procTime - if bc.logger != nil { - bc.logger.OnBlockEnd(nil) - } return it.index, nil // Direct block insertion of a single block } switch res.status { @@ -1901,9 +1898,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), "root", block.Root()) } - if bc.logger != nil { - bc.logger.OnBlockEnd(nil) - } } // Any blocks remaining here? The only ones we care about are the future ones diff --git a/core/vm/contracts_fuzz_test.go b/core/vm/contracts_fuzz_test.go index 87c1fff7cc81..1e5cc8007471 100644 --- a/core/vm/contracts_fuzz_test.go +++ b/core/vm/contracts_fuzz_test.go @@ -36,7 +36,7 @@ func FuzzPrecompiledContracts(f *testing.F) { return } inWant := string(input) - RunPrecompiledContract(p, input, gas) + RunPrecompiledContract(p, input, gas, nil) if inHave := string(input); inWant != inHave { t.Errorf("Precompiled %v modified input data", a) } From 5190cfc5cb24493311fb5724361dd3c519fa66f8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 5 Dec 2023 14:16:25 +0330 Subject: [PATCH 059/100] rm extra galloc capturing --- core/genesis.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 81efbd314b73..ed2f1eb503d7 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -158,12 +158,13 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { // specification will be flushed as well. func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash, bcLogger BlockchainLogger) error { statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) - statedb.SetLogger(bcLogger) if err != nil { return err } for addr, account := range *ga { if account.Balance != nil { + // This is not actually logged via tracer because OnGenesisBlock + // already captures the allocations. statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) } statedb.SetCode(addr, account.Code) From 9e5c96fdff55b8f43df7ef80e35b9acd3d14ba3e Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 5 Dec 2023 16:31:16 +0330 Subject: [PATCH 060/100] add chainConfig to block events --- core/blockchain.go | 10 +++++----- core/genesis.go | 2 +- eth/tracers/live/printer.go | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index c496f677a93f..5bc5bbd68ddf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -192,9 +192,9 @@ type BlockchainLogger interface { state.StateLogger // 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) + OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) OnBlockEnd(err error) - OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) + OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc, chainConfig *params.ChainConfig) OnBeaconBlockRootStart(root common.Hash) OnBeaconBlockRootEnd() } @@ -461,7 +461,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") } - bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) + bc.logger.OnGenesisBlock(bc.genesisBlock, alloc, bc.chainConfig) } } @@ -1804,7 +1804,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.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), bc.chainConfig) bc.logger.OnBlockEnd(nil) } @@ -1932,7 +1932,7 @@ type blockProcessingResult struct { func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, followupInterrupt *atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { if bc.logger != nil { td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) - bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) + bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), bc.chainConfig) defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/core/genesis.go b/core/genesis.go index ed2f1eb503d7..cd62eebd958e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -540,7 +540,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc return nil, errors.New("can't start clique chain without signers") } if bcLogger != nil { - bcLogger.OnGenesisBlock(block, g.Alloc) + bcLogger.OnGenesisBlock(block, g.Alloc, config) } // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 62129d29399a..58022b390366 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -12,6 +12,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/params" ) func init() { @@ -84,7 +85,7 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) { fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) } -func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { +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 { @@ -96,7 +97,7 @@ func (p *Printer) OnBlockEnd(err error) { fmt.Printf("OnBlockEnd: err=%v\n", err) } -func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc, _ *params.ChainConfig) { fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc)) } From f862531c250fed8e2912a9a1d7ccdc075377cf83 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 5 Dec 2023 16:49:03 +0330 Subject: [PATCH 061/100] rm chainConfig from OnGenesisBlock --- core/blockchain.go | 4 ++-- core/genesis.go | 2 +- eth/tracers/live/printer.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 5bc5bbd68ddf..e7ba251c8f1a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -194,7 +194,7 @@ type BlockchainLogger interface { // `td` is the total difficulty prior to `block`. OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) OnBlockEnd(err error) - OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc, chainConfig *params.ChainConfig) + OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) OnBeaconBlockRootStart(root common.Hash) OnBeaconBlockRootEnd() } @@ -461,7 +461,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") } - bc.logger.OnGenesisBlock(bc.genesisBlock, alloc, bc.chainConfig) + bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) } } diff --git a/core/genesis.go b/core/genesis.go index cd62eebd958e..ed2f1eb503d7 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -540,7 +540,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc return nil, errors.New("can't start clique chain without signers") } if bcLogger != nil { - bcLogger.OnGenesisBlock(block, g.Alloc, config) + bcLogger.OnGenesisBlock(block, g.Alloc) } // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 58022b390366..422b009e291c 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -97,7 +97,7 @@ func (p *Printer) OnBlockEnd(err error) { fmt.Printf("OnBlockEnd: err=%v\n", err) } -func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc, _ *params.ChainConfig) { +func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc)) } From 9360cab0df77575584f5d0e589df26e53a84de66 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 7 Dec 2023 11:18:38 +0330 Subject: [PATCH 062/100] assign values for balance reasons --- core/state/metadata.go | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/core/state/metadata.go b/core/state/metadata.go index 9e78e6816f5a..db17b92a9ed0 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -21,19 +21,23 @@ package state type BalanceChangeReason byte const ( - BalanceChangeUnspecified BalanceChangeReason = iota - BalanceChangeRewardMineUncle - BalanceChangeRewardMineBlock - BalanceChangeDaoRefundContract - BalanceChangeDaoAdjustBalance - BalanceChangeTransfer - BalanceChangeGenesisBalance - BalanceChangeGasBuy - BalanceChangeRewardTransactionFee - BalanceChangeGasRefund - BalanceChangeTouchAccount - BalanceChangeSuicideRefund - BalanceChangeSuicideWithdraw - BalanceChangeBurn - BalanceChangeWithdrawal + BalanceChangeUnspecified BalanceChangeReason = 0 + BalanceChangeRewardMineUncle = 1 + BalanceChangeRewardMineBlock = 2 + BalanceChangeDaoRefundContract = 3 + BalanceChangeDaoAdjustBalance = 4 + BalanceChangeTransfer = 5 + BalanceChangeGenesisBalance = 6 + BalanceChangeGasBuy = 7 + BalanceChangeRewardTransactionFee = 8 + BalanceChangeGasRefund = 9 + BalanceChangeTouchAccount = 10 + // TODO: rename (debit, credit) + BalanceChangeSuicideRefund = 11 + BalanceChangeSuicideWithdraw = 12 + // TODO: add method on statedb to track burn without Add/Sub balance + // Or: Track via OnBurn + // 1559 burn, blob burn, withdraw to self via selfdestruct burn, receive ether after selfdestruct (at end of tx) + BalanceChangeBurn = 13 + BalanceChangeWithdrawal = 14 ) From 0967291487146bdf256a4f829ae84bbd9a9fd2ca Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 7 Dec 2023 12:00:54 +0330 Subject: [PATCH 063/100] Track burnt and selfdestruct withdraw bal changes --- core/state/metadata.go | 20 ++++++--- core/state/statedb.go | 13 +++++- core/state_transition.go | 96 ++++++++++++++++++++++++++++++---------- 3 files changed, 98 insertions(+), 31 deletions(-) diff --git a/core/state/metadata.go b/core/state/metadata.go index db17b92a9ed0..90ea3d17423f 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -33,11 +33,19 @@ const ( BalanceChangeGasRefund = 9 BalanceChangeTouchAccount = 10 // TODO: rename (debit, credit) - BalanceChangeSuicideRefund = 11 + // BalanceChangeSuicideRefund is added to the recipient as indicated by a selfdestructing account. + BalanceChangeSuicideRefund = 11 + // BalanceChangeSuicideWithdraw is deducted from a contract due to self-destruct. + // This can happen either at the point of self-destruction, or at the end of the tx + // if ether was sent to contract post-selfdestruct. BalanceChangeSuicideWithdraw = 12 - // TODO: add method on statedb to track burn without Add/Sub balance - // Or: Track via OnBurn - // 1559 burn, blob burn, withdraw to self via selfdestruct burn, receive ether after selfdestruct (at end of tx) - BalanceChangeBurn = 13 - BalanceChangeWithdrawal = 14 + // BalanceChangeBurn accounts for: + // - EIP-1559 burnt fees + // - ether that is sent to a self-destructed contract within the same tx (captured at end of tx) + // Note it doesn't account for a self-destruct which appoints same contract as recipient. + BalanceChangeBurn = 13 + // BalanceChangeBurnRefund is refunded to an account at the end of transaction based on + // gas usage from the estimated burn amount. + BalanceChangeBurnRefund = 14 + BalanceChangeWithdrawal = 15 ) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0182fbb1dd78..f951aa490b9d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -476,13 +476,18 @@ func (s *StateDB) SelfDestruct(addr common.Address) { if stateObject == nil { return } + var ( + prev = new(big.Int).Set(stateObject.Balance()) + n = new(big.Int) + ) s.journal.append(selfDestructChange{ account: &addr, prev: stateObject.selfDestructed, - prevbalance: new(big.Int).Set(stateObject.Balance()), + prevbalance: prev, }) + s.logger.OnBalanceChange(addr, prev, n, BalanceChangeSuicideWithdraw) stateObject.markSelfdestructed() - stateObject.data.Balance = new(big.Int) + stateObject.data.Balance = n } func (s *StateDB) Selfdestruct6780(addr common.Address) { @@ -870,6 +875,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { obj.deleted = true + // If ether was sent to account post-selfdestruct it is burnt. + if bal := obj.Balance(); bal.Sign() != 0 { + s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceChangeBurn) + } // We need to maintain account deletions explicitly (will remain // set indefinitely). Note only the first occurred self-destruct // event is tracked. diff --git a/core/state_transition.go b/core/state_transition.go index a50447f3de8d..f4a68ec38f00 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -233,44 +233,84 @@ func (st *StateTransition) to() common.Address { } func (st *StateTransition) buyGas() error { - mgval := new(big.Int).SetUint64(st.msg.GasLimit) - mgval = mgval.Mul(mgval, st.msg.GasPrice) - balanceCheck := new(big.Int).Set(mgval) if st.msg.GasFeeCap != nil { - balanceCheck.SetUint64(st.msg.GasLimit) - balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) - balanceCheck.Add(balanceCheck, st.msg.Value) + if err := st.buy1559Gas(); err != nil { + return err + } + } else { + if err := st.buyLegacyGas(); err != nil { + return err + } } if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { - if blobGas := st.blobGasUsed(); blobGas > 0 { - // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap - blobBalanceCheck := new(big.Int).SetUint64(blobGas) - blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap) - balanceCheck.Add(balanceCheck, blobBalanceCheck) - // Pay for blobGasUsed * actual blob fee - blobFee := new(big.Int).SetUint64(blobGas) - blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee) - mgval.Add(mgval, blobFee) + if err := st.buyBlobGas(); err != nil { + return err } } - if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) - } + if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } - if st.evm.Config.Tracer != nil { st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance) } - st.gasRemaining += st.msg.GasLimit - st.initialGas = st.msg.GasLimit + + return nil +} + +func (st *StateTransition) buyLegacyGas() error { + mgval := new(big.Int).SetUint64(st.msg.GasLimit) + mgval = mgval.Mul(mgval, st.msg.GasPrice) + balanceCheck := new(big.Int).Set(mgval) + if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) + } st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) return nil } +// buy1559Gas purchases gas according to EIP-1559 rules. See: +// https://eips.ethereum.org/EIPS/eip-1559 +func (st *StateTransition) buy1559Gas() error { + balanceCheck := new(big.Int).SetUint64(st.msg.GasLimit) + balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) + balanceCheck.Add(balanceCheck, st.msg.Value) + if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) + } + + burnt := new(big.Int).SetUint64(st.msg.GasLimit) + burnt = burnt.Mul(burnt, st.evm.Context.BaseFee) + st.state.SubBalance(st.msg.From, burnt, state.BalanceChangeBurn) + + effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) + tipVal := new(big.Int).SetUint64(st.msg.GasLimit) + tipVal = tipVal.Mul(tipVal, effectiveTip) + st.state.SubBalance(st.msg.From, tipVal, state.BalanceChangeGasBuy) + + return nil +} + +// buyBlobGas purchases blob gas as per: +// https://eips.ethereum.org/EIPS/eip-4844 +func (st *StateTransition) buyBlobGas() error { + if blobGas := st.blobGasUsed(); blobGas > 0 { + // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap + balanceCheck := new(big.Int).SetUint64(blobGas) + balanceCheck.Mul(balanceCheck, st.msg.BlobGasFeeCap) + if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) + } + // Pay for blobGasUsed * actual blob fee + blobFee := new(big.Int).SetUint64(blobGas) + blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee) + st.state.SubBalance(st.msg.From, blobFee, state.BalanceChangeBurn) + } + return nil +} + func (st *StateTransition) preCheck() error { // Only check transactions that are not fake msg := st.msg @@ -467,8 +507,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { 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.BalanceChangeGasRefund) + gasRemaining := new(big.Int).SetUint64(st.gasRemaining) + if st.msg.GasFeeCap.Sign() == 0 { + remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice) + st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) + } else { + // Split into burnt gas and tip gas to refund. + burnt := new(big.Int).Mul(gasRemaining, st.evm.Context.BaseFee) + st.state.AddBalance(st.msg.From, burnt, state.BalanceChangeBurnRefund) + effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) + tip := new(big.Int).Mul(gasRemaining, effectiveTip) + st.state.AddBalance(st.msg.From, tip, state.BalanceChangeGasRefund) + } if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) From ddd1b0a63f398a4a5c7733b9468e517d3ea951e6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 11 Dec 2023 12:55:24 +0330 Subject: [PATCH 064/100] fix gas purchase --- core/state_transition.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index f4a68ec38f00..5f88df3273b4 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -140,6 +140,8 @@ type Message struct { AccessList types.AccessList BlobGasFeeCap *big.Int BlobHashes []common.Hash + // Distinguishes type-2 txes + DynamicFee bool // When SkipAccountChecks is true, the message nonce is not checked against the // account nonce in state. It also disables checking that the sender is an EOA. @@ -162,6 +164,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In SkipAccountChecks: false, BlobHashes: tx.BlobHashes(), BlobGasFeeCap: tx.BlobGasFeeCap(), + DynamicFee: tx.Type() == 2 || tx.Type() == 3, } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { @@ -233,7 +236,7 @@ func (st *StateTransition) to() common.Address { } func (st *StateTransition) buyGas() error { - if st.msg.GasFeeCap != nil { + if st.msg.DynamicFee { if err := st.buy1559Gas(); err != nil { return err } @@ -247,6 +250,10 @@ func (st *StateTransition) buyGas() error { return err } } + valueCheck := new(big.Int).Set(st.msg.Value) + if have, want := st.state.GetBalance(st.msg.From), valueCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) + } if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err @@ -508,16 +515,16 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Return ETH for remaining gas, exchanged at the original rate. gasRemaining := new(big.Int).SetUint64(st.gasRemaining) - if st.msg.GasFeeCap.Sign() == 0 { - remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice) - st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) - } else { + if st.msg.DynamicFee { // Split into burnt gas and tip gas to refund. burnt := new(big.Int).Mul(gasRemaining, st.evm.Context.BaseFee) st.state.AddBalance(st.msg.From, burnt, state.BalanceChangeBurnRefund) effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) tip := new(big.Int).Mul(gasRemaining, effectiveTip) st.state.AddBalance(st.msg.From, tip, state.BalanceChangeGasRefund) + } else { + remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice) + st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) } if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { From 0484068df5758bae60818567ce1908f4fba800ea Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 11 Dec 2023 14:17:29 +0330 Subject: [PATCH 065/100] fix lint issues --- core/state/metadata.go | 30 +++++++++++++++--------------- eth/tracers/live/printer.go | 1 - eth/tracers/native/prestate.go | 1 - 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/core/state/metadata.go b/core/state/metadata.go index 90ea3d17423f..6a2f20a0f9b1 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -22,30 +22,30 @@ type BalanceChangeReason byte const ( BalanceChangeUnspecified BalanceChangeReason = 0 - BalanceChangeRewardMineUncle = 1 - BalanceChangeRewardMineBlock = 2 - BalanceChangeDaoRefundContract = 3 - BalanceChangeDaoAdjustBalance = 4 - BalanceChangeTransfer = 5 - BalanceChangeGenesisBalance = 6 - BalanceChangeGasBuy = 7 - BalanceChangeRewardTransactionFee = 8 - BalanceChangeGasRefund = 9 - BalanceChangeTouchAccount = 10 + BalanceChangeRewardMineUncle BalanceChangeReason = 1 + BalanceChangeRewardMineBlock BalanceChangeReason = 2 + BalanceChangeDaoRefundContract BalanceChangeReason = 3 + BalanceChangeDaoAdjustBalance BalanceChangeReason = 4 + BalanceChangeTransfer BalanceChangeReason = 5 + BalanceChangeGenesisBalance BalanceChangeReason = 6 + BalanceChangeGasBuy BalanceChangeReason = 7 + BalanceChangeRewardTransactionFee BalanceChangeReason = 8 + BalanceChangeGasRefund BalanceChangeReason = 9 + BalanceChangeTouchAccount BalanceChangeReason = 10 // TODO: rename (debit, credit) // BalanceChangeSuicideRefund is added to the recipient as indicated by a selfdestructing account. - BalanceChangeSuicideRefund = 11 + BalanceChangeSuicideRefund BalanceChangeReason = 11 // BalanceChangeSuicideWithdraw is deducted from a contract due to self-destruct. // This can happen either at the point of self-destruction, or at the end of the tx // if ether was sent to contract post-selfdestruct. - BalanceChangeSuicideWithdraw = 12 + BalanceChangeSuicideWithdraw BalanceChangeReason = 12 // BalanceChangeBurn accounts for: // - EIP-1559 burnt fees // - ether that is sent to a self-destructed contract within the same tx (captured at end of tx) // Note it doesn't account for a self-destruct which appoints same contract as recipient. - BalanceChangeBurn = 13 + BalanceChangeBurn BalanceChangeReason = 13 // BalanceChangeBurnRefund is refunded to an account at the end of transaction based on // gas usage from the estimated burn amount. - BalanceChangeBurnRefund = 14 - BalanceChangeWithdrawal = 15 + BalanceChangeBurnRefund BalanceChangeReason = 14 + BalanceChangeWithdrawal BalanceChangeReason = 15 ) diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 422b009e291c..727dc3dc1610 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -69,7 +69,6 @@ func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common return } fmt.Printf("CaptureTxStart: tx=%s\n", buf) - } func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b59834ff5d08..8608ab69dcac 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -61,7 +61,6 @@ type prestateTracer struct { env *vm.EVM pre stateMap post stateMap - create bool to common.Address config prestateTracerConfig interrupt atomic.Bool // Atomic flag to signal execution interruption From 5e82cbec8d2746d5a65b674762e2b4adfa3cd339 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 11 Dec 2023 15:59:23 +0330 Subject: [PATCH 066/100] nil check --- core/state/statedb.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index f951aa490b9d..7800be8a09df 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -485,7 +485,9 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prev: stateObject.selfDestructed, prevbalance: prev, }) - s.logger.OnBalanceChange(addr, prev, n, BalanceChangeSuicideWithdraw) + if s.logger != nil { + s.logger.OnBalanceChange(addr, prev, n, BalanceChangeSuicideWithdraw) + } stateObject.markSelfdestructed() stateObject.data.Balance = n } @@ -876,7 +878,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 { + if bal := obj.Balance(); bal.Sign() != 0 && s.logger != nil { s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceChangeBurn) } // We need to maintain account deletions explicitly (will remain From 0d254e4983613113a83ca255e8a25bbbd06fc271 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 11 Dec 2023 16:17:49 +0330 Subject: [PATCH 067/100] fix test --- eth/tracers/internal/tracetest/prestate_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 9a9189e3994d..24dfa17f91cd 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -118,7 +118,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } statedb.SetLogger(tracer) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) + msg, err := core.TransactionToMessage(tx, signer, test.Genesis.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } From a52c80dec53822ddefe668a111892e27b2e35082 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 12 Dec 2023 11:34:41 +0330 Subject: [PATCH 068/100] Fix test case --- .../testdata/prestate_tracer_with_diff_mode/create_failed.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e80dad5667ef..561ead05b6f8 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": { From 89d79d6d3c7ce2c1689ada6f68a670ecdc48a0d3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 12 Dec 2023 11:48:25 +0330 Subject: [PATCH 069/100] fix t8n tracer nil check --- cmd/evm/internal/t8ntool/execution.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 1ba3c26a8cba..ef118ffbcb5c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -234,7 +234,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) - tracer.CaptureTxStart(evm, tx, msg.From) + if tracer != nil { + tracer.CaptureTxStart(evm, tx, msg.From) + } // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { @@ -242,7 +244,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) - tracer.CaptureTxEnd(nil, err) + if tracer != nil { + tracer.CaptureTxEnd(nil, err) + } continue } includedTxs = append(includedTxs, tx) @@ -284,7 +288,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) - tracer.CaptureTxEnd(receipt, nil) + if tracer != nil { + tracer.CaptureTxEnd(receipt, nil) + } } txIndex++ From 54f4bc741d845f23976b0c33311cc01ce081155c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Dec 2023 13:50:04 +0330 Subject: [PATCH 070/100] fix balance check --- core/state_transition.go | 64 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 5f88df3273b4..95a65f1f671a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -236,24 +236,22 @@ func (st *StateTransition) to() common.Address { } func (st *StateTransition) buyGas() error { - if st.msg.DynamicFee { - if err := st.buy1559Gas(); err != nil { - return err - } + if err := st.balanceCheck(); err != nil { + return err + } + if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { + st.buyDynamicFee() } else { - if err := st.buyLegacyGas(); err != nil { - return err - } + fee := new(big.Int).SetUint64(st.msg.GasLimit) + fee = fee.Mul(fee, st.msg.GasPrice) + // TODO: rename change reason to indicate tip. + st.state.SubBalance(st.msg.From, fee, state.BalanceChangeGasBuy) } if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { if err := st.buyBlobGas(); err != nil { return err } } - valueCheck := new(big.Int).Set(st.msg.Value) - if have, want := st.state.GetBalance(st.msg.From), valueCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) - } if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err @@ -267,50 +265,44 @@ func (st *StateTransition) buyGas() error { return nil } -func (st *StateTransition) buyLegacyGas() error { - mgval := new(big.Int).SetUint64(st.msg.GasLimit) - mgval = mgval.Mul(mgval, st.msg.GasPrice) - balanceCheck := new(big.Int).Set(mgval) +// balanceCheck checks the account can pay all they claimed +// they can pay. +func (st *StateTransition) balanceCheck() error { + balanceCheck := new(big.Int).SetUint64(st.msg.GasLimit) + // GasFeeCap defaults to gas price for legacy txes. + balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) + balanceCheck = balanceCheck.Add(balanceCheck, st.msg.Value) + if st.msg.BlobGasFeeCap != nil { + blobFee := new(big.Int).SetUint64(st.blobGasUsed()) + blobFee = blobFee.Mul(blobFee, st.msg.BlobGasFeeCap) + balanceCheck = balanceCheck.Add(balanceCheck, blobFee) + } if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) } - st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) return nil } -// buy1559Gas purchases gas according to EIP-1559 rules. See: +// buyDynamicFee purchases gas according to EIP-1559 rules. See: // https://eips.ethereum.org/EIPS/eip-1559 -func (st *StateTransition) buy1559Gas() error { - balanceCheck := new(big.Int).SetUint64(st.msg.GasLimit) - balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) - balanceCheck.Add(balanceCheck, st.msg.Value) - if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) - } - +func (st *StateTransition) buyDynamicFee() { burnt := new(big.Int).SetUint64(st.msg.GasLimit) burnt = burnt.Mul(burnt, st.evm.Context.BaseFee) + // TODO: rename and create new change reason type so it's possible to calculate total fee paid. st.state.SubBalance(st.msg.From, burnt, state.BalanceChangeBurn) effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) tipVal := new(big.Int).SetUint64(st.msg.GasLimit) tipVal = tipVal.Mul(tipVal, effectiveTip) + // TODO: rename to indicate tip. st.state.SubBalance(st.msg.From, tipVal, state.BalanceChangeGasBuy) - - return nil } // buyBlobGas purchases blob gas as per: // https://eips.ethereum.org/EIPS/eip-4844 func (st *StateTransition) buyBlobGas() error { if blobGas := st.blobGasUsed(); blobGas > 0 { - // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap - balanceCheck := new(big.Int).SetUint64(blobGas) - balanceCheck.Mul(balanceCheck, st.msg.BlobGasFeeCap) - if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) - } - // Pay for blobGasUsed * actual blob fee + // Pay for blobGasUsed * effective blob fee blobFee := new(big.Int).SetUint64(blobGas) blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee) st.state.SubBalance(st.msg.From, blobFee, state.BalanceChangeBurn) @@ -515,15 +507,17 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Return ETH for remaining gas, exchanged at the original rate. gasRemaining := new(big.Int).SetUint64(st.gasRemaining) - if st.msg.DynamicFee { + if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { // Split into burnt gas and tip gas to refund. burnt := new(big.Int).Mul(gasRemaining, st.evm.Context.BaseFee) + // TODO: rename to unburnt st.state.AddBalance(st.msg.From, burnt, state.BalanceChangeBurnRefund) effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) tip := new(big.Int).Mul(gasRemaining, effectiveTip) st.state.AddBalance(st.msg.From, tip, state.BalanceChangeGasRefund) } else { remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice) + // TODO: rename to unusedTip st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) } From 64e35e93dd8a4e4bb585f46df7a8cad37e01a9c3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Dec 2023 16:44:56 +0330 Subject: [PATCH 071/100] revert buyGas refactor --- core/state_transition.go | 82 +++++++++++----------------------------- 1 file changed, 23 insertions(+), 59 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 95a65f1f671a..311bd7fda111 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -236,77 +236,41 @@ func (st *StateTransition) to() common.Address { } func (st *StateTransition) buyGas() error { - if err := st.balanceCheck(); err != nil { - return err - } - if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { - st.buyDynamicFee() - } else { - fee := new(big.Int).SetUint64(st.msg.GasLimit) - fee = fee.Mul(fee, st.msg.GasPrice) - // TODO: rename change reason to indicate tip. - st.state.SubBalance(st.msg.From, fee, state.BalanceChangeGasBuy) + mgval := new(big.Int).SetUint64(st.msg.GasLimit) + mgval = mgval.Mul(mgval, st.msg.GasPrice) + balanceCheck := new(big.Int).Set(mgval) + if st.msg.GasFeeCap != nil { + balanceCheck.SetUint64(st.msg.GasLimit) + balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) + balanceCheck.Add(balanceCheck, st.msg.Value) } if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { - if err := st.buyBlobGas(); err != nil { - return err + if blobGas := st.blobGasUsed(); blobGas > 0 { + // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap + blobBalanceCheck := new(big.Int).SetUint64(blobGas) + blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap) + balanceCheck.Add(balanceCheck, blobBalanceCheck) + // Pay for blobGasUsed * actual blob fee + blobFee := new(big.Int).SetUint64(blobGas) + blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee) + mgval.Add(mgval, blobFee) } } - + if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) + } if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } + if st.evm.Config.Tracer != nil { st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance) } - st.gasRemaining += st.msg.GasLimit - st.initialGas = st.msg.GasLimit - return nil -} - -// balanceCheck checks the account can pay all they claimed -// they can pay. -func (st *StateTransition) balanceCheck() error { - balanceCheck := new(big.Int).SetUint64(st.msg.GasLimit) - // GasFeeCap defaults to gas price for legacy txes. - balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) - balanceCheck = balanceCheck.Add(balanceCheck, st.msg.Value) - if st.msg.BlobGasFeeCap != nil { - blobFee := new(big.Int).SetUint64(st.blobGasUsed()) - blobFee = blobFee.Mul(blobFee, st.msg.BlobGasFeeCap) - balanceCheck = balanceCheck.Add(balanceCheck, blobFee) - } - if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) - } - return nil -} - -// buyDynamicFee purchases gas according to EIP-1559 rules. See: -// https://eips.ethereum.org/EIPS/eip-1559 -func (st *StateTransition) buyDynamicFee() { - burnt := new(big.Int).SetUint64(st.msg.GasLimit) - burnt = burnt.Mul(burnt, st.evm.Context.BaseFee) - // TODO: rename and create new change reason type so it's possible to calculate total fee paid. - st.state.SubBalance(st.msg.From, burnt, state.BalanceChangeBurn) - - effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) - tipVal := new(big.Int).SetUint64(st.msg.GasLimit) - tipVal = tipVal.Mul(tipVal, effectiveTip) - // TODO: rename to indicate tip. - st.state.SubBalance(st.msg.From, tipVal, state.BalanceChangeGasBuy) -} + st.gasRemaining += st.msg.GasLimit -// buyBlobGas purchases blob gas as per: -// https://eips.ethereum.org/EIPS/eip-4844 -func (st *StateTransition) buyBlobGas() error { - if blobGas := st.blobGasUsed(); blobGas > 0 { - // Pay for blobGasUsed * effective blob fee - blobFee := new(big.Int).SetUint64(blobGas) - blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee) - st.state.SubBalance(st.msg.From, blobFee, state.BalanceChangeBurn) - } + st.initialGas = st.msg.GasLimit + st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) return nil } From 8b3180d8a72f9c04d24df0bcfd338fade12dfb22 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Dec 2023 17:51:19 +0330 Subject: [PATCH 072/100] revert gas refund --- core/state_transition.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 311bd7fda111..165fbd853e77 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -470,20 +470,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. - gasRemaining := new(big.Int).SetUint64(st.gasRemaining) - if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { - // Split into burnt gas and tip gas to refund. - burnt := new(big.Int).Mul(gasRemaining, st.evm.Context.BaseFee) - // TODO: rename to unburnt - st.state.AddBalance(st.msg.From, burnt, state.BalanceChangeBurnRefund) - effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee)) - tip := new(big.Int).Mul(gasRemaining, effectiveTip) - st.state.AddBalance(st.msg.From, tip, state.BalanceChangeGasRefund) - } else { - remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice) - // TODO: rename to unusedTip - st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) - } + remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) + st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) From 2d14bb573c90a427b3454e446464655cc3f8092f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 13 Dec 2023 17:52:56 +0330 Subject: [PATCH 073/100] rename and document balance change reasons --- cmd/evm/internal/t8ntool/execution.go | 6 +-- consensus/ethash/consensus.go | 4 +- consensus/misc/dao.go | 4 +- core/genesis.go | 4 +- core/state/metadata.go | 67 +++++++++++++++++---------- core/state/statedb.go | 4 +- core/state_transition.go | 6 +-- core/vm/instructions.go | 6 +-- 8 files changed, 59 insertions(+), 42 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index ef118ffbcb5c..df46e298d831 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -316,9 +316,9 @@ 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.BalanceChangeRewardMineUncle) + statedb.AddBalance(ommer.Address, reward, state.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceChangeRewardMineBlock) + statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceIncreaseRewardMineBlock) } // Apply withdrawals for _, w := range pre.Env.Withdrawals { @@ -367,7 +367,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.BalanceChangeGenesisBalance) + statedb.SetBalance(addr, a.Balance, state.BalanceIncreaseGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 4b919ee59141..17346384e1c0 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -586,10 +586,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.BalanceChangeRewardMineUncle) + stateDB.AddBalance(uncle.Coinbase, r, state.BalanceIncreaseRewardMineUncle) r.Div(blockReward, big32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward, state.BalanceChangeRewardMineBlock) + stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index 7f0895eb26bb..bc393a9cbced 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -80,7 +80,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.BalanceChangeDaoRefundContract) - statedb.SetBalance(addr, new(big.Int), state.BalanceChangeDaoAdjustBalance) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceIncreaseDaoContract) + statedb.SetBalance(addr, new(big.Int), state.BalanceDecreaseDaoAccount) } } diff --git a/core/genesis.go b/core/genesis.go index ed2f1eb503d7..59f06007b2e1 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -142,7 +142,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) + statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -165,7 +165,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, state.BalanceChangeGenesisBalance) + statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) diff --git a/core/state/metadata.go b/core/state/metadata.go index 6a2f20a0f9b1..6e7a717794b7 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -21,31 +21,48 @@ package state type BalanceChangeReason byte const ( - BalanceChangeUnspecified BalanceChangeReason = 0 - BalanceChangeRewardMineUncle BalanceChangeReason = 1 - BalanceChangeRewardMineBlock BalanceChangeReason = 2 - BalanceChangeDaoRefundContract BalanceChangeReason = 3 - BalanceChangeDaoAdjustBalance BalanceChangeReason = 4 - BalanceChangeTransfer BalanceChangeReason = 5 - BalanceChangeGenesisBalance BalanceChangeReason = 6 - BalanceChangeGasBuy BalanceChangeReason = 7 - BalanceChangeRewardTransactionFee BalanceChangeReason = 8 - BalanceChangeGasRefund BalanceChangeReason = 9 - BalanceChangeTouchAccount BalanceChangeReason = 10 - // TODO: rename (debit, credit) - // BalanceChangeSuicideRefund is added to the recipient as indicated by a selfdestructing account. - BalanceChangeSuicideRefund BalanceChangeReason = 11 - // BalanceChangeSuicideWithdraw is deducted from a contract due to self-destruct. + 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. + BalanceChangeWithdrawal 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 transfered 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. // This can happen either at the point of self-destruction, or at the end of the tx // if ether was sent to contract post-selfdestruct. - BalanceChangeSuicideWithdraw BalanceChangeReason = 12 - // BalanceChangeBurn accounts for: - // - EIP-1559 burnt fees - // - ether that is sent to a self-destructed contract within the same tx (captured at end of tx) - // Note it doesn't account for a self-destruct which appoints same contract as recipient. - BalanceChangeBurn BalanceChangeReason = 13 - // BalanceChangeBurnRefund is refunded to an account at the end of transaction based on - // gas usage from the estimated burn amount. - BalanceChangeBurnRefund BalanceChangeReason = 14 - BalanceChangeWithdrawal BalanceChangeReason = 15 + 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/statedb.go b/core/state/statedb.go index 7800be8a09df..ff33096f9ce1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -486,7 +486,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prevbalance: prev, }) if s.logger != nil { - s.logger.OnBalanceChange(addr, prev, n, BalanceChangeSuicideWithdraw) + s.logger.OnBalanceChange(addr, prev, n, BalanceDecreaseSelfdestruct) } stateObject.markSelfdestructed() stateObject.data.Balance = n @@ -879,7 +879,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // If ether was sent to account post-selfdestruct it is burnt. if bal := obj.Balance(); bal.Sign() != 0 && s.logger != nil { - s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceChangeBurn) + s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceDecreaseSelfdestructBurn) } // We need to maintain account deletions explicitly (will remain // set indefinitely). Note only the first occurred self-destruct diff --git a/core/state_transition.go b/core/state_transition.go index 165fbd853e77..880e7f81fb6e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -270,7 +270,7 @@ func (st *StateTransition) buyGas() error { st.gasRemaining += st.msg.GasLimit st.initialGas = st.msg.GasLimit - st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) + st.state.SubBalance(st.msg.From, mgval, state.BalanceDecreaseGasBuy) return nil } @@ -445,7 +445,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.BalanceChangeRewardTransactionFee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -471,7 +471,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // 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.BalanceChangeGasRefund) + st.state.AddBalance(st.msg.From, remaining, state.BalanceIncreaseGasReturn) if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 13f7425f67b1..a70b4bea777c 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -855,7 +855,7 @@ 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.BalanceChangeSuicideRefund) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.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) @@ -870,8 +870,8 @@ 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.BalanceChangeSuicideWithdraw) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceChangeSuicideRefund) + interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceDecreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.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) From 68bd6c6b317c0dcfa479aa3fd9328ed8583db57a Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Thu, 11 Jan 2024 06:24:52 -0500 Subject: [PATCH 074/100] Removed the `OnGenesisBlock` in `genesis.Commit` (#20) This is not actually required as the `blockchain` does emit the `OnGenesisBlock` itself if starting a sync from scratch. --- cmd/geth/chaincmd.go | 2 +- core/blockchain.go | 2 +- core/chain_makers.go | 2 +- core/genesis.go | 19 ++++++++----------- core/genesis_test.go | 10 +++++----- core/headerchain_test.go | 2 +- eth/filters/filter_test.go | 2 +- tests/block_test_util.go | 2 +- 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index e17098214242..a7715e6e7a79 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -202,7 +202,7 @@ func initGenesis(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) defer triedb.Close() - _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides, nil) + _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } diff --git a/core/blockchain.go b/core/blockchain.go index e7ba251c8f1a..1484b8650a67 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -295,7 +295,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // 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. - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, logger) + chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } diff --git a/core/chain_makers.go b/core/chain_makers.go index f0d21e9c45dd..2949162bfe61 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -409,7 +409,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, triedb := trie.NewDatabase(db, trie.HashDefaults) defer triedb.Close() - _, err := genesis.Commit(db, triedb, nil) + _, err := genesis.Commit(db, triedb) if err != nil { panic(err) } diff --git a/core/genesis.go b/core/genesis.go index 59f06007b2e1..b28d403b222c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -156,7 +156,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { // flush 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, bcLogger BlockchainLogger) error { +func (ga *GenesisAlloc) flush(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 @@ -307,10 +307,10 @@ type ChainOverrides struct { // // The returned chain configuration is never nil. func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlockWithOverride(db, triedb, genesis, nil, nil) + return SetupGenesisBlockWithOverride(db, triedb, genesis, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides, bcLogger BlockchainLogger) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } @@ -335,7 +335,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen } applyOverrides(genesis.Config) - block, err := genesis.Commit(db, triedb, bcLogger) + block, err := genesis.Commit(db, triedb) if err != nil { return genesis.Config, common.Hash{}, err } @@ -356,7 +356,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen if hash != stored { return genesis.Config, hash, &GenesisMismatchError{stored, hash} } - block, err := genesis.Commit(db, triedb, bcLogger) + block, err := genesis.Commit(db, triedb) if err != nil { return genesis.Config, hash, err } @@ -524,7 +524,7 @@ func (g *Genesis) ToBlock() *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. -func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger BlockchainLogger) (*types.Block, error) { +func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) { block := g.ToBlock() if block.Number().Sign() != 0 { return nil, errors.New("can't commit genesis block with number > 0") @@ -539,13 +539,10 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { return nil, errors.New("can't start clique chain without signers") } - if bcLogger != nil { - bcLogger.OnGenesisBlock(block, g.Alloc) - } // 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(), bcLogger); err != nil { + if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) @@ -564,7 +561,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc // Note the state changes will be committed in hash-based scheme, use Commit // if path-scheme is preferred. func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block { - block, err := g.Commit(db, triedb, nil) + block, err := g.Commit(db, triedb) if err != nil { panic(err) } diff --git a/core/genesis_test.go b/core/genesis_test.go index 8d97430123f8..1d85b510caa1 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -38,7 +38,7 @@ func TestInvalidCliqueConfig(t *testing.T) { block := DefaultGoerliGenesisBlock() block.ExtraData = []byte{} db := rawdb.NewMemoryDatabase() - if _, err := block.Commit(db, trie.NewDatabase(db, nil), nil); err == nil { + if _, err := block.Commit(db, trie.NewDatabase(db, nil)); err == nil { t.Fatal("Expected error on invalid clique config") } } @@ -97,7 +97,7 @@ func testSetupGenesis(t *testing.T, scheme string) { name: "custom block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { tdb := trie.NewDatabase(db, newDbConfig(scheme)) - customg.Commit(db, tdb, nil) + customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, nil) }, wantHash: customghash, @@ -107,7 +107,7 @@ func testSetupGenesis(t *testing.T, scheme string) { name: "custom block in DB, genesis == goerli", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { tdb := trie.NewDatabase(db, newDbConfig(scheme)) - customg.Commit(db, tdb, nil) + customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, @@ -118,7 +118,7 @@ func testSetupGenesis(t *testing.T, scheme string) { name: "compatible config in DB", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { tdb := trie.NewDatabase(db, newDbConfig(scheme)) - oldcustomg.Commit(db, tdb, nil) + oldcustomg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, &customg) }, wantHash: customghash, @@ -130,7 +130,7 @@ func testSetupGenesis(t *testing.T, scheme string) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. tdb := trie.NewDatabase(db, newDbConfig(scheme)) - oldcustomg.Commit(db, tdb, nil) + oldcustomg.Commit(db, tdb) bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) defer bc.Stop() diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 9e901671e8a6..2c0323e6f74d 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - gspec.Commit(db, trie.NewDatabase(db, nil), nil) + gspec.Commit(db, trie.NewDatabase(db, nil)) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index a14bc3b20f39..1db917c960e5 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -180,7 +180,7 @@ func TestFilters(t *testing.T) { // Hack: GenerateChainWithGenesis creates a new db. // Commit the genesis manually and use GenerateChain. - _, err = gspec.Commit(db, trie.NewDatabase(db, nil), nil) + _, err = gspec.Commit(db, trie.NewDatabase(db, nil)) if err != nil { t.Fatal(err) } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 765935867cb0..e0130be48a0b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -128,7 +128,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, po // Commit genesis state gspec := t.genesis(config) triedb := trie.NewDatabase(db, tconf) - gblock, err := gspec.Commit(db, triedb, nil) + gblock, err := gspec.Commit(db, triedb) if err != nil { return err } From f241a76f4a26a730630b4263dac448ad2b1dd89d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 12 Jan 2024 16:24:42 +0330 Subject: [PATCH 075/100] fix comment' --- core/state/metadata.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/state/metadata.go b/core/state/metadata.go index 6e7a717794b7..2d1cd9c656b6 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -58,8 +58,6 @@ const ( // 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. - // This can happen either at the point of self-destruction, or at the end of the tx - // if ether was sent to contract post-selfdestruct. BalanceDecreaseSelfdestruct BalanceChangeReason = 13 // BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed // account within the same tx (captured at end of tx). From 580f02527e65dfb5252f681c6d5507a5874d97f1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 12 Jan 2024 17:53:12 +0330 Subject: [PATCH 076/100] has call reverted to snapshot --- core/vm/evm.go | 13 ++++++++++--- core/vm/instructions.go | 4 ++-- core/vm/logger.go | 12 ++++++++++-- eth/tracers/directory/noop.go | 4 ++-- eth/tracers/js/goja.go | 4 ++-- eth/tracers/js/tracer_test.go | 6 +++--- eth/tracers/live/printer.go | 4 ++-- eth/tracers/logger/logger.go | 4 ++-- eth/tracers/logger/logger_json.go | 2 +- eth/tracers/native/call.go | 16 +++++++++------- eth/tracers/native/call_flat.go | 8 ++++---- eth/tracers/native/mux.go | 8 ++++---- 12 files changed, 51 insertions(+), 34 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index e003084c6b8a..d2617283dd3b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,6 +17,7 @@ package vm import ( + "errors" "math/big" "sync/atomic" @@ -536,10 +537,16 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas if leftOverGas != 0 { tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverReturned) } - + var reverted bool + if err != nil { + reverted = true + } + if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { + reverted = false + } if isRoot { - tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err)) + tracer.CaptureEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } else { - tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err)) + tracer.CaptureExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index a70b4bea777c..b9c5b153b731 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -859,7 +859,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext 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.CaptureExit([]byte{}, 0, nil) + tracer.CaptureExit([]byte{}, 0, nil, false) } return nil, errStopToken } @@ -875,7 +875,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon 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.CaptureExit([]byte{}, 0, nil) + tracer.CaptureExit([]byte{}, 0, nil, false) } return nil, errStopToken } diff --git a/core/vm/logger.go b/core/vm/logger.go index 94c499b0a418..e86bb5d98e27 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -36,10 +36,18 @@ type EVMLogger interface { 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(output []byte, gasUsed uint64, err error) + // 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(output []byte, gasUsed uint64, err error) + // 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) diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index f02884e33b5e..4aeb15ae30b7 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -44,7 +44,7 @@ func (t *NoopTracer) CaptureStart(from common.Address, to common.Address, create } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (t *NoopTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -67,7 +67,7 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. // 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) { +func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } func (*NoopTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) {} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 4d45e4fdc79f..73b106f4ee1e 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -331,7 +331,7 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } @@ -369,7 +369,7 @@ func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad // CaptureExit 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) { +func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { if !t.traceFrame { return } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index a247b993187a..11c44fbcc4ab 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.ChainC tracer.CaptureTxStart(env, 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) + tracer.CaptureEnd(ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) if err != nil { @@ -209,7 +209,7 @@ 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}) tracer.CaptureTxStart(env, types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.CaptureStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) - tracer.CaptureEnd(nil, 0, nil) + tracer.CaptureEnd(nil, 0, nil, false) ret, err := tracer.GetResult() if err != nil { t.Fatal(err) @@ -279,7 +279,7 @@ func TestEnterExit(t *testing.T) { 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.CaptureExit([]byte{}, 400, nil) + tracer.CaptureExit([]byte{}, 400, nil, false) have, err := tracer.GetResult() if err != nil { diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 727dc3dc1610..55da7352e0ea 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -31,7 +31,7 @@ func (p *Printer) CaptureStart(from common.Address, to common.Address, create bo } // CaptureEnd is called after the call finishes to finalize the tracing. -func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error) { +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) } @@ -55,7 +55,7 @@ func (p *Printer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Add // 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) { +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) } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index a56dc47c720d..c3bc494280bb 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -210,7 +210,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s } // CaptureEnd is called after the call finishes to finalize the tracing. -func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { l.output = output l.err = err if l.cfg.Debug { @@ -377,7 +377,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope 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) { +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) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 96d6f1a1010d..1bf88f8899ea 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -77,7 +77,7 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco } // CaptureEnd is triggered at end of execution. -func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { +func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index f2515f4dbd4d..43bd0198da73 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -59,7 +59,8 @@ type callFrame struct { Logs []callLog `json:"logs,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. - Value *big.Int `json:"value,omitempty" rlp:"optional"` + Value *big.Int `json:"value,omitempty" rlp:"optional"` + revertedSnapshot bool } func (f callFrame) TypeString() string { @@ -67,16 +68,17 @@ func (f callFrame) TypeString() string { } func (f callFrame) failed() bool { - return len(f.Error) > 0 + return len(f.Error) > 0 && f.revertedSnapshot } -func (f *callFrame) processOutput(output []byte, err error) { +func (f *callFrame) processOutput(output []byte, err error, reverted bool) { output = common.CopyBytes(output) if err == nil { f.Output = output return } f.Error = err.Error() + f.revertedSnapshot = reverted if f.Type == vm.CREATE || f.Type == vm.CREATE2 { f.To = nil } @@ -147,8 +149,8 @@ func (t *callTracer) CaptureStart(from common.Address, to common.Address, create } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - t.callstack[0].processOutput(output, err) +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. @@ -180,7 +182,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. // CaptureExit 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) { +func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { t.depth-- if t.config.OnlyTopCall { return @@ -195,7 +197,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { size -= 1 call.GasUsed = gasUsed - call.processOutput(output, err) + call.processOutput(output, err, reverted) t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index dbbe6901a348..26f114f44fe3 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -151,8 +151,8 @@ func (t *flatCallTracer) CaptureStart(from common.Address, to common.Address, cr } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - t.tracer.CaptureEnd(output, gasUsed, err) +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. @@ -178,8 +178,8 @@ func (t *flatCallTracer) CaptureEnter(typ vm.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 *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { - t.tracer.CaptureExit(output, gasUsed, err) +func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { + t.tracer.CaptureExit(output, gasUsed, err, reverted) // Parity traces don't include CALL/STATICCALLs to precompiles. // By default we remove them from the callstack. diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index c39d84087667..62657fe8cc08 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -68,9 +68,9 @@ 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) { +func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - t.CaptureEnd(output, gasUsed, err) + t.CaptureEnd(output, gasUsed, err, reverted) } } @@ -111,9 +111,9 @@ func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.A // 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) { +func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { for _, t := range t.tracers { - t.CaptureExit(output, gasUsed, err) + t.CaptureExit(output, gasUsed, err, reverted) } } From f21efbc3edb08f07d0e27b0ab82266dd1adf4663 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 12 Jan 2024 18:11:52 +0330 Subject: [PATCH 077/100] fix traceWriter --- cmd/evm/internal/t8ntool/tracewriter.go | 33 ++++++++++++++++--------- cmd/evm/internal/t8ntool/transition.go | 4 +-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/cmd/evm/internal/t8ntool/tracewriter.go b/cmd/evm/internal/t8ntool/tracewriter.go index e4efad112f74..8a850f1d9812 100644 --- a/cmd/evm/internal/t8ntool/tracewriter.go +++ b/cmd/evm/internal/t8ntool/tracewriter.go @@ -22,8 +22,9 @@ import ( "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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/log" ) @@ -38,11 +39,11 @@ type traceWriter struct { // Compile-time interface check var _ = vm.EVMLogger((*traceWriter)(nil)) -func (t *traceWriter) CaptureTxEnd(restGas uint64) { - t.inner.CaptureTxEnd(restGas) +func (t *traceWriter) CaptureTxEnd(receipt *types.Receipt, err error) { + t.inner.CaptureTxEnd(receipt, err) defer t.f.Close() - if tracer, ok := t.inner.(tracers.Tracer); ok { + if tracer, ok := t.inner.(directory.Tracer); ok { result, err := tracer.GetResult() if err != nil { log.Warn("Error in tracer", "err", err) @@ -56,21 +57,23 @@ func (t *traceWriter) CaptureTxEnd(restGas uint64) { } } -func (t *traceWriter) CaptureTxStart(gasLimit uint64) { t.inner.CaptureTxStart(gasLimit) } -func (t *traceWriter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.inner.CaptureStart(env, from, to, create, input, gas, value) +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) { - t.inner.CaptureEnd(output, gasUsed, err) +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) { - t.inner.CaptureExit(output, gasUsed, err) +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) { @@ -79,3 +82,11 @@ func (t *traceWriter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sc 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 4dc50e577fd4..05d616442932 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -31,7 +31,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" + "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -113,7 +113,7 @@ func Transition(ctx *cli.Context) error { if err != nil { return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) + 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)) } From c3319301cc7dc3a4b5cadc7b881f53497c62e103 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 15 Jan 2024 13:37:39 +0330 Subject: [PATCH 078/100] add test case for frontier create out of storage --- .../frontier_create_outofstorage.json | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json new file mode 100644 index 000000000000..c46fe080f7f2 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json @@ -0,0 +1,189 @@ +{ + "genesis": { + "difficulty": "7797655526461", + "extraData": "0xd583010203844765746885676f312e35856c696e7578", + "gasLimit": "3141592", + "hash": "0x4ad333086cb86a6d261329504c9e1ca4d571212f56d6635dd213b700e1e85a6f", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226", + "mixHash": "0xdaca4c8bd9a6e6707059736633543ebf50f97c07700a9ed55859b97275c19ea5", + "nonce": "0x894c15d74e8ae8bd", + "number": "469666", + "stateRoot": "0xf9c50965ffae3f99310483a7836c545a025cc680303adaf3671dbeef99edf03a", + "timestamp": "1446318401", + "totalDifficulty": "2462705215747880313", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0" + }, + "0x0047a8033cc6d6ca2ed5044674fd421f44884de8": { + "balance": "0x44f5ced08fe37cf7", + "nonce": "872" + }, + "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8": { + "balance": "0x0", + "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806338cc48311461004f578063767800de14610088578063d1d80fdf146100c15761004d565b005b61005c60048050506100ff565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61009560048050506100d9565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100d7600480803590602001909190505061012e565b005b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905061012b565b90565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018a57610002565b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be" + } + }, + "0xe48430c4e88a929bba0ee3dce284866a9937b609": { + "balance": "0x26758774d51d8677a", + "nonce": "261" + }, + "0xf631e3b3aafa084bc51c714825aacf505d2059be": { + "balance": "0x0", + "code": "0x606060405236156100da5760e060020a600035046323dc42e781146100ff5780632ef3accc146101a5578063385928321461021d57806345362978146102b65780634c7737951461034a578063524f38891461035c5780635c242c59146103ad578063772286591461044a5780637e1c42051461052457806381ade30714610601578063a2ec191a14610696578063adf59f991461071b578063ae815843146107b5578063bf1fe4201461084f578063de4b326214610890578063e8025731146108d4578063e839e65e14610970578063fbf8041814610a44575b610b20604051600160a060020a03331690600090349082818181858883f15050505050565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008260006000610c0b83335b60006113fd8362030d40846101f5565b6040805160206004803580820135601f8101849004840285018401909552848452610b22949193602493909291840191908190840183828082843750949650509335935050505060006113fd8383335b600160a060020a03811660009081526003602052604081205460ff168114156114b557610b57565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050506000610d5885858585610841565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750949650505050505050600082600060006114068333610195565b610b34600154600160a060020a031681565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375094965050505050505060006114008233610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b60008360006000610d5f8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610cb88333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505050505b60008460006000610f288333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c0135918201839004830284018301909452808352979998604498929750929092019450925082915084018382808284375094965050505050505060006113fd6000848462030d40610439565b6040805160206004803580820135601f8101849004840285018401909552848452610b209491936024939092918401919081908401838280828437509496505093359350505050600254600090600160a060020a039081163391909116148015906107115750600154600160a060020a039081163390911614155b156111fd57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000610c0484848462030d40610439565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b6000610d5885858585610439565b610b20600435600254600160a060020a039081163391909116148015906108865750600154600160a060020a039081163390911614155b156114b057610002565b610b20600435600254600090600160a060020a039081163391909116148015906108ca5750600154600160a060020a039081163390911614155b1561134d57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505093359350505050600083600060006111618333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610b5e8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760849791965060249190910194509092508291508401838280828437509496505093359350505050600084600060006112a68333610195565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b93505050505b9392505050565b91508160001415610b8d57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610bee57604051600160a060020a03331690600090839082818181858883f150505050505b610b51600088888862030d406105f0565b610002565b9050610b57565b91508160001415610c3a57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610c9b57604051600160a060020a03331690600090839082818181858883f150505050505b610b5187878762030d40610439565b93505050505b949350505050565b91508160001415610ce757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610d4857604051600160a060020a03331690600090839082818181858883f150505050505b610caa8888888862030d406105f0565b9050610cb0565b91508160001415610d8e57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610def57604051600160a060020a03331690600090839082818181858883f150505050505b604080516000805442810183528351928390036020908101842060019290920183558184528381018d9052608084018a905260a09484018581528c51958501959095528b519198507f1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c679489948e948e948e948e9492606085019260c086019289810192829185918391869190600490601f850104600302600f01f150905090810190601f168015610eb45780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610f0d5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a150610cb0915050565b91508160001415610f5757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610fb857604051600160a060020a03331690600090839082818181858883f150505050505b60006000505442016040518082815260200191505060405180910390209350835060006000818150548092919060010191905055507f4e65aab8959da44521dc50a6ce3dfbd65016d8cfab70a47ea7541458206c4d5b848a8a8a8a8a604051808781526020018681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561108e5780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110e75780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111405780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a15050505b95945050505050565b9150816000141561119057600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f150505034849003925082111590506111f157604051600160a060020a03331690600090839082818181858883f150505050505b610caa88888888610439565b82604051808280519060200190808383829060006004602084601f0104600302600f01f1506007805491909301849003909320600184018084559095508594509192918391508280158290116112765781836000526020600020918201910161127691905b808211156112a25760008155600101611262565b505050815481101561000257600091825260208083209091019290925591825260069052604090205550565b5090565b915081600014156112d557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061133657604051600160a060020a03331690600090839082818181858883f150505050505b61134389898989896105f0565b9350505050611158565b50600481905560005b6007548110156113f957600780546006916000918490811015610002575080547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888501548352602093909352604082205485029260059291908590811015610002579082527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688018150548152602081019190915260400160002055600101611356565b5050565b90505b92915050565b9150816000141561143557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061149657604051600160a060020a03331690600090839082818181858883f150505050505b6114a66000878762030d40610439565b9350505050611400565b600855565b6005600050600085604051808280519060200190808383829060006004602084601f0104600302600f01f1509091018290039091208352505060209190915260409020546008548402019050610b5756", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xde5cab2c6836c23f6388364c9a0e20bd1c8c7e6c3b5d0339cd8a2f7c4b36208c": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4": { + "balance": "0x2c52a97273d2164" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "shanghaiTime": 1681338455, + "terminalTotalDifficulty": 7797655526461000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "469667", + "difficulty": "7793848077478", + "timestamp": "1446318425", + "gasLimit": "3141592", + "miner": "0xe48430c4e88a929bba0ee3dce284866a9937b609" + }, + "input": "0xf91ec7820368850ba43b7400831b77408080b91e72606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b50561ca083d25971e732af3acb0a223dea6258f37407bf2d075fd852a83312238fca7cdea01f5a1189b054e947a0a140c565c4fc829b584e7348c9a7f65a890fe688e8b67f", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", + "gas": "0x1b7740", + "gasUsed": "0x9274f", + "input": "0x606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", + "error": "contract creation code storage out of gas", + "calls": [ + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12c54b", + "gasUsed": "0x106", + "to": "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8", + "input": "0x38cc4831", + "output": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x127270", + "gasUsed": "0x26b", + "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "input": "0x2ef3accc00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x18", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xc24431c1a1147456414355b1f1769de450e524da", + "gas": "0x124995", + "gasUsed": "0x78f5", + "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "input": "0x385928320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000", + "output": "0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32", + "calls": [ + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x0", + "gasUsed": "0x0", + "to": "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4", + "input": "0x", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "gas": "0x18", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30", + "value": "0x0", + "type": "CALL" + } + ], + "logs":[ + { + "address": "0xf631e3b3aafa084bc51c714825aacf505d2059be", + "topics": ["0x1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c67"], + "data":"0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000", + "position":"0x3" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CREATE" + } +} \ No newline at end of file From 626fee4fed96858708ef8931ded73c7a2b0a65e1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 15 Jan 2024 19:40:55 +0330 Subject: [PATCH 079/100] fix withdraw balance change name --- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/beacon/consensus.go | 2 +- core/state/metadata.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index d5c8ffb53681..c2ef09721eda 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -325,7 +325,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, 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.BalanceChangeWithdrawal) + statedb.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) } // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 4b91a6099757..9ab9026fa8e2 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -357,7 +357,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.BalanceChangeWithdrawal) + stateDB.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/core/state/metadata.go b/core/state/metadata.go index 2d1cd9c656b6..77fce6c26cb4 100644 --- a/core/state/metadata.go +++ b/core/state/metadata.go @@ -29,7 +29,7 @@ const ( // BalanceIncreaseRewardMineBlock is a reward for mining a block. BalanceIncreaseRewardMineBlock BalanceChangeReason = 2 // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain. - BalanceChangeWithdrawal BalanceChangeReason = 3 + BalanceIncreaseWithdrawal BalanceChangeReason = 3 // BalanceIncreaseGenesisBalance is ether allocated at the genesis block. BalanceIncreaseGenesisBalance BalanceChangeReason = 4 From d07264afe034a793a84075ba0e635a12ebc74c1b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 16 Jan 2024 21:03:16 +0330 Subject: [PATCH 080/100] no balance change reason on 0 balance selfdestruct --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ba06d8e4d6a7..847812fe89a6 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -485,7 +485,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) { prev: stateObject.selfDestructed, prevbalance: prev, }) - if s.logger != nil { + if s.logger != nil && prev.Sign() > 0 { s.logger.OnBalanceChange(addr, prev, n, BalanceDecreaseSelfdestruct) } stateObject.markSelfdestructed() From 9a6b9a2735aa14b97eec24cbba08219f43541bf8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 30 Jan 2024 15:54:03 +0100 Subject: [PATCH 081/100] re-add simulated backend removed accidentally --- accounts/abi/bind/backends/simulated.go | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 accounts/abi/bind/backends/simulated.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go new file mode 100644 index 000000000000..756a9d355264 --- /dev/null +++ b/accounts/abi/bind/backends/simulated.go @@ -0,0 +1,52 @@ +// 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 backends + +import ( + "context" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/ethclient/simulated" +) + +// SimulatedBackend is a simulated blockchain. +// Deprecated: use package github.com/ethereum/go-ethereum/ethclient/simulated instead. +type SimulatedBackend struct { + *simulated.Backend + simulated.Client +} + +// Fork sets the head to a new block, which is based on the provided parentHash. +func (b *SimulatedBackend) Fork(ctx context.Context, parentHash common.Hash) error { + return b.Backend.Fork(parentHash) +} + +// NewSimulatedBackend creates a new binding backend using a simulated blockchain +// for testing purposes. +// +// A simulated backend always uses chainID 1337. +// +// Deprecated: please use simulated.Backend from package +// github.com/ethereum/go-ethereum/ethclient/simulated instead. +func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { + b := simulated.NewBackend(alloc, simulated.WithBlockGasLimit(gasLimit)) + return &SimulatedBackend{ + Backend: b, + Client: b.Client(), + } +} From ae522d6fb614b6741b3bfd3198d6b2eb6e342e6f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 30 Jan 2024 16:29:19 +0100 Subject: [PATCH 082/100] rm empty line Co-authored-by: Martin HS --- core/vm/evm.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index be0a204ecd94..5badc33b89c1 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -336,7 +336,6 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if evm.Config.Tracer != nil { evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution) } - gas = 0 } } From 56862cf07f20ab8f35d3db00812a3cb2fc02df87 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 30 Jan 2024 16:36:14 +0100 Subject: [PATCH 083/100] emit onNewAccount when reseting account --- core/state/statedb.go | 18 ++++++++++-------- eth/tracers/directory/noop.go | 2 +- eth/tracers/live/printer.go | 2 +- eth/tracers/native/mux.go | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 409dfeca9fdd..7dc346bf1a45 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -61,7 +61,9 @@ type StateLogger interface { OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) OnLog(log *types.Log) // OnNewAccount is called when a new account is created. - OnNewAccount(addr common.Address) + // Reset indicates an account existed at that address + // which will be replaced. + OnNewAccount(addr common.Address, reset bool) } // StateDB structs within the ethereum protocol are used to store anything @@ -665,15 +667,15 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { 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) + } + } if prev == nil { s.journal.append(createObjectChange{account: &addr}) - 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) - } - } } else { // The original account should be marked as destructed and all cached // account and storage data should be cleared as well. Note, it must diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index 4aeb15ae30b7..e784b6c8462e 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -86,7 +86,7 @@ func (*NoopTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { func (*NoopTracer) OnLog(log *types.Log) {} -func (*NoopTracer) OnNewAccount(a common.Address) {} +func (*NoopTracer) OnNewAccount(a common.Address, reset bool) {} // GetResult returns an empty json object. func (t *NoopTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index 55da7352e0ea..fc6e75900535 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -125,7 +125,7 @@ func (p *Printer) OnLog(l *types.Log) { fmt.Printf("OnLog: l=%s\n", buf) } -func (p *Printer) OnNewAccount(a common.Address) { +func (p *Printer) OnNewAccount(a common.Address, reset bool) { fmt.Printf("OnNewAccount: a=%v\n", a) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 62657fe8cc08..1175cc768a3a 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -159,9 +159,9 @@ func (t *muxTracer) OnLog(log *types.Log) { } } -func (t *muxTracer) OnNewAccount(a common.Address) { +func (t *muxTracer) OnNewAccount(a common.Address, reset bool) { for _, t := range t.tracers { - t.OnNewAccount(a) + t.OnNewAccount(a, reset) } } From 68342ef933dc716cbc145bc8e06945c9bdef9184 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 31 Jan 2024 12:03:21 +0100 Subject: [PATCH 084/100] improve processBlock --- core/blockchain.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 6230e0826a42..b6e6096da33e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1809,8 +1809,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } // The traced section of block import. - err, stop, res := bc.processBlock(block, statedb, &followupInterrupt, start, setHead) - if err != nil || stop { + res, err := bc.processBlock(block, statedb, &followupInterrupt, start, setHead) + followupInterrupt.Store(true) + if err != nil { return it.index, err } // Report the import stats before returning the various results @@ -1887,7 +1888,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, followupInterrupt *atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { +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) @@ -1901,16 +1902,14 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, f receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return err, true, nil + return nil, err } ptime := time.Since(pstart) vstart := time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - followupInterrupt.Store(true) - return err, true, nil + return nil, err } vtime := time.Since(vstart) proctime := time.Since(start) // processing + validation @@ -1942,9 +1941,8 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, f } else { status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) } - followupInterrupt.Store(true) if err != nil { - return err, true, &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status} + return nil, err } // Update the metrics touched during block commit accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them @@ -1955,7 +1953,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, f blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockInsertTimer.UpdateSince(start) - return nil, false, &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status} + return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil } // insertSideChain is called when an import batch hits upon a pruned ancestor From 3078dfe80be0f4cb3eacb439810e69975eb75148 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 31 Jan 2024 12:05:59 +0100 Subject: [PATCH 085/100] minor fix --- core/blockchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index b6e6096da33e..180f74fc11c9 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } // The traced section of block import. - res, err := bc.processBlock(block, statedb, &followupInterrupt, start, setHead) + res, err := bc.processBlock(block, statedb, start, setHead) followupInterrupt.Store(true) if err != nil { return it.index, err From 6c44a594f4423664cc363ea4e9e50223a4597139 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 5 Feb 2024 18:29:53 +0100 Subject: [PATCH 086/100] fix self destruct burn condition --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 7dc346bf1a45..42daa16c2ae7 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -881,7 +881,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.ToBig(), new(big.Int), BalanceDecreaseSelfdestructBurn) } // We need to maintain account deletions explicitly (will remain From 188cd4182e3dee1c7ac5fc91b0c29cde2c2eb48f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 5 Feb 2024 18:37:57 +0100 Subject: [PATCH 087/100] remove precompile check for newAccount --- core/state/statedb.go | 18 +----------------- core/state_processor.go | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 42daa16c2ae7..d202eba393a2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -125,9 +125,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 @@ -184,7 +181,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(), @@ -668,11 +664,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}) @@ -1389,14 +1381,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 6e46e7a08dae..e98b32cee3d2 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) From f3c0a89b574c34dc88349c0b3df9d8b1e7e707ab Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 6 Feb 2024 17:21:52 +0100 Subject: [PATCH 088/100] add OnBlockchainInit for chainConfig --- core/blockchain.go | 10 +++++++--- eth/tracers/live/printer.go | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 180f74fc11c9..53d0ab358774 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) @@ -502,6 +503,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 if it's enabled. if txLookupLimit != nil { bc.txIndexer = newTxIndexer(*txLookupLimit, bc) @@ -1762,7 +1766,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) } @@ -1891,7 +1895,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/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index fc6e75900535..34e137e928c7 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -84,7 +84,7 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) { fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) } -func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header, _ *params.ChainConfig) { +func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { 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 { @@ -96,6 +96,10 @@ func (p *Printer) OnBlockEnd(err error) { fmt.Printf("OnBlockEnd: err=%v\n", err) } +func (p *Printer) OnBlockchainInit(chainConfig *params.ChainConfig) { + fmt.Printf("OnBlockchainInit: chainConfig=%v\n", chainConfig) +} + func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc)) } From 95b50299a5c4f96ccdd44fe73d543f28629e1938 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 6 Feb 2024 17:31:33 +0100 Subject: [PATCH 089/100] replace printer with noop live tracer --- eth/tracers/live/noop.go | 98 +++++++++++++++++++++++++ eth/tracers/live/printer.go | 138 ------------------------------------ 2 files changed, 98 insertions(+), 138 deletions(-) create mode 100644 eth/tracers/live/noop.go delete mode 100644 eth/tracers/live/printer.go diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go new file mode 100644 index 000000000000..8e94e7ddcd8f --- /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("liveNoop", newLiveNoopTracer) +} + +// liveNoop 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 liveNoop struct{} + +func newLiveNoopTracer() (core.BlockchainLogger, error) { + return &liveNoop{}, nil +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *liveNoop) 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 *liveNoop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *liveNoop) 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 *liveNoop) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +} + +// CaptureKeccakPreimage is called during the KECCAK256 opcode. +func (t *liveNoop) CaptureKeccakPreimage(hash common.Hash, data []byte) {} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *liveNoop) 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 *liveNoop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { +} + +func (t *liveNoop) OnBeaconBlockRootStart(root common.Hash) {} +func (t *liveNoop) OnBeaconBlockRootEnd() {} + +func (t *liveNoop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +} + +func (t *liveNoop) CaptureTxEnd(receipt *types.Receipt, err error) { +} + +func (t *liveNoop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { +} + +func (t *liveNoop) OnBlockEnd(err error) { +} + +func (t *liveNoop) OnBlockchainInit(chainConfig *params.ChainConfig) { +} + +func (t *liveNoop) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +} + +func (t *liveNoop) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +} + +func (t *liveNoop) OnNonceChange(a common.Address, prev, new uint64) { +} + +func (t *liveNoop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +} + +func (t *liveNoop) OnStorageChange(a common.Address, k, prev, new common.Hash) { +} + +func (t *liveNoop) OnLog(l *types.Log) { + +} + +func (t *liveNoop) OnNewAccount(a common.Address, reset bool) { +} + +func (t *liveNoop) 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 34e137e928c7..000000000000 --- a/eth/tracers/live/printer.go +++ /dev/null @@ -1,138 +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) { - 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) OnBlockchainInit(chainConfig *params.ChainConfig) { - fmt.Printf("OnBlockchainInit: chainConfig=%v\n", chainConfig) -} - -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) -} From 2cc09548bb86736718ff4c897c1b30e495ac31a6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 6 Feb 2024 17:33:18 +0100 Subject: [PATCH 090/100] rename --- eth/tracers/live/noop.go | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 8e94e7ddcd8f..822fbbaea334 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -13,86 +13,86 @@ import ( ) func init() { - directory.LiveDirectory.Register("liveNoop", newLiveNoopTracer) + directory.LiveDirectory.Register("noop", newNoopTracer) } -// liveNoop is a no-op live tracer. It's there to +// 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 liveNoop struct{} +type noop struct{} -func newLiveNoopTracer() (core.BlockchainLogger, error) { - return &liveNoop{}, nil +func newNoopTracer() (core.BlockchainLogger, error) { + return &noop{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *liveNoop) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +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 *liveNoop) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) { +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 *liveNoop) 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 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 *liveNoop) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +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 *liveNoop) CaptureKeccakPreimage(hash common.Hash, data []byte) {} +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 *liveNoop) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +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 *liveNoop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { +func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) { } -func (t *liveNoop) OnBeaconBlockRootStart(root common.Hash) {} -func (t *liveNoop) OnBeaconBlockRootEnd() {} +func (t *noop) OnBeaconBlockRootStart(root common.Hash) {} +func (t *noop) OnBeaconBlockRootEnd() {} -func (t *liveNoop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { +func (t *noop) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common.Address) { } -func (t *liveNoop) CaptureTxEnd(receipt *types.Receipt, err error) { +func (t *noop) CaptureTxEnd(receipt *types.Receipt, err error) { } -func (t *liveNoop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { +func (t *noop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { } -func (t *liveNoop) OnBlockEnd(err error) { +func (t *noop) OnBlockEnd(err error) { } -func (t *liveNoop) OnBlockchainInit(chainConfig *params.ChainConfig) { +func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { } -func (t *liveNoop) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +func (t *noop) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { } -func (t *liveNoop) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { +func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) { } -func (t *liveNoop) OnNonceChange(a common.Address, prev, new uint64) { +func (t *noop) OnNonceChange(a common.Address, prev, new uint64) { } -func (t *liveNoop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { +func (t *noop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) { } -func (t *liveNoop) OnStorageChange(a common.Address, k, prev, new common.Hash) { +func (t *noop) OnStorageChange(a common.Address, k, prev, new common.Hash) { } -func (t *liveNoop) OnLog(l *types.Log) { +func (t *noop) OnLog(l *types.Log) { } -func (t *liveNoop) OnNewAccount(a common.Address, reset bool) { +func (t *noop) OnNewAccount(a common.Address, reset bool) { } -func (t *liveNoop) OnGasChange(old, new uint64, reason vm.GasChangeReason) { +func (t *noop) OnGasChange(old, new uint64, reason vm.GasChangeReason) { } From 57cd0c30df8ca897a1ba1bd805822ee89e38869f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 8 Feb 2024 16:30:14 +0100 Subject: [PATCH 091/100] rm OnNewAccount --- core/state/statedb.go | 7 ------- eth/tracers/directory/noop.go | 2 -- eth/tracers/live/noop.go | 3 --- eth/tracers/native/mux.go | 6 ------ 4 files changed, 18 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index d202eba393a2..cbf2463c2c26 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -60,10 +60,6 @@ type StateLogger interface { 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) - // OnNewAccount is called when a new account is created. - // Reset indicates an account existed at that address - // which will be replaced. - OnNewAccount(addr common.Address, reset bool) } // StateDB structs within the ethereum protocol are used to store anything @@ -663,9 +659,6 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { 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 { - s.logger.OnNewAccount(addr, prev != nil) - } if prev == nil { s.journal.append(createObjectChange{account: &addr}) } else { diff --git a/eth/tracers/directory/noop.go b/eth/tracers/directory/noop.go index e784b6c8462e..5f6546cfbebc 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/directory/noop.go @@ -86,8 +86,6 @@ func (*NoopTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) { func (*NoopTracer) OnLog(log *types.Log) {} -func (*NoopTracer) OnNewAccount(a common.Address, reset bool) {} - // GetResult returns an empty json object. func (t *NoopTracer) GetResult() (json.RawMessage, error) { return json.RawMessage(`{}`), nil diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 822fbbaea334..2984c6ee8366 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -91,8 +91,5 @@ 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/native/mux.go b/eth/tracers/native/mux.go index 1175cc768a3a..70af63e752a3 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -159,12 +159,6 @@ func (t *muxTracer) OnLog(log *types.Log) { } } -func (t *muxTracer) OnNewAccount(a common.Address, reset bool) { - for _, t := range t.tracers { - t.OnNewAccount(a, reset) - } -} - // GetResult returns an empty json object. func (t *muxTracer) GetResult() (json.RawMessage, error) { resObject := make(map[string]json.RawMessage) From 056f2292602b9f8ae59dd14611234ec7f20653bc Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 8 Feb 2024 17:20:53 +0100 Subject: [PATCH 092/100] indicate known block --- core/blockchain.go | 10 +++++++--- eth/tracers/live/noop.go | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 53d0ab358774..5e0f5b90bd48 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -193,7 +193,11 @@ type BlockchainLogger interface { 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) + // `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) OnBlockEnd(err error) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) OnBeaconBlockRootStart(root common.Hash) @@ -1766,7 +1770,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.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), true) bc.logger.OnBlockEnd(nil) } @@ -1895,7 +1899,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.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), false) defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 2984c6ee8366..beb532a42366 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -63,7 +63,7 @@ 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) { +func (t *noop) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header, skip bool) { } func (t *noop) OnBlockEnd(err error) { From 706c869e93fb8265160018eac263bf53d46b47f6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 9 Feb 2024 10:46:01 +0100 Subject: [PATCH 093/100] fix remaining conflict --- core/txpool/blobpool/blobpool_test.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index d040bde76e00..40ed4fa14863 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -1248,13 +1248,8 @@ func TestAdd(t *testing.T) { keys[acc], _ = crypto.GenerateKey() addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) -<<<<<<< HEAD - // Seed the state database with this acocunt - statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), state.BalanceChangeUnspecified) -======= // Seed the state database with this account - statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance)) ->>>>>>> master + statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), state.BalanceChangeUnspecified) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store From 03206befb9a57d00411bba8e1ad7982a50710145 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 9 Feb 2024 11:02:39 +0100 Subject: [PATCH 094/100] fix blockchain -> logger circular import --- cmd/geth/config.go | 4 ++-- cmd/utils/flags.go | 4 ++-- core/blockchain_test.go | 8 +++++--- eth/tracers/directory/{live.go => live/dir.go} | 12 ++++++------ eth/tracers/live/noop.go | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) rename eth/tracers/directory/{live.go => live/dir.go} (55%) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index edc907ff3f90..c166ce158df0 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -36,7 +36,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "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,7 +181,7 @@ 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 := directory.LiveDirectory.New(name) + t, err := live.Directory.New(name) if err != nil { utils.Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 12ee94d7252c..bb48268f5911 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -51,7 +51,7 @@ import ( "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" - "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/ethdb/remotedb" "github.com/ethereum/go-ethereum/ethstats" @@ -2128,7 +2128,7 @@ 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 := directory.LiveDirectory.New(name) + t, err := live.Directory.New(name) if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d16bb39cc34d..46882f409816 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -21,6 +21,7 @@ import ( "fmt" "math/big" "math/rand" + "os" "sync" "testing" "time" @@ -35,6 +36,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/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -3062,7 +3064,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), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -3144,7 +3146,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), }, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -4290,7 +4292,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)}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/eth/tracers/directory/live.go b/eth/tracers/directory/live/dir.go similarity index 55% rename from eth/tracers/directory/live.go rename to eth/tracers/directory/live/dir.go index dc6927b14228..011d27f88746 100644 --- a/eth/tracers/directory/live.go +++ b/eth/tracers/directory/live/dir.go @@ -1,4 +1,4 @@ -package directory +package live import ( "errors" @@ -8,21 +8,21 @@ import ( type ctorFunc func() (core.BlockchainLogger, error) -// LiveDirectory is the collection of tracers which can be used +// Directory is the collection of tracers which can be used // during normal block import operations. -var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)} +var Directory = directory{elems: make(map[string]ctorFunc)} -type liveDirectory struct { +type directory struct { elems map[string]ctorFunc } // Register registers a tracer constructor by name. -func (d *liveDirectory) Register(name string, f ctorFunc) { +func (d *directory) Register(name string, f ctorFunc) { d.elems[name] = f } // New instantiates a tracer by name. -func (d *liveDirectory) New(name string) (core.BlockchainLogger, error) { +func (d *directory) New(name string) (core.BlockchainLogger, error) { if f, ok := d.elems[name]; ok { return f() } diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index beb532a42366..4ff4153c6049 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -8,12 +8,12 @@ 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" + "github.com/ethereum/go-ethereum/eth/tracers/directory/live" "github.com/ethereum/go-ethereum/params" ) func init() { - directory.LiveDirectory.Register("noop", newNoopTracer) + live.Directory.Register("noop", newNoopTracer) } // noop is a no-op live tracer. It's there to From 08cb623c2e27c562badcf55185e90f4eb761154a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 9 Feb 2024 11:13:35 +0100 Subject: [PATCH 095/100] live tracer err -> warn --- core/blockchain.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index ca8d111fbd40..ca78c799126c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -293,10 +293,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis var logger BlockchainLogger if vmConfig.Tracer != nil { l, ok := vmConfig.Tracer.(BlockchainLogger) - if !ok { - return nil, errors.New("only extended tracers are supported for live mode") + if ok { + logger = l + } else { + log.Warn("only extended tracers are supported for live mode") } - logger = l } // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the From cf6a31514b8c1b8502861fbe1773830172b1d98e Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 9 Feb 2024 11:19:56 +0100 Subject: [PATCH 096/100] fix mdLogger --- eth/tracers/logger/logger.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c3bc494280bb..562078177f12 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -335,6 +335,10 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } +func (t *mdLogger) CaptureTxStart(env *vm.EVM, 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) { if !create { fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", From 674a38ed60f307ed2be4fc7604079268fb008b8d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 14 Feb 2024 16:52:10 +0100 Subject: [PATCH 097/100] 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 d71cfbb38e7d..8454e35d68ea 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -100,6 +100,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 c166ce158df0..72ca956e92ea 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -18,6 +18,7 @@ package main import ( "bufio" + "encoding/json" "errors" "fmt" "os" @@ -181,7 +182,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 420958c9eebf..3312e29055e2 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 80a9c0f77c34..efb20d693e94 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" @@ -502,7 +503,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", @@ -2128,7 +2133,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 011d27f88746..39d1e99caa2f 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 0db7a19f339701ab7cee30fe8efead861300589c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 14 Feb 2024 16:54:51 +0100 Subject: [PATCH 098/100] 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 4ff4153c6049..cc597adfc55e 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 3ba6b92dfb8936405e8816d42a543bcfb221c4bf Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Feb 2024 16:05:55 +0100 Subject: [PATCH 099/100] 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 8341df826c9e..3e40ab50eae4 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() } // txLookup is wrapper over transaction lookup along with the corresponding diff --git a/core/state_processor.go b/core/state_processor.go index e98b32cee3d2..5b597240753f 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 cc597adfc55e..c565feced0c7 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 5f0a5437e6a821b4aff15d39fa1fc986cc7cf992 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 15 Feb 2024 16:22:59 +0100 Subject: [PATCH 100/100] 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 3e40ab50eae4..c4b18da48d94 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) } @@ -1770,8 +1779,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 @@ -1899,7 +1912,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 c565feced0c7..fe835e1d81ac 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) { }