diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 88ac13d1f0..8734cd79ba 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -34,7 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -121,7 +121,7 @@ type rejectedTx struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { + getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -419,7 +419,7 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime return ethash.CalcDifficulty(config, currentTime, parent) } -func writeTraceResult(tracer *directory.Tracer, f io.WriteCloser) error { +func writeTraceResult(tracer *tracers.Tracer, f io.WriteCloser) error { defer f.Close() result, err := tracer.GetResult() if err != nil || result == nil { diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index d8a8671468..72c7996a54 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -24,6 +24,7 @@ import ( "math/big" "os" "path" + "path/filepath" "golang.org/x/exp/slog" @@ -34,7 +35,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" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -89,7 +90,7 @@ func Transition(ctx *cli.Context) error { glogger.Verbosity(slog.Level(ctx.Int(VerbosityFlag.Name))) log.SetDefault(log.NewLogger(glogger)) - var getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { return nil, nil, nil } + var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil } baseDir, err := createBasedir(ctx) if err != nil { return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) @@ -121,13 +122,13 @@ func Transition(ctx *cli.Context) error { prevFile.Close() } }() - getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { - traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) + getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { + traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) if err != nil { return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } logger := logger.NewJSONLogger(logConfig, traceFile) - tracer := &directory.Tracer{ + tracer := &tracers.Tracer{ Hooks: logger, // jsonLogger streams out result to file. GetResult: func() (json.RawMessage, error) { return nil, nil }, @@ -140,12 +141,12 @@ func Transition(ctx *cli.Context) error { if ctx.IsSet(TraceTracerConfigFlag.Name) { config = []byte(ctx.String(TraceTracerConfigFlag.Name)) } - getTracer = func(txIndex int, txHash common.Hash) (*directory.Tracer, io.WriteCloser, error) { - traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) + getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { + traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) if err != nil { return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } - tracer, err := directory.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) + tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) if err != nil { return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 269862d1f2..60b0380b86 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -26,6 +26,10 @@ import ( "github.com/ethereum/go-ethereum/lib/debug" "github.com/ethereum/go-ethereum/lib/flags" "github.com/urfave/cli/v2" + + // Force-load the tracer engines to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) var ( @@ -143,6 +147,8 @@ var stateTransitionCommand = &cli.Command{ Action: t8ntool.Transition, Flags: []cli.Flag{ t8ntool.TraceFlag, + t8ntool.TraceTracerFlag, + t8ntool.TraceTracerConfigFlag, t8ntool.TraceDisableMemoryFlag, t8ntool.TraceEnableMemoryFlag, t8ntool.TraceDisableStackFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f409fe8339..1c1e123d02 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -52,7 +52,6 @@ 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/live" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/remotedb" "github.com/ethereum/go-ethereum/ethstats" @@ -2145,7 +2144,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if ctx.IsSet(VMTraceConfigFlag.Name) { config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name)) } - t, err := live.Directory.New(name, config) + t, err := tracers.LiveDirectory.New(name, config) if err != nil { Fatalf("Failed to create tracer %q: %v", name, err) } diff --git a/core/blockchain.go b/core/blockchain.go index 129a6dfeb7..6a128de4d3 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1834,6 +1834,7 @@ 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) { + // Disable tracing for prefetcher executions. vmCfg := bc.vmConfig vmCfg.Tracer = nil bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt) diff --git a/core/state_processor.go b/core/state_processor.go index ed93d5f170..35d66debde 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -111,14 +110,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb vm.StateDB, cfg vm. // this method takes an already created EVM instance as input. func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb vm.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil { - evm.Config.Tracer.OnTxStart(&tracing.VMContext{ - ChainConfig: evm.ChainConfig(), - StateDB: statedb, - BlockNumber: evm.Context.BlockNumber, - Time: evm.Context.Time, - Coinbase: evm.Context.Coinbase, - Random: evm.Context.Random, - }, tx, msg.From) + evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) if evm.Config.Tracer.OnTxEnd != nil { defer func() { evm.Config.Tracer.OnTxEnd(receipt, err) diff --git a/core/state_transition.go b/core/state_transition.go index bb074a2398..e901077cfc 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -140,8 +140,6 @@ 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. @@ -164,7 +162,6 @@ 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 { diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 073e4975fe..87753b315a 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) { sender = vm.AccountRef(cfg.Origin) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) - if cfg.EVMConfig.Tracer != nil { + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: @@ -158,7 +158,7 @@ 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 { + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: @@ -189,7 +189,7 @@ 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 { + if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index c9356d6155..fb05375498 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/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "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 := directory.DefaultDirectory.New(tracerCode, new(directory.Context), nil) + tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.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 := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil) + tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.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 := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil) + tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } diff --git a/eth/backend.go b/eth/backend.go index 6569b8b130..4ceed5f3dc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -45,7 +45,7 @@ import ( "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/lib/ethapi" @@ -212,7 +212,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.VMTraceConfig != "" { traceConfig = json.RawMessage(config.VMTraceConfig) } - t, err := live.Directory.New(config.VMTrace, traceConfig) + t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) if err != nil { return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 79e2e87ebf..0fb6501399 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -36,7 +36,6 @@ 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/lib/ethapi" @@ -273,7 +272,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 := &directory.Context{ + txctx := &Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), TxIndex: i, @@ -590,7 +589,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 := directory.DefaultDirectory.IsJS(*config.Tracer); isJS { + if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS { return api.traceBlockParallel(ctx, block, statedb, config) } } @@ -605,7 +604,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 := &directory.Context{ + txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: i, @@ -644,7 +643,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 := &directory.Context{ + txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: task.index, @@ -859,7 +858,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * return nil, err } - txctx := &directory.Context{ + txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: int(index), @@ -926,27 +925,26 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) } // Execute the trace - msg, err := args.ToMessage(api.backend.RPCGasCap(), vmctx.BaseFee) - if err != nil { + if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil { return nil, err } - tx, err := argsToTransaction(api.backend, &args, msg) - if err != nil { - return nil, err - } - var traceConfig *TraceConfig + var ( + msg = args.ToMessage(vmctx.BaseFee) + tx = args.ToTransaction() + traceConfig *TraceConfig + ) if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, tx, msg, new(directory.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, tx *types.Transaction, message *core.Message, txctx *directory.Context, vmctx vm.BlockContext, statedb vm.StateDB, config *TraceConfig) (interface{}, error) { +func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb vm.StateDB, config *TraceConfig) (interface{}, error) { var ( - tracer *directory.Tracer + tracer *Tracer err error timeout = defaultTraceTimeout usedGas uint64 @@ -955,9 +953,15 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor config = &TraceConfig{} } // Default tracer is the struct logger - tracer = logger.NewStructLogger(config.Config).Tracer() - if config.Tracer != nil { - tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) + if config.Tracer == nil { + logger := logger.NewStructLogger(config.Config) + tracer = &Tracer{ + Hooks: logger.Hooks(), + GetResult: logger.GetResult, + Stop: logger.Stop, + } + } else { + tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } @@ -1050,54 +1054,3 @@ 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/directory/tracers.go b/eth/tracers/dir.go similarity index 95% rename from eth/tracers/directory/tracers.go rename to eth/tracers/dir.go index 766278974c..650815350b 100644 --- a/eth/tracers/directory/tracers.go +++ b/eth/tracers/dir.go @@ -14,10 +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 directory provides functionality to lookup tracers by name. -// It also includes utility functions that are imported by the other -// tracing packages. -package directory +package tracers import ( "encoding/json" diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index a45ba2bf14..9a115c7235 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/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" @@ -139,7 +139,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { ) triedb.Close() - tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.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 := directory.DefaultDirectory.New(tracerName, new(directory.Context), nil) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.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) *directory.Tracer { - tr, err := directory.DefaultDirectory.New(name, nil, cfg) + mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer { + tr, err := tracers.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 *directory.Tracer + tracer *tracers.Tracer want string }{ { diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index afffb80bf8..e2de2c2081 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -16,7 +16,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/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" ) @@ -97,7 +97,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string defer triedb.Close() // Create the tracer, the EVM environment and run it - tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.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 9bad16bc4c..779ecb3d54 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -30,7 +30,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/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/tests" ) @@ -113,7 +113,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) } - tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/directory/util.go b/eth/tracers/internal/util.go similarity index 96% rename from eth/tracers/directory/util.go rename to eth/tracers/internal/util.go index f5a2cd80d3..18a372d192 100644 --- a/eth/tracers/directory/util.go +++ b/eth/tracers/internal/util.go @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package directory +package internal import ( "errors" @@ -62,6 +62,7 @@ func memoryCopy(m []byte, offset, size int64) (cpy []byte) { return } +// MemoryPtr returns a pointer to a slice of memory. func MemoryPtr(m []byte, offset, size int64) []byte { if size == 0 { return nil diff --git a/eth/tracers/directory/util_test.go b/eth/tracers/internal/util_test.go similarity index 99% rename from eth/tracers/directory/util_test.go rename to eth/tracers/internal/util_test.go index 731eeb832f..6a467314cc 100644 --- a/eth/tracers/directory/util_test.go +++ b/eth/tracers/internal/util_test.go @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package directory +package internal import ( "testing" diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 5c52ba1f11..7e4930f81d 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -25,7 +25,8 @@ import ( "github.com/dop251/goja" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/internal" "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" @@ -44,16 +45,16 @@ func init() { if err != nil { panic(err) } - type ctorFn = func(*directory.Context, json.RawMessage) (*directory.Tracer, error) + type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error) lookup := func(code string) ctorFn { - return func(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { + return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { return newJsTracer(code, ctx, cfg) } } for name, code := range assetTracers { - directory.DefaultDirectory.Register(name, lookup(code), true) + tracers.DefaultDirectory.Register(name, lookup(code), true) } - directory.DefaultDirectory.RegisterJSEval(newJsTracer) + tracers.DefaultDirectory.RegisterJSEval(newJsTracer) } // bigIntProgram is compiled once and the exported function mostly invoked to convert @@ -136,7 +137,7 @@ type jsTracer struct { // The methods `result` and `fault` are required to be present. // The methods `step`, `enter`, and `exit` are optional, but note that // `enter` and `exit` always go together. -func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { +func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { vm := goja.New() // By default field names are exported to JS as is, i.e. capitalized. vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) @@ -149,7 +150,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir t.setBuiltinFunctions() if ctx == nil { - ctx = new(directory.Context) + ctx = new(tracers.Context) } if ctx.BlockHash != (common.Hash{}) { blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes()) @@ -220,7 +221,7 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir t.frameResultValue = t.frameResult.setupObject() t.logValue = t.log.setupObject() - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, @@ -643,7 +644,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 := directory.GetMemoryCopyPadded(mo.memory, begin, end-begin) + slice, err := internal.GetMemoryCopyPadded(mo.memory, begin, end-begin) if err != nil { return nil, err } @@ -669,7 +670,7 @@ func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { if len(mo.memory) < int(addr)+32 || addr < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", len(mo.memory), addr, 32) } - return new(big.Int).SetBytes(directory.MemoryPtr(mo.memory, addr, 32)), nil + return new(big.Int).SetBytes(internal.MemoryPtr(mo.memory, addr, 32)), nil } func (mo *memoryObj) Length() int { @@ -709,7 +710,7 @@ func (s *stackObj) peek(idx int) (*big.Int, error) { if len(s.stack) <= idx || idx < 0 { return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack), idx) } - return directory.StackBack(s.stack, idx).ToBig(), nil + return internal.StackBack(s.stack, idx).ToBig(), nil } func (s *stackObj) Length() int { diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 895d6be684..1bcc3a446c 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/directory" + "github.com/ethereum/go-ethereum/eth/tracers" "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 *directory.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { +func runTrace(tracer *tracers.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.Hooks}) 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(directory.Context), nil); err == nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.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(directory.Context), nil); err != nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.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(directory.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(tracers.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(directory.Context), nil) + _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.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(directory.Context), cfg) + _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.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(directory.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(tracers.Context), cfg) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/directory/live/dir.go b/eth/tracers/live.go similarity index 57% rename from eth/tracers/directory/live/dir.go rename to eth/tracers/live.go index cedf81c35e..ffb2303af4 100644 --- a/eth/tracers/directory/live/dir.go +++ b/eth/tracers/live.go @@ -1,4 +1,4 @@ -package live +package tracers import ( "encoding/json" @@ -9,21 +9,21 @@ import ( type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error) -// Directory is the collection of tracers which can be used +// LiveDirectory is the collection of tracers which can be used // during normal block import operations. -var Directory = directory{elems: make(map[string]ctorFunc)} +var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)} -type directory struct { +type liveDirectory struct { elems map[string]ctorFunc } // Register registers a tracer constructor by name. -func (d *directory) Register(name string, f ctorFunc) { +func (d *liveDirectory) Register(name string, f ctorFunc) { d.elems[name] = f } // New instantiates a tracer by name. -func (d *directory) New(name string, config json.RawMessage) (*tracing.Hooks, error) { +func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) { if f, ok := d.elems[name]; ok { return f(config) } diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 2236674201..7433c28840 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -7,12 +7,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory/live" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/params" ) func init() { - live.Directory.Register("noop", newNoopTracer) + tracers.LiveDirectory.Register("noop", newNoopTracer) } // noop is a no-op live tracer. It's there to diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 9d6f4c8a19..ef1d471466 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -142,14 +141,6 @@ func (l *StructLogger) Hooks() *tracing.Hooks { } } -func (l *StructLogger) Tracer() *directory.Tracer { - return &directory.Tracer{ - Hooks: l.Hooks(), - GetResult: l.GetResult, - Stop: l.Stop, - } -} - // Reset clears the data held by the logger. func (l *StructLogger) Reset() { l.storage = make(map[common.Address]Storage) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 550b0115a3..6cb0e433d2 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -26,11 +26,11 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" ) func init() { - directory.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false) + tracers.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false) } // fourByteTracer searches for 4byte-identifiers, and collects them for post-processing. @@ -56,11 +56,11 @@ type fourByteTracer struct { // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tracer, error) { +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnEnter: t.OnEnter, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 83db1139f1..3b63506580 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -28,13 +28,13 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" ) //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go func init() { - directory.DefaultDirectory.Register("callTracer", newCallTracer, false) + tracers.DefaultDirectory.Register("callTracer", newCallTracer, false) } type callLog struct { @@ -120,12 +120,12 @@ type callTracerConfig struct { // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { +func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { t, err := newCallTracerObject(ctx, cfg) if err != nil { return nil, err } - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, @@ -138,7 +138,7 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac }, nil } -func newCallTracerObject(ctx *directory.Context, cfg json.RawMessage) (*callTracer, error) { +func newCallTracerObject(ctx *tracers.Context, cfg json.RawMessage) (*callTracer, 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 cd53736ed9..37be64310c 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -28,14 +28,14 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" ) //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() { - directory.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false) + tracers.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false) } var parityErrorMapping = map[string]string{ @@ -112,9 +112,9 @@ type flatCallResultMarshaling struct { type flatCallTracer struct { tracer *callTracer config flatCallTracerConfig - ctx *directory.Context // Holds tracer context data - reason error // Textual reason for the interruption - activePrecompiles []common.Address // Updated on tx start based on given rules + ctx *tracers.Context // Holds tracer context data + reason error // Textual reason for the interruption + activePrecompiles []common.Address // Updated on tx start based on given rules } type flatCallTracerConfig struct { @@ -123,7 +123,7 @@ type flatCallTracerConfig struct { } // newFlatCallTracer returns a new flatCallTracer. -func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { +func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config flatCallTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -139,7 +139,7 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. } ft := &flatCallTracer{tracer: t, ctx: ctx, config: config} - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: ft.OnTxStart, OnTxEnd: ft.OnTxEnd, @@ -236,7 +236,7 @@ func (t *flatCallTracer) isPrecompiled(addr common.Address) bool { return false } -func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *directory.Context) (output []flatCallFrame, err error) { +func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) { var frame *flatCallFrame switch input.Type { case vm.CREATE, vm.CREATE2: @@ -335,7 +335,7 @@ func newFlatSelfdestruct(input *callFrame) *flatCallFrame { } } -func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *directory.Context) { +func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *tracers.Context) { if ctx == nil { return } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 177082ffd9..c3b1d9f8ca 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -23,32 +23,32 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" ) func init() { - directory.DefaultDirectory.Register("muxTracer", newMuxTracer, false) + tracers.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 []*directory.Tracer + tracers []*tracers.Tracer } // newMuxTracer returns a new mux tracer. -func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { +func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config map[string]json.RawMessage if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { return nil, err } } - objects := make([]*directory.Tracer, 0, len(config)) + objects := make([]*tracers.Tracer, 0, len(config)) names := make([]string, 0, len(config)) for k, v := range config { - t, err := directory.DefaultDirectory.New(k, ctx, v) + t, err := tracers.DefaultDirectory.New(k, ctx, v) if err != nil { return nil, err } @@ -57,7 +57,7 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace } t := &muxTracer{names: names, tracers: objects} - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, diff --git a/eth/tracers/directory/noop.go b/eth/tracers/native/noop.go similarity index 64% rename from eth/tracers/directory/noop.go rename to eth/tracers/native/noop.go index d0edf12e21..f147134610 100644 --- a/eth/tracers/directory/noop.go +++ b/eth/tracers/native/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 directory +package native import ( "encoding/json" @@ -23,20 +23,21 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers" ) func init() { - DefaultDirectory.Register("noopTracer", newNoopTracer, false) + tracers.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 *Context, _ json.RawMessage) (*Tracer, error) { - t := &NoopTracer{} - return &Tracer{ +func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) { + t := &noopTracer{} + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, @@ -56,42 +57,42 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) { }, nil } -func (t *NoopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { +func (t *noopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { } -func (t *NoopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { +func (t *noopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) { } -func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} +func (t *noopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {} -func (t *NoopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +func (t *noopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } -func (t *NoopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { +func (t *noopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { } -func (*NoopTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { +func (*noopTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { } -func (*NoopTracer) OnTxEnd(receipt *types.Receipt, err error) {} +func (*noopTracer) OnTxEnd(receipt *types.Receipt, err error) {} -func (*NoopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { +func (*noopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { } -func (*NoopTracer) OnNonceChange(a common.Address, prev, new uint64) {} +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) 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) OnStorageChange(a common.Address, k, prev, new common.Hash) {} -func (*NoopTracer) OnLog(log *types.Log) {} +func (*noopTracer) OnLog(log *types.Log) {} // 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/native/prestate.go b/eth/tracers/native/prestate.go index e90a1729bb..e844e9ea48 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -28,14 +28,15 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/directory" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/internal" "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() { - directory.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) + tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) } type stateMap = map[common.Address]*account @@ -73,7 +74,7 @@ type prestateTracerConfig struct { DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications } -func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Tracer, error) { +func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) { var config prestateTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -87,7 +88,7 @@ func newPrestateTracer(ctx *directory.Context, cfg json.RawMessage) (*directory. created: make(map[common.Address]bool), deleted: make(map[common.Address]bool), } - return &directory.Tracer{ + return &tracers.Tracer{ Hooks: &tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, @@ -132,7 +133,7 @@ func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scop case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] - init, err := directory.GetMemoryCopyPadded(scope.MemoryData(), int64(offset.Uint64()), int64(size.Uint64())) + init, err := internal.GetMemoryCopyPadded(scope.MemoryData(), int64(offset.Uint64()), int64(size.Uint64())) if err != nil { log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size) return diff --git a/lib/ethapi/api.go b/lib/ethapi/api.go index be8e68d406..7fdd7c2070 100644 --- a/lib/ethapi/api.go +++ b/lib/ethapi/api.go @@ -454,7 +454,7 @@ func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *Transact return nil, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction() + tx := args.ToTransaction() return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) } @@ -497,7 +497,7 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti return nil, errors.New("nonce not specified") } // Before actually signing the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction() + tx := args.ToTransaction() if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -1081,14 +1081,14 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state vm.State defer cancel() // Get a new instance of the EVM. - msg, err := args.ToMessage(globalGasCap, header.BaseFee) - if err != nil { - return nil, err - } blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { blockOverrides.Apply(&blockCtx) } + if err := args.CallDefaults(globalGasCap, blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil { + return nil, err + } + msg := args.ToMessage(blockCtx.BaseFee) evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) // Wait for the context to be done and cancel the evm. Even if the @@ -1200,11 +1200,15 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr State: state, ErrorRatio: estimateGasErrorRatio, } - // Run the gas estimation andwrap any revertals into a custom return - call, err := args.ToMessage(gasCap, header.BaseFee) + + if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { + return 0, err + } + call := args.ToMessage(header.BaseFee) if err != nil { return 0, err } + // Run the gas estimation andwrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { if len(revert) > 0 { @@ -1537,7 +1541,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH statedb := db.Copy().(vm.StateDB) // Set the accesslist to the last al args.AccessList = &accessList - msg, err := args.ToMessage(b.RPCGasCap(), header.BaseFee) + msg := args.ToMessage(header.BaseFee) if err != nil { return nil, 0, nil, err } @@ -1548,7 +1552,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { - return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) + return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction().Hash(), err) } if tracer.Equal(prevTracer) { return accessList, res.UsedGas, res.Err, nil @@ -1816,7 +1820,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr return common.Hash{}, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction() + tx := args.ToTransaction() signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) if err != nil { @@ -1834,7 +1838,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr return nil, err } // Assemble the transaction and obtain rlp - tx := args.toTransaction() + tx := args.ToTransaction() data, err := tx.MarshalBinary() if err != nil { return nil, err @@ -1900,7 +1904,7 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction() + tx := args.ToTransaction() if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { return nil, err } @@ -1948,7 +1952,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if err := sendArgs.SetDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - matchTx := sendArgs.toTransaction() + matchTx := sendArgs.ToTransaction() // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. var price = matchTx.GasPrice() @@ -1978,7 +1982,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction()) + signedTx, err := s.sign(sendArgs.from(), sendArgs.ToTransaction()) if err != nil { return common.Hash{}, err } diff --git a/lib/ethapi/transaction_args.go b/lib/ethapi/transaction_args.go index c0a239d4f5..cdd8caa922 100644 --- a/lib/ethapi/transaction_args.go +++ b/lib/ethapi/transaction_args.go @@ -197,40 +197,68 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ return nil } +// CallDefaults sanitizes the transaction arguments, often filling in zero values, +// for the purpose of eth_call class of RPC methods. +func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error { + // Reject invalid combinations of pre- and post-1559 fee styles + if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { + return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + } + if args.ChainID == nil { + args.ChainID = (*hexutil.Big)(chainID) + } else { + if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 { + return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID) + } + } + if args.Gas == nil { + gas := globalGasCap + if gas == 0 { + gas = uint64(math.MaxUint64 / 2) + } + args.Gas = (*hexutil.Uint64)(&gas) + } else { + if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) { + log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap) + args.Gas = (*hexutil.Uint64)(&globalGasCap) + } + } + if args.Nonce == nil { + args.Nonce = new(hexutil.Uint64) + } + if args.Value == nil { + args.Value = new(hexutil.Big) + } + if baseFee == nil { + // If there's no basefee, then it must be a non-1559 execution + if args.GasPrice == nil { + args.GasPrice = new(hexutil.Big) + } + } else { + // A basefee is provided, necessitating 1559-type execution + if args.MaxFeePerGas == nil { + args.MaxFeePerGas = new(hexutil.Big) + } + if args.MaxPriorityFeePerGas == nil { + args.MaxPriorityFeePerGas = new(hexutil.Big) + } + } + + return nil +} + // ToMessage converts the transaction arguments to the Message type used by the // core evm. This method is used in calls and traces that do not require a real // live transaction. -func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) { - // Reject invalid combinations of pre- and post-1559 fee styles - if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { - return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") - } - // Set sender address or use zero address if none specified. - addr := args.from() - - // Set default gas & gas price if none were set - gas := globalGasCap - if gas == 0 { - gas = uint64(math.MaxUint64 / 2) - } - if args.Gas != nil { - gas = uint64(*args.Gas) - } - if globalGasCap != 0 && globalGasCap < gas { - log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) - gas = globalGasCap - } +// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called. +func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { var ( gasPrice *big.Int gasFeeCap *big.Int gasTipCap *big.Int ) if baseFee == nil { - // If there's no basefee, then it must be a non-1559 execution - gasPrice = new(big.Int) - if args.GasPrice != nil { - gasPrice = args.GasPrice.ToInt() - } + gasPrice = args.GasPrice.ToInt() gasFeeCap, gasTipCap = gasPrice, gasPrice } else { // A basefee is provided, necessitating 1559-type execution @@ -240,14 +268,8 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (* gasFeeCap, gasTipCap = gasPrice, gasPrice } else { // User specified 1559 gas fields (or none), use those - gasFeeCap = new(big.Int) - if args.MaxFeePerGas != nil { - gasFeeCap = args.MaxFeePerGas.ToInt() - } - gasTipCap = new(big.Int) - if args.MaxPriorityFeePerGas != nil { - gasTipCap = args.MaxPriorityFeePerGas.ToInt() - } + gasFeeCap = args.MaxFeePerGas.ToInt() + gasTipCap = args.MaxPriorityFeePerGas.ToInt() // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes gasPrice = new(big.Int) if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { @@ -255,33 +277,27 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (* } } } - value := new(big.Int) - if args.Value != nil { - value = args.Value.ToInt() - } - data := args.data() var accessList types.AccessList if args.AccessList != nil { accessList = *args.AccessList } - msg := &core.Message{ - From: addr, + return &core.Message{ + From: args.from(), To: args.To, - Value: value, - GasLimit: gas, + Value: (*big.Int)(args.Value), + GasLimit: uint64(*args.Gas), GasPrice: gasPrice, GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, - Data: data, + Data: args.data(), AccessList: accessList, SkipAccountChecks: true, } - return msg, nil } -// toTransaction converts the arguments to a transaction. -// This assumes that SetDefaults has been called. -func (args *TransactionArgs) toTransaction() *types.Transaction { +// ToTransaction converts the arguments to a transaction. +// This assumes that setDefaults has been called. +func (args *TransactionArgs) ToTransaction() *types.Transaction { var data types.TxData switch { case args.MaxFeePerGas != nil: @@ -323,9 +339,3 @@ func (args *TransactionArgs) toTransaction() *types.Transaction { } return types.NewTx(data) } - -// ToTransaction converts the arguments to a transaction. -// This assumes that SetDefaults has been called. -func (args *TransactionArgs) ToTransaction() *types.Transaction { - return args.toTransaction() -}