From b2ef73f5857824964b23e6195746db7c005d108f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 24 Mar 2024 03:57:32 -0300 Subject: [PATCH] Implement the optional output field on ots_traceTransaction https://github.com/otterscan/execution-apis/pull/1 --- turbo/jsonrpc/otterscan_trace_transaction.go | 74 +++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/turbo/jsonrpc/otterscan_trace_transaction.go b/turbo/jsonrpc/otterscan_trace_transaction.go index bbf1488acdc..84d9d10b7ea 100644 --- a/turbo/jsonrpc/otterscan_trace_transaction.go +++ b/turbo/jsonrpc/otterscan_trace_transaction.go @@ -2,9 +2,10 @@ package jsonrpc import ( "context" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "math/big" + "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" @@ -29,12 +30,13 @@ func (api *OtterscanAPIImpl) TraceTransaction(ctx context.Context, hash common.H } type TraceEntry struct { - Type string `json:"type"` - Depth int `json:"depth"` - From common.Address `json:"from"` - To common.Address `json:"to"` - Value *hexutil.Big `json:"value"` - Input hexutility.Bytes `json:"input"` + Type string `json:"type"` + Depth int `json:"depth"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Value *hexutil.Big `json:"value"` + Input hexutility.Bytes `json:"input"` + Output hexutility.Bytes `json:"output"` } type TransactionTracer struct { @@ -42,12 +44,14 @@ type TransactionTracer struct { ctx context.Context Results []*TraceEntry depth int // computed from CaptureStart, CaptureEnter, and CaptureExit calls + stack []*TraceEntry } func NewTransactionTracer(ctx context.Context) *TransactionTracer { return &TransactionTracer{ ctx: ctx, Results: make([]*TraceEntry, 0), + stack: make([]*TraceEntry, 0), } } @@ -62,35 +66,31 @@ func (t *TransactionTracer) captureStartOrEnter(typ vm.OpCode, from, to common.A if value != nil { _value.Set(value.ToBig()) } - if typ == vm.CALL { - t.Results = append(t.Results, &TraceEntry{"CALL", t.depth, from, to, (*hexutil.Big)(_value), inputCopy}) - return - } - if typ == vm.STATICCALL { - t.Results = append(t.Results, &TraceEntry{"STATICCALL", t.depth, from, to, nil, inputCopy}) - return - } - if typ == vm.DELEGATECALL { - t.Results = append(t.Results, &TraceEntry{"DELEGATECALL", t.depth, from, to, nil, inputCopy}) - return - } - if typ == vm.CALLCODE { - t.Results = append(t.Results, &TraceEntry{"CALLCODE", t.depth, from, to, (*hexutil.Big)(_value), inputCopy}) - return - } - if typ == vm.CREATE { - t.Results = append(t.Results, &TraceEntry{"CREATE", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy}) - return - } - if typ == vm.CREATE2 { - t.Results = append(t.Results, &TraceEntry{"CREATE2", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy}) - return - } - if typ == vm.SELFDESTRUCT { + var entry *TraceEntry + if typ == vm.CALL { + entry = &TraceEntry{"CALL", t.depth, from, to, (*hexutil.Big)(_value), inputCopy, nil} + } else if typ == vm.STATICCALL { + entry = &TraceEntry{"STATICCALL", t.depth, from, to, nil, inputCopy, nil} + } else if typ == vm.DELEGATECALL { + entry = &TraceEntry{"DELEGATECALL", t.depth, from, to, nil, inputCopy, nil} + } else if typ == vm.CALLCODE { + entry = &TraceEntry{"CALLCODE", t.depth, from, to, (*hexutil.Big)(_value), inputCopy, nil} + } else if typ == vm.CREATE { + entry = &TraceEntry{"CREATE", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil} + } else if typ == vm.CREATE2 { + entry = &TraceEntry{"CREATE2", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil} + } else if typ == vm.SELFDESTRUCT { last := t.Results[len(t.Results)-1] - t.Results = append(t.Results, &TraceEntry{"SELFDESTRUCT", last.Depth + 1, from, to, (*hexutil.Big)(value.ToBig()), nil}) + entry = &TraceEntry{"SELFDESTRUCT", last.Depth + 1, from, to, (*hexutil.Big)(value.ToBig()), nil, nil} + } else { + // safeguard in case new CALL-like opcodes are introduced but not handled, + // otherwise CaptureExit/stack will get out of sync + entry = &TraceEntry{"UNKNOWN", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil} } + + t.Results = append(t.Results, entry) + t.stack = append(t.stack, entry) } func (t *TransactionTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, precompile bool, create bool, input []byte, gas uint64, value *uint256.Int, code []byte) { @@ -105,4 +105,12 @@ func (t *TransactionTracer) CaptureEnter(typ vm.OpCode, from common.Address, to func (t *TransactionTracer) CaptureExit(output []byte, usedGas uint64, err error) { t.depth-- + + lastIdx := len(t.stack) - 1 + pop := t.stack[lastIdx] + t.stack = t.stack[:lastIdx] + + outputCopy := make([]byte, len(output)) + copy(outputCopy, output) + pop.Output = outputCopy }