From fbc3318a024cb062c5a2f1007e20fec22c1465f4 Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Fri, 8 Mar 2024 13:31:58 -0500 Subject: [PATCH] feat: add new failed deposit trace call frame Natively supports the trace call where a deposit fails. Frame will appear empty with a "failed_deposit" type and the proper amount of gas used. Clients can now use and understand the result. --- core/state_transition.go | 6 +- .../internal/tracetest/flat_calltrace_test.go | 3 +- .../testdata/call_tracer/failed_deposit.json | 47 +++++++++++++++ .../call_tracer_flat/failed_deposit.json | 59 +++++++++++++++++++ eth/tracers/native/call.go | 4 ++ eth/tracers/native/call_flat.go | 6 ++ 6 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/failed_deposit.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/failed_deposit.json diff --git a/core/state_transition.go b/core/state_transition.go index 51c4b36cca..8de452bada 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -438,7 +438,11 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) { if tracer := st.evm.Config.Tracer; tracer != nil { tracer.CaptureTxStart(st.initialGas) defer func() { - tracer.CaptureTxEnd(st.gasRemaining) + if st.msg.IsDepositTx { + tracer.CaptureTxEnd(0) + } else { + tracer.CaptureTxEnd(st.gasRemaining) + } }() } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 423167b13c..9244628482 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -16,7 +16,6 @@ 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/rlp" "github.com/ethereum/go-ethereum/tests" // Force-load the native, to trigger registration @@ -82,7 +81,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string } // Configure a blockchain with the given prestate tx := new(types.Transaction) - if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil { return fmt.Errorf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/failed_deposit.json b/eth/tracers/internal/tracetest/testdata/call_tracer/failed_deposit.json new file mode 100644 index 0000000000..2c43cdae0f --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/failed_deposit.json @@ -0,0 +1,47 @@ +{ + "context": { + "difficulty": "3699098917", + "gasLimit": "5258985", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "number": "2294631", + "timestamp": "1513675366" + }, + "genesis": { + "alloc": {}, + "config": { + "chainId": 3, + "daoForkSupport": true, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "ethash": {}, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0 + }, + "difficulty": "3699098917", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "5263953", + "hash": "0x03a0f62a8106793dafcfae7b75fd2654322062d585a19cea568314d7205790dc", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x15482cc64b7c00a947f5bf015dfc010db1a6a668c74df61974d6a7848c174408", + "nonce": "0xd1bdb150f6fd170e", + "number": "2294630", + "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", + "timestamp": "1513675347", + "totalDifficulty": "7160543502214733" + }, + "input": "0x7ef85aa0b4f9f798a5fe956d1b79c3eff355febf9e1039a7440948845536982cb62aa03194bc339e628e6fe32c39e84392d087567b2743ea3594bc339e628e6fe32c39e84392d087567b2743ea3580871aa535d3d0c00083030d408000", + "result": { + "from":"0x0000000000000000000000000000000000000000", + "gas":"0x0", + "gasUsed":"0x30d40", + "input":"0x", + "error": "failed deposit transaction", + "type":"STOP" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/failed_deposit.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/failed_deposit.json new file mode 100644 index 0000000000..540cd53579 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/failed_deposit.json @@ -0,0 +1,59 @@ +{ + "context": { + "difficulty": "3699098917", + "gasLimit": "5258985", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "number": "2294631", + "timestamp": "1513675366" + }, + "genesis": { + "alloc": {}, + "config": { + "chainId": 3, + "daoForkSupport": true, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "ethash": {}, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0 + }, + "difficulty": "3699098917", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "5263953", + "hash": "0x03a0f62a8106793dafcfae7b75fd2654322062d585a19cea568314d7205790dc", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x15482cc64b7c00a947f5bf015dfc010db1a6a668c74df61974d6a7848c174408", + "nonce": "0xd1bdb150f6fd170e", + "number": "2294630", + "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", + "timestamp": "1513675347", + "totalDifficulty": "7160543502214733" + }, + "input": "0x7ef85aa0b4f9f798a5fe956d1b79c3eff355febf9e1039a7440948845536982cb62aa03194bc339e628e6fe32c39e84392d087567b2743ea3594bc339e628e6fe32c39e84392d087567b2743ea3580871aa535d3d0c00083030d408000", + "result": [ + { + "action": { + "callType": "stop", + "from": "0x0000000000000000000000000000000000000000", + "gas": "0x0", + "input": "0x", + "value": "0x0" + }, + "blockNumber": 0, + "error": "failed deposit transaction", + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index f85cf6206a..ac5dac7449 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -262,6 +262,10 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { return nil, errors.New("incorrect number of top-level calls") } + if len(t.callstack) == 1 && t.callstack[0].Type == vm.STOP { + t.callstack[0].Error = "failed deposit transaction" + } + res, err := json.Marshal(t.callstack[0]) if err != nil { return nil, err diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 266ab99001..44637b84b6 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -215,6 +215,10 @@ func (t *flatCallTracer) GetResult() (json.RawMessage, error) { return nil, errors.New("invalid number of calls") } + if len(t.tracer.callstack) == 1 && t.tracer.callstack[0].Type == vm.STOP { + t.tracer.callstack[0].Error = "failed deposit transaction" + } + flat, err := flatFromNested(&t.tracer.callstack[0], []int{}, t.config.ConvertParityErrors, t.ctx) if err != nil { return nil, err @@ -251,6 +255,8 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx frame = newFlatSelfdestruct(input) case vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.DELEGATECALL: frame = newFlatCall(input) + case vm.STOP: + frame = newFlatCall(input) default: return nil, fmt.Errorf("unrecognized call frame type: %s", input.Type) }