Skip to content

Commit

Permalink
Implement the optional output field on ots_traceTransaction otterscan…
Browse files Browse the repository at this point in the history
  • Loading branch information
wmitsuda committed Apr 15, 2024
1 parent 2b71976 commit 39d91d5
Showing 1 changed file with 50 additions and 34 deletions.
84 changes: 50 additions & 34 deletions turbo/jsonrpc/otterscan_trace_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -29,25 +30,28 @@ 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 {
DefaultTracer
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),
}
}

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

func (t *TransactionTracer) CaptureExit(output []byte, usedGas uint64, err error) {
func (t *TransactionTracer) captureEndOrExit(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
}

func (t *TransactionTracer) CaptureExit(output []byte, usedGas uint64, err error) {
t.captureEndOrExit(output, usedGas, err)
}

func (t *TransactionTracer) CaptureEnd(output []byte, usedGas uint64, err error) {
t.captureEndOrExit(output, usedGas, err)
}

0 comments on commit 39d91d5

Please sign in to comment.