Skip to content

Commit 39d91d5

Browse files
committed
Implement the optional output field on ots_traceTransaction otterscan/execution-apis#1
1 parent 2b71976 commit 39d91d5

File tree

1 file changed

+50
-34
lines changed

1 file changed

+50
-34
lines changed

turbo/jsonrpc/otterscan_trace_transaction.go

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package jsonrpc
22

33
import (
44
"context"
5-
"github.com/ledgerwatch/erigon-lib/common/hexutil"
65
"math/big"
76

7+
"github.com/ledgerwatch/erigon-lib/common/hexutil"
8+
89
"github.com/holiman/uint256"
910

1011
"github.com/ledgerwatch/erigon-lib/common"
@@ -29,25 +30,28 @@ func (api *OtterscanAPIImpl) TraceTransaction(ctx context.Context, hash common.H
2930
}
3031

3132
type TraceEntry struct {
32-
Type string `json:"type"`
33-
Depth int `json:"depth"`
34-
From common.Address `json:"from"`
35-
To common.Address `json:"to"`
36-
Value *hexutil.Big `json:"value"`
37-
Input hexutility.Bytes `json:"input"`
33+
Type string `json:"type"`
34+
Depth int `json:"depth"`
35+
From common.Address `json:"from"`
36+
To common.Address `json:"to"`
37+
Value *hexutil.Big `json:"value"`
38+
Input hexutility.Bytes `json:"input"`
39+
Output hexutility.Bytes `json:"output"`
3840
}
3941

4042
type TransactionTracer struct {
4143
DefaultTracer
4244
ctx context.Context
4345
Results []*TraceEntry
4446
depth int // computed from CaptureStart, CaptureEnter, and CaptureExit calls
47+
stack []*TraceEntry
4548
}
4649

4750
func NewTransactionTracer(ctx context.Context) *TransactionTracer {
4851
return &TransactionTracer{
4952
ctx: ctx,
5053
Results: make([]*TraceEntry, 0),
54+
stack: make([]*TraceEntry, 0),
5155
}
5256
}
5357

@@ -62,35 +66,31 @@ func (t *TransactionTracer) captureStartOrEnter(typ vm.OpCode, from, to common.A
6266
if value != nil {
6367
_value.Set(value.ToBig())
6468
}
65-
if typ == vm.CALL {
66-
t.Results = append(t.Results, &TraceEntry{"CALL", t.depth, from, to, (*hexutil.Big)(_value), inputCopy})
67-
return
68-
}
69-
if typ == vm.STATICCALL {
70-
t.Results = append(t.Results, &TraceEntry{"STATICCALL", t.depth, from, to, nil, inputCopy})
71-
return
72-
}
73-
if typ == vm.DELEGATECALL {
74-
t.Results = append(t.Results, &TraceEntry{"DELEGATECALL", t.depth, from, to, nil, inputCopy})
75-
return
76-
}
77-
if typ == vm.CALLCODE {
78-
t.Results = append(t.Results, &TraceEntry{"CALLCODE", t.depth, from, to, (*hexutil.Big)(_value), inputCopy})
79-
return
80-
}
81-
if typ == vm.CREATE {
82-
t.Results = append(t.Results, &TraceEntry{"CREATE", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy})
83-
return
84-
}
85-
if typ == vm.CREATE2 {
86-
t.Results = append(t.Results, &TraceEntry{"CREATE2", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy})
87-
return
88-
}
8969

90-
if typ == vm.SELFDESTRUCT {
70+
var entry *TraceEntry
71+
if typ == vm.CALL {
72+
entry = &TraceEntry{"CALL", t.depth, from, to, (*hexutil.Big)(_value), inputCopy, nil}
73+
} else if typ == vm.STATICCALL {
74+
entry = &TraceEntry{"STATICCALL", t.depth, from, to, nil, inputCopy, nil}
75+
} else if typ == vm.DELEGATECALL {
76+
entry = &TraceEntry{"DELEGATECALL", t.depth, from, to, nil, inputCopy, nil}
77+
} else if typ == vm.CALLCODE {
78+
entry = &TraceEntry{"CALLCODE", t.depth, from, to, (*hexutil.Big)(_value), inputCopy, nil}
79+
} else if typ == vm.CREATE {
80+
entry = &TraceEntry{"CREATE", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil}
81+
} else if typ == vm.CREATE2 {
82+
entry = &TraceEntry{"CREATE2", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil}
83+
} else if typ == vm.SELFDESTRUCT {
9184
last := t.Results[len(t.Results)-1]
92-
t.Results = append(t.Results, &TraceEntry{"SELFDESTRUCT", last.Depth + 1, from, to, (*hexutil.Big)(value.ToBig()), nil})
85+
entry = &TraceEntry{"SELFDESTRUCT", last.Depth + 1, from, to, (*hexutil.Big)(value.ToBig()), nil, nil}
86+
} else {
87+
// safeguard in case new CALL-like opcodes are introduced but not handled,
88+
// otherwise CaptureExit/stack will get out of sync
89+
entry = &TraceEntry{"UNKNOWN", t.depth, from, to, (*hexutil.Big)(value.ToBig()), inputCopy, nil}
9390
}
91+
92+
t.Results = append(t.Results, entry)
93+
t.stack = append(t.stack, entry)
9494
}
9595

9696
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) {
@@ -103,6 +103,22 @@ func (t *TransactionTracer) CaptureEnter(typ vm.OpCode, from common.Address, to
103103
t.captureStartOrEnter(typ, from, to, precompile, input, value)
104104
}
105105

106-
func (t *TransactionTracer) CaptureExit(output []byte, usedGas uint64, err error) {
106+
func (t *TransactionTracer) captureEndOrExit(output []byte, usedGas uint64, err error) {
107107
t.depth--
108+
109+
lastIdx := len(t.stack) - 1
110+
pop := t.stack[lastIdx]
111+
t.stack = t.stack[:lastIdx]
112+
113+
outputCopy := make([]byte, len(output))
114+
copy(outputCopy, output)
115+
pop.Output = outputCopy
116+
}
117+
118+
func (t *TransactionTracer) CaptureExit(output []byte, usedGas uint64, err error) {
119+
t.captureEndOrExit(output, usedGas, err)
120+
}
121+
122+
func (t *TransactionTracer) CaptureEnd(output []byte, usedGas uint64, err error) {
123+
t.captureEndOrExit(output, usedGas, err)
108124
}

0 commit comments

Comments
 (0)