From 856d7245f2bb2b5341b2d29e562a783b1ac2d835 Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Thu, 21 Sep 2023 07:39:29 -0400 Subject: [PATCH] refactor: Rename blocknative.txnOpCodeTracer -> blocknative.tracer. --- core/state_processor.go | 2 +- eth/filters/trace_api.go | 2 +- .../{txnopcodetracer_readme.md => README.md} | 2 +- eth/tracers/blocknative/blocknative.go | 4 + .../blocknative/decoder/calldata_test.go | 7 +- eth/tracers/blocknative/tracer.go | 261 ++++++++++++++++++ eth/tracers/blocknative/txnOpCodeTracer.go | 260 ----------------- ...CodeTracer_test.go => blocknative_test.go} | 53 ++-- .../block_random.json | 0 .../create.json | 0 .../deep_calls.json | 0 .../delegatecall.json | 0 .../inner_create_oog_outer_throw.json | 0 .../inner_instafail.json | 0 .../inner_revert_reason.json | 0 .../inner_throw_outer_revert.json | 0 .../logs.json | 0 .../oog.json | 0 .../revert.json | 0 .../revert_reason.json | 0 .../selfdestruct.json | 0 .../simple.json | 0 .../simple_onlytop.json | 0 .../throw.json | 0 .../with_decoding}/delegatecall.json | 0 .../with_decoding}/erc20_transfer.json | 0 .../with_decoding}/erc20_transfer2.json | 0 .../with_decoding}/inner_create.json | 0 .../multi_contracts_transfers.json | 0 eth/tracers/register_blocknative.go | 6 +- 30 files changed, 304 insertions(+), 293 deletions(-) rename eth/tracers/blocknative/{txnopcodetracer_readme.md => README.md} (99%) create mode 100644 eth/tracers/blocknative/tracer.go delete mode 100644 eth/tracers/blocknative/txnOpCodeTracer.go rename eth/tracers/internal/tracetest/{txnOpCodeTracer_test.go => blocknative_test.go} (84%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/block_random.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/create.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/deep_calls.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/delegatecall.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/inner_create_oog_outer_throw.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/inner_instafail.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/inner_revert_reason.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/inner_throw_outer_revert.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/logs.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/oog.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/revert.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/revert_reason.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/selfdestruct.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/simple.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/simple_onlytop.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer => blocknative}/throw.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer_with_netbalchanges => blocknative/with_decoding}/delegatecall.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer_with_netbalchanges => blocknative/with_decoding}/erc20_transfer.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer_with_netbalchanges => blocknative/with_decoding}/erc20_transfer2.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer_with_netbalchanges => blocknative/with_decoding}/inner_create.json (100%) rename eth/tracers/internal/tracetest/testdata/{txnOpCode_tracer_with_netbalchanges => blocknative/with_decoding}/multi_contracts_transfers.json (100%) diff --git a/core/state_processor.go b/core/state_processor.go index 17555f62d7ac..bf3707f828d6 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -250,7 +250,7 @@ func ApplyTransactionWithResult(config *params.ChainConfig, bc ChainContext, aut func ApplyUnsignedTransactionWithResult(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, msg *Message, usedGas *uint64, cfg vm.Config) (*types.Receipt, *ExecutionResult, interface{}, error) { // Create a blocknative tracer to get execution traces. - tracer, err := blocknative.NewTxnOpCodeTracer(nil) + tracer, err := blocknative.NewTracer(nil) if err != nil { return nil, nil, nil, err } diff --git a/eth/filters/trace_api.go b/eth/filters/trace_api.go index 898bcb4cbc6a..f5e7bb750cb4 100644 --- a/eth/filters/trace_api.go +++ b/eth/filters/trace_api.go @@ -266,7 +266,7 @@ func traceTx(message *core.Message, txCtx *tracers.Context, vmctx vm.BlockContex txTraceLocksMu.Unlock() // No trace in cache or in-progress so create a new one. - tracer, err := blocknative.NewTxnOpCodeTracerWithOpts(tracerOpts) + tracer, err := blocknative.NewTracerWithOpts(tracerOpts) if err != nil { return nil, err } diff --git a/eth/tracers/blocknative/txnopcodetracer_readme.md b/eth/tracers/blocknative/README.md similarity index 99% rename from eth/tracers/blocknative/txnopcodetracer_readme.md rename to eth/tracers/blocknative/README.md index 8b6a6114083e..6f926f824f5f 100644 --- a/eth/tracers/blocknative/txnopcodetracer_readme.md +++ b/eth/tracers/blocknative/README.md @@ -1,4 +1,4 @@ -# txnOpCodeTracer +# Blocknative Tracer ## Options diff --git a/eth/tracers/blocknative/blocknative.go b/eth/tracers/blocknative/blocknative.go index 5f3abff0dd63..fd1517a8672d 100644 --- a/eth/tracers/blocknative/blocknative.go +++ b/eth/tracers/blocknative/blocknative.go @@ -2,11 +2,15 @@ package blocknative import ( "encoding/json" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/blocknative/decoder" ) +// Tracer is the interface for the Blocknative tracer. +// It implements the standard EVMLogger tracer interface, but also exposes the +// resulting Trace object directly. type Tracer interface { vm.EVMLogger GetTrace() (*Trace, error) diff --git a/eth/tracers/blocknative/decoder/calldata_test.go b/eth/tracers/blocknative/decoder/calldata_test.go index d4599c84b26d..baa30881beb1 100644 --- a/eth/tracers/blocknative/decoder/calldata_test.go +++ b/eth/tracers/blocknative/decoder/calldata_test.go @@ -8,8 +8,9 @@ import ( "path/filepath" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" ) type decodeCallDataTest struct { @@ -92,8 +93,8 @@ type testCall struct { func loadTestVectors() ([]*testVector, error) { testVectorDirs := []string{ - "../../internal/tracetest/testdata/txnOpCode_tracer", - "../../internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges", + "../../internal/tracetest/testdata/blocknative", + "../../internal/tracetest/testdata/blocknative/with_decoding", } var testVectors []*testVector diff --git a/eth/tracers/blocknative/tracer.go b/eth/tracers/blocknative/tracer.go new file mode 100644 index 000000000000..c407548b309d --- /dev/null +++ b/eth/tracers/blocknative/tracer.go @@ -0,0 +1,261 @@ +package blocknative + +import ( + "encoding/json" + "math/big" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/blocknative/decoder" +) + +var ( + // decoderCache is a global cache for the decoder, shared across traces. + decoderCache = decoder.NewCaches() +) + +// tracer is Blocknative's transaction tracer. It decodes messages into +// call-frames and decodes them into higher-level abstractions. It returns all +// the information required to reconstruct a transaction's execution while +// decoding inputs, outputs, logs, and environmental effects. +type tracer struct { + opts TracerOpts + evm *vm.EVM + decoder *decoder.Decoder + + trace Trace + startTime time.Time + callStack []CallFrame + + interrupt *atomic.Bool + interruptReason error +} + +// NewTracer returns a new tracer with the given json decoded as TracerOpts. +// This allows us to easily construct a tracer from the standard tracer API +// which receives options as json. +func NewTracer(cfg json.RawMessage) (Tracer, error) { + var opts TracerOpts + if cfg != nil { + if err := json.Unmarshal(cfg, &opts); err != nil { + return nil, err + } + } + return NewTracerWithOpts(opts) +} + +// NewTracerWithOpts is the primary constructor for the tracer. +func NewTracerWithOpts(opts TracerOpts) (Tracer, error) { + opts.Decode = opts.Decode || opts.BalanceChanges + + var t = tracer{ + opts: opts, + callStack: make([]CallFrame, 1, 4), + interrupt: new(atomic.Bool), + } + + if !opts.DisableBlockContext { + t.trace.BlockContext = &BlockContext{} + } + + return &t, nil + +} + +// SetStateRoot implements core.stateRootSetter and stores the given root in the +// trace's BlockContext. It's called between the constructor and the first +// call-frame. +func (t *tracer) SetStateRoot(root common.Hash) { + if t.trace.BlockContext != nil { + t.trace.BlockContext.StateRoot = bytesToHex(root.Bytes()) + } +} + +// CaptureStart is called before the top-level call starts. +// This is also where we get the EVM instance, so we initialize the things that +// need it here instead of the constructor. +func (t *tracer) CaptureStart(evm *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + t.startTime = time.Now() + t.evm = evm + + if t.opts.Decode { + t.decoder = decoder.New(decoderCache, decoderEVM{evm}) + } + + if !t.opts.DisableBlockContext { + t.trace.BlockContext.Number = evm.Context.BlockNumber.Uint64() + t.trace.BlockContext.BaseFee = evm.Context.BaseFee.Uint64() + t.trace.BlockContext.Time = evm.Context.Time + t.trace.BlockContext.Coinbase = addrToHex(evm.Context.Coinbase) + t.trace.BlockContext.GasLimit = evm.Context.GasLimit + if evm.Context.Random != nil { + t.trace.BlockContext.Random = bytesToHex(evm.Context.Random.Bytes()) + } + } + + // Create a call-frame for the top-level call. + t.callStack[0] = CallFrame{ + Type: "CALL", + From: addrToHex(from), + To: addrToHex(to), + Input: bytesToHex(input), + Gas: uintToHex(gas), + Value: bigToHex(value), + } + if create { + t.callStack[0].Type = "CREATE" + } + + // Try adding decode information, but don't fail if we can't. + if t.opts.Decode { + if decoded, err := t.decoder.DecodeCallFrame(from, to, value, input); err == nil { + t.callStack[0].Decoded = decoded + } + } +} + +// CaptureEnd is called after the top-level call finishes to finalize tracing. +func (t *tracer) CaptureEnd(output []byte, gasUsed uint64, err error) { + finalizeCallFrame(&t.callStack[0], output, gasUsed, err) + + // If the user wants the logs, grab them from the state + if t.opts.Logs { + for _, stateLog := range t.evm.StateDB.Logs() { + t.trace.Logs = append(t.trace.Logs, CallLog{ + Address: stateLog.Address, + Data: bytesToHex(stateLog.Data), + Topics: stateLog.Topics, + }) + } + } + + // Add gas payments to balance changes + if t.opts.Decode { + t.decoder.CaptureGas(t.evm.TxContext.Origin, t.evm.Context.Coinbase, gasUsed, t.evm.TxContext.GasPrice, t.evm.Context.BaseFee) + } + + // Add total time duration for this trace request + t.trace.Time = time.Now().Sub(t.startTime).Nanoseconds() +} + +// CaptureEnter is called before any new sub-call starts. +// (via call, create or selfdestruct). +func (t *tracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.interrupt.Load() { + return + } + + // Create CallFrame, decode it, and all it to the end of the callstack. + call := CallFrame{ + Type: typ.String(), + From: addrToHex(from), + To: addrToHex(to), + Input: bytesToHex(input), + Gas: uintToHex(gas), + Value: bigToHex(value), + } + if t.opts.Decode { + if decoded, err := t.decoder.DecodeCallFrame(from, to, value, input); err == nil { + call.Decoded = decoded + } + } + + t.callStack = append(t.callStack, call) +} + +// CaptureExit is called after any sub call ends. +func (t *tracer) CaptureExit(output []byte, gasUsed uint64, err error) { + // Skip if we have no call-frames. + size := len(t.callStack) + if size == 0 { + return + } + + // We have a call-frame, so finalize it. + finalizeCallFrame(&t.callStack[size-1], output, gasUsed, err) + + // We have a parent call-frame, so nest this one under it. + if size <= 1 { + return + } + end := size - 1 + call := t.callStack[end] + t.callStack = t.callStack[:end] + end -= 1 + t.callStack[end].Calls = append(t.callStack[end].Calls, call) +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *tracer) Stop(err error) { + t.interrupt.Store(true) + t.interruptReason = err + t.evm.Cancel() +} + +// GetTrace returns a Trace from the current state. +func (t *tracer) GetTrace() (*Trace, error) { + if t.interrupt.Load() { + return nil, t.interruptReason + } + + t.trace.CallFrame = t.callStack[0] + + if t.opts.Decode { + t.trace.BalanceChanges = t.decoder.GetBalanceChanges() + } + + return &t.trace, nil +} + +// GetResult returns a JSON encoded Trace from the current state. +func (t *tracer) GetResult() (json.RawMessage, error) { + trace, err := t.GetTrace() + if err != nil { + return nil, err + } + + return json.Marshal(trace) +} + +func finalizeCallFrame(call *CallFrame, output []byte, gasUsed uint64, err error) { + call.GasUsed = uintToHex(gasUsed) + + // If there was an error then try decoding it and stop. + if err != nil { + call.Error = err.Error() + if err.Error() == "execution reverted" && len(output) > 0 { + call.Output = bytesToHex(output) + revertReason, _ := abi.UnpackRevert(output) + call.ErrorReason = revertReason + } + + if call.Type == "CREATE" || call.Type == "CREATE2" { + call.To = "" + } + return + } + + // The call was successful so decode the output. + call.Output = bytesToHex(output) +} + +// +// Unused interface methods. +// + +// CaptureState implements the tracer interface, but is unused. +func (t *tracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, _ int, _ error) { +} + +// CaptureFault implements the tracer interface, but is unused. +func (t *tracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) { +} + +// CaptureTxStart implements the tracer interface, but is unused. +func (t *tracer) CaptureTxStart(_ uint64) {} + +// CaptureTxEnd implements the tracer interface, but is unused. +func (t *tracer) CaptureTxEnd(_ uint64) {} diff --git a/eth/tracers/blocknative/txnOpCodeTracer.go b/eth/tracers/blocknative/txnOpCodeTracer.go deleted file mode 100644 index eca7f8622805..000000000000 --- a/eth/tracers/blocknative/txnOpCodeTracer.go +++ /dev/null @@ -1,260 +0,0 @@ -package blocknative - -import ( - "encoding/json" - "math/big" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/blocknative/decoder" - "github.com/ethereum/go-ethereum/log" -) - -var ( - decoderCache = decoder.NewCaches() -) - -// txnOpCodeTracer is a go implementation of the Tracer interface which -// only returns a restricted trace of a transaction consisting of transaction -// op codes and relevant gas data. -// This is intended for Blocknative usage. -type txnOpCodeTracer struct { - opts TracerOpts - env *vm.EVM - decoder *decoder.Decoder - - trace Trace - startTime time.Time - callStack []CallFrame - interrupt uint32 - reason error -} - -// NewTxnOpCodeTracer returns a new txnOpCodeTracer tracer with the given -// options applied. -func NewTxnOpCodeTracer(cfg json.RawMessage) (Tracer, error) { - var opts TracerOpts - - if cfg != nil { - if err := json.Unmarshal(cfg, &opts); err != nil { - return nil, err - } - } - - return NewTxnOpCodeTracerWithOpts(opts) -} - -func NewTxnOpCodeTracerWithOpts(opts TracerOpts) (Tracer, error) { - opts.Decode = opts.Decode || opts.BalanceChanges - - var t = txnOpCodeTracer{ - opts: opts, - callStack: make([]CallFrame, 1), - } - - if !t.opts.DisableBlockContext { - t.trace.BlockContext = &BlockContext{} - } - - return &t, nil - -} - -// GetTrace returns the resulting Trace object. -func (t *txnOpCodeTracer) GetTrace() (*Trace, error) { - if t.opts.Decode { - t.trace.BalanceChanges = t.decoder.GetBalanceChanges() - } - - t.trace.CallFrame = t.callStack[0] - return &t.trace, nil -} - -// GetResult returns an empty json object. -func (t *txnOpCodeTracer) GetResult() (json.RawMessage, error) { - trace, err := t.GetTrace() - if err != nil { - return nil, err - } - - res, err := json.Marshal(trace) - if err != nil { - return nil, err - } - return res, t.reason -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *txnOpCodeTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.startTime = time.Now() - t.env = env - - if t.opts.Decode { - t.decoder = decoder.New(decoderCache, decoderEVM{env}) - } - - if !t.opts.DisableBlockContext { - // Blocks only contain `Random` post-merge, but we still have pre-merge tests. - random := "" - if env.Context.Random != nil { - random = bytesToHex(env.Context.Random.Bytes()) - } - - t.trace.BlockContext.Number = env.Context.BlockNumber.Uint64() - t.trace.BlockContext.BaseFee = env.Context.BaseFee.Uint64() - t.trace.BlockContext.Time = env.Context.Time - t.trace.BlockContext.Coinbase = addrToHex(env.Context.Coinbase) - t.trace.BlockContext.GasLimit = env.Context.GasLimit - t.trace.BlockContext.Random = random - } - - // Create a call-frame for the top level call. - t.callStack[0] = CallFrame{ - Type: "CALL", - From: addrToHex(from), - To: addrToHex(to), - Input: bytesToHex(input), - Gas: uintToHex(gas), - Value: bigToHex(value), - } - if create { - t.callStack[0].Type = "CREATE" - } - - // Try adding decode information but don't fail if we can't. - if t.opts.Decode { - if decoded, err := t.decoder.DecodeCallFrame(from, to, value, input); err == nil { - t.callStack[0].Decoded = decoded - } - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *txnOpCodeTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - finalizeCallFrame(&t.callStack[0], output, gasUsed, err) - - // If the user wants the logs, grab them from the state - if t.opts.Logs { - for _, stateLog := range t.env.StateDB.Logs() { - t.trace.Logs = append(t.trace.Logs, CallLog{ - Address: stateLog.Address, - Data: bytesToHex(stateLog.Data), - Topics: stateLog.Topics, - }) - } - } - - // Add gas payments to balance changes - if t.opts.Decode { - t.decoder.CaptureGas(t.env.TxContext.Origin, t.env.Context.Coinbase, gasUsed, t.env.TxContext.GasPrice, t.env.Context.BaseFee) - } - - // Add total time duration for this trace request - t.trace.Time = time.Now().Sub(t.startTime).Nanoseconds() -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *txnOpCodeTracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, depth int, _ error) { - defer func() { - if r := recover(); r != nil { - t.callStack[depth].Error = "internal failure" - log.Warn("Panic during trace. Recovered.", "err", r) - } - }() -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *txnOpCodeTracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) { -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *txnOpCodeTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { - t.env.Cancel() - return - } - - // Create CallFrame, decode it, and all it to the end of the callstack. - call := CallFrame{ - Type: typ.String(), - From: addrToHex(from), - To: addrToHex(to), - Input: bytesToHex(input), - Gas: uintToHex(gas), - Value: bigToHex(value), - } - if t.opts.Decode { - if decoded, err := t.decoder.DecodeCallFrame(from, to, value, input); err == nil { - call.Decoded = decoded - } - } - - t.callStack = append(t.callStack, call) -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't execute any code. -func (t *txnOpCodeTracer) CaptureExit(output []byte, gasUsed uint64, err error) { - // Skip if we have no call frames. - size := len(t.callStack) - if size == 0 { - return - } - - // We have a call frame, so finalize it. - finalizeCallFrame(&t.callStack[size-1], output, gasUsed, err) - - // If we have a parent call frame nest this one into it. - if size <= 1 { - return - } - end := size - 1 - call := t.callStack[end] - t.callStack = t.callStack[:end] - end -= 1 - t.callStack[end].Calls = append(t.callStack[end].Calls, call) -} - -// CaptureTxStart fulfils the standard Tracer interface, but we don't use it. -func (t *txnOpCodeTracer) CaptureTxStart(_ uint64) {} - -// CaptureTxEnd fulfils the standard Tracer interface, but we don't use it. -func (t *txnOpCodeTracer) CaptureTxEnd(_ uint64) {} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *txnOpCodeTracer) Stop(err error) { - t.reason = err - atomic.StoreUint32(&t.interrupt, 1) -} - -// SetStateRoot implements core.stateRootSetter and stores the given root in the trace's BlockContext. -func (t *txnOpCodeTracer) SetStateRoot(root common.Hash) { - if !t.opts.DisableBlockContext { - t.trace.BlockContext.StateRoot = bytesToHex(root.Bytes()) - } -} - -func finalizeCallFrame(call *CallFrame, output []byte, gasUsed uint64, err error) { - call.GasUsed = uintToHex(gasUsed) - - // If there was an error then try decoding it and stop. - if err != nil { - call.Error = err.Error() - if err.Error() == "execution reverted" && len(output) > 0 { - call.Output = bytesToHex(output) - revertReason, _ := abi.UnpackRevert(output) - call.ErrorReason = revertReason - } - - if call.Type == "CREATE" || call.Type == "CREATE2" { - call.To = "" - } - return - } - - // The call was successful so decode the output. - call.Output = bytesToHex(output) -} diff --git a/eth/tracers/internal/tracetest/txnOpCodeTracer_test.go b/eth/tracers/internal/tracetest/blocknative_test.go similarity index 84% rename from eth/tracers/internal/tracetest/txnOpCodeTracer_test.go rename to eth/tracers/internal/tracetest/blocknative_test.go index 73ec2b770b98..c40e242d0d6a 100644 --- a/eth/tracers/internal/tracetest/txnOpCodeTracer_test.go +++ b/eth/tracers/internal/tracetest/blocknative_test.go @@ -2,6 +2,7 @@ package tracetest import ( "encoding/json" + "fmt" "math/big" "os" "path/filepath" @@ -22,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/tests" ) -type txnOpCodeTracerTest struct { +type blocknativeTracerTest struct { Genesis *core.Genesis `json:"genesis"` Context *callContext `json:"context"` Input string `json:"input"` @@ -41,21 +42,21 @@ type txnOpCodeTracerTest struct { txContext vm.TxContext } -func TestTxnOpCodeTracer(t *testing.T) { +func TestBlocknativeTracer(t *testing.T) { log.Root().SetHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(true))) - testTxnOpCodeTracer("txnOpCode_tracer", t) - testTxnOpCodeTracer("txnOpCode_tracer_with_netbalchanges", t) + testBlocknativeTracer("blocknative", t) + testBlocknativeTracer("blocknative/with_decoding", t) } -func BenchmarkTxnOpCodeTracerWithoutDecoding(b *testing.B) { - benchmarkTxnOpCodeTracer(b, false, "txnOpCode_tracer", "txnOpCode_tracer_with_netbalchanges") +func BenchmarkBlocknativeTracerWithoutDecoding(b *testing.B) { + benchmarkBlocknativeTracer(b, false, "blocknative", "blocknative/with_decoding") } -func BenchmarkTxnOpCodeTracerWithDecoding(b *testing.B) { - benchmarkTxnOpCodeTracer(b, true, "txnOpCode_tracer", "txnOpCode_tracer_with_netbalchanges") +func BenchmarkBlocknativeTracerWithDecoding(b *testing.B) { + benchmarkBlocknativeTracer(b, true, "blocknative", "blocknative/with_decoding") } -func benchmarkTxnOpCodeTracer(b *testing.B, decode bool, dirPaths ...string) { - testCases := []*txnOpCodeTracerTest{} +func benchmarkBlocknativeTracer(b *testing.B, decode bool, dirPaths ...string) { + testCases := []*blocknativeTracerTest{} for _, dirPath := range dirPaths { files, err := os.ReadDir(filepath.Join("testdata", dirPath)) @@ -65,7 +66,7 @@ func benchmarkTxnOpCodeTracer(b *testing.B, decode bool, dirPaths ...string) { for _, file := range files { var ( - test = new(txnOpCodeTracerTest) + test = new(blocknativeTracerTest) tx = new(types.Transaction) ) if blob, err := os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil { @@ -115,7 +116,7 @@ func benchmarkTxnOpCodeTracer(b *testing.B, decode bool, dirPaths ...string) { _, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) opts := blocknative.TracerOpts{Decode: decode} - tracer, err := blocknative.NewTxnOpCodeTracerWithOpts(opts) + tracer, err := blocknative.NewTracerWithOpts(opts) if err != nil { b.Fatal(err) } @@ -135,7 +136,7 @@ func benchmarkTxnOpCodeTracer(b *testing.B, decode bool, dirPaths ...string) { } } -func testTxnOpCodeTracer(dirPath string, t *testing.T) { +func testBlocknativeTracer(dirPath string, t *testing.T) { testsCases, err := loadTestTxs(dirPath) if err != nil { t.Fatal(err) @@ -148,20 +149,20 @@ func testTxnOpCodeTracer(dirPath string, t *testing.T) { } } -func loadTestTxs(dirPath string) ([]*txnOpCodeTracerTest, error) { +func loadTestTxs(dirPath string) ([]*blocknativeTracerTest, error) { files, err := os.ReadDir(filepath.Join("testdata", dirPath)) if err != nil { return nil, err } - testCases := make([]*txnOpCodeTracerTest, 0, len(files)) + testCases := make([]*blocknativeTracerTest, 0, len(files)) for _, file := range files { if !strings.HasSuffix(file.Name(), ".json") { continue } var ( - test = new(txnOpCodeTracerTest) + test = new(blocknativeTracerTest) tx = new(types.Transaction) ) if blob, err := os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil { @@ -199,7 +200,7 @@ func loadTestTxs(dirPath string) ([]*txnOpCodeTracerTest, error) { } _, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) ) - tracer, err := blocknative.NewTxnOpCodeTracer(test.TracerConfig) + tracer, err := blocknative.NewTracer(test.TracerConfig) if err != nil { return nil, err } @@ -220,7 +221,7 @@ func loadTestTxs(dirPath string) ([]*txnOpCodeTracerTest, error) { return testCases, nil } -func executeTestCase(test *txnOpCodeTracerTest, t testing.TB, checkResult bool) { +func executeTestCase(test *blocknativeTracerTest, t testing.TB, checkResult bool) { st := core.NewStateTransition(test.evm, test.msg, new(core.GasPool).AddGas(test.tx.Gas())) if _, err := st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) @@ -237,15 +238,15 @@ func executeTestCase(test *txnOpCodeTracerTest, t testing.TB, checkResult bool) if checkResult && !tracesEqual(ret, test.Result) { // Below are prints to show differences if we fail, can always just check against the specific test json files too! - //fmt.Println("Trace return: ") - //x, _ := json.Marshal(ret) - ////x, _ := json.MarshalIndent(ret, "", " ") - //y, _ := json.Marshal(test.Result) - //fmt.Println(string(x)) - //fmt.Println("test.Result") - //fmt.Println(string(y)) + fmt.Println("Trace return: ") + x, _ := json.Marshal(ret) + // //x, _ := json.MarshalIndent(ret, "", " ") + y, _ := json.Marshal(test.Result) + fmt.Println(string(x)) + fmt.Println("test.Result") + fmt.Println(string(y)) t.Fatal("traces mismatch") - //t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) + // t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) } } diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/block_random.json b/eth/tracers/internal/tracetest/testdata/blocknative/block_random.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/block_random.json rename to eth/tracers/internal/tracetest/testdata/blocknative/block_random.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/create.json b/eth/tracers/internal/tracetest/testdata/blocknative/create.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/create.json rename to eth/tracers/internal/tracetest/testdata/blocknative/create.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/blocknative/deep_calls.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/deep_calls.json rename to eth/tracers/internal/tracetest/testdata/blocknative/deep_calls.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/blocknative/delegatecall.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/delegatecall.json rename to eth/tracers/internal/tracetest/testdata/blocknative/delegatecall.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/blocknative/inner_create_oog_outer_throw.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_create_oog_outer_throw.json rename to eth/tracers/internal/tracetest/testdata/blocknative/inner_create_oog_outer_throw.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/blocknative/inner_instafail.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_instafail.json rename to eth/tracers/internal/tracetest/testdata/blocknative/inner_instafail.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/blocknative/inner_revert_reason.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_revert_reason.json rename to eth/tracers/internal/tracetest/testdata/blocknative/inner_revert_reason.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/blocknative/inner_throw_outer_revert.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/inner_throw_outer_revert.json rename to eth/tracers/internal/tracetest/testdata/blocknative/inner_throw_outer_revert.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/logs.json b/eth/tracers/internal/tracetest/testdata/blocknative/logs.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/logs.json rename to eth/tracers/internal/tracetest/testdata/blocknative/logs.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/oog.json b/eth/tracers/internal/tracetest/testdata/blocknative/oog.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/oog.json rename to eth/tracers/internal/tracetest/testdata/blocknative/oog.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/revert.json b/eth/tracers/internal/tracetest/testdata/blocknative/revert.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/revert.json rename to eth/tracers/internal/tracetest/testdata/blocknative/revert.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/blocknative/revert_reason.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/revert_reason.json rename to eth/tracers/internal/tracetest/testdata/blocknative/revert_reason.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/blocknative/selfdestruct.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/selfdestruct.json rename to eth/tracers/internal/tracetest/testdata/blocknative/selfdestruct.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/blocknative/simple.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/simple.json rename to eth/tracers/internal/tracetest/testdata/blocknative/simple.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/blocknative/simple_onlytop.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/simple_onlytop.json rename to eth/tracers/internal/tracetest/testdata/blocknative/simple_onlytop.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/throw.json b/eth/tracers/internal/tracetest/testdata/blocknative/throw.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer/throw.json rename to eth/tracers/internal/tracetest/testdata/blocknative/throw.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/delegatecall.json b/eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/delegatecall.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/delegatecall.json rename to eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/delegatecall.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/erc20_transfer.json b/eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/erc20_transfer.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/erc20_transfer.json rename to eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/erc20_transfer.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/erc20_transfer2.json b/eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/erc20_transfer2.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/erc20_transfer2.json rename to eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/erc20_transfer2.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/inner_create.json b/eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/inner_create.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/inner_create.json rename to eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/inner_create.json diff --git a/eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/multi_contracts_transfers.json b/eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/multi_contracts_transfers.json similarity index 100% rename from eth/tracers/internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges/multi_contracts_transfers.json rename to eth/tracers/internal/tracetest/testdata/blocknative/with_decoding/multi_contracts_transfers.json diff --git a/eth/tracers/register_blocknative.go b/eth/tracers/register_blocknative.go index f6b67c913619..900ea9872ca2 100644 --- a/eth/tracers/register_blocknative.go +++ b/eth/tracers/register_blocknative.go @@ -2,6 +2,7 @@ package tracers import ( "encoding/json" + "github.com/ethereum/go-ethereum/eth/tracers/blocknative" ) @@ -11,9 +12,12 @@ import ( // in turn allows us to use the blocknative tracers from inside the geth/core // package without causing circular dependency issues. func init() { + DefaultDirectory.Register("blocknative", blocknativeTracerCtor, false) + + // Also register the tracer under the old name for backwards compatibility. DefaultDirectory.Register("txnOpCodeTracer", blocknativeTracerCtor, false) } func blocknativeTracerCtor(_ *Context, cfg json.RawMessage) (Tracer, error) { - return blocknative.NewTxnOpCodeTracer(cfg) + return blocknative.NewTracer(cfg) }