Skip to content

Commit

Permalink
Merge pull request #16 from kaiachain/api-new-calltracer
Browse files Browse the repository at this point in the history
tracers: debug APIs and chaindatafetcher use new vm.CallTracer
  • Loading branch information
blukat29 authored Jul 3, 2024
2 parents 83efc71 + 41cbb31 commit 3f0d609
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 16 deletions.
6 changes: 6 additions & 0 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,12 @@ func GetInternalTxTrace(tracer vm.Tracer) (*vm.InternalTxTrace, error) {
if err != nil {
return nil, err
}
case *vm.CallTracer:
callTrace, err := tracer.GetResult()
if err != nil {
return nil, err
}
internalTxTrace = callTrace.ToInternalTxTrace()
default:
logger.Error("To trace internal transactions, VM tracer type should be vm.InternalTxTracer", "actualType", reflect.TypeOf(tracer).String())
return nil, ErrInvalidTracer
Expand Down
44 changes: 35 additions & 9 deletions blockchain/vm/call_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package vm

import (
"encoding/json"
"errors"
"math/big"
"sync/atomic"
Expand Down Expand Up @@ -51,6 +50,38 @@ func (f CallFrame) TypeString() string { // to satisfy gencodec
return f.Type.String()
}

func (f CallFrame) ToInternalTxTrace() *InternalTxTrace {
t := &InternalTxTrace{}

t.Type = f.Type.String()
t.From = &f.From
t.To = f.To
if f.Value != nil {
t.Value = "0x" + f.Value.Text(16)
}

t.Gas = f.Gas
t.GasUsed = f.GasUsed

if len(f.Input) > 0 {
t.Input = hexutil.Encode(f.Input)
}
if len(f.Output) > 0 {
t.Output = hexutil.Encode(f.Output)
}
t.Error = errors.New(f.Error)

t.Calls = make([]*InternalTxTrace, len(f.Calls))
for i, call := range f.Calls {
t.Calls[i] = call.ToInternalTxTrace()
}

t.RevertReason = f.RevertReason
t.Reverted = f.Reverted

return t
}

// FieldType overrides for callFrame that's used for JSON encoding
// Must rerun gencodec after modifying this struct
type callFrameMarshaling struct {
Expand Down Expand Up @@ -188,18 +219,13 @@ func (t *CallTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost, ccL
func (t *CallTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost, ccLeft, ccOpcode uint64, scope *ScopeContext, depth int, err error) {
}

func (t *CallTracer) GetResult() (json.RawMessage, error) {
func (t *CallTracer) GetResult() (CallFrame, error) {
if len(t.callstack) != 1 {
return nil, errors.New("incorrect number of top-level calls")
}

result, err := json.Marshal(t.callstack[0])
if err != nil {
return nil, err
return CallFrame{}, errors.New("incorrect number of top-level calls")
}

// Return with interrupt reason if any
return result, t.interruptReason
return t.callstack[0], t.interruptReason
}

// Stop terminates execution of the tracer at the first opportune moment.
Expand Down
2 changes: 1 addition & 1 deletion blockchain/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
// If internal transaction tracing is enabled, creates a tracer for a transaction
if vmConfig.EnableInternalTxTracing {
vmConfig.Debug = true
vmConfig.Tracer = NewInternalTxTracer()
vmConfig.Tracer = NewCallTracer()
}

evm.interpreter = NewEVMInterpreter(evm)
Expand Down
3 changes: 2 additions & 1 deletion blockchain/vm/internaltx_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ type InternalTxTrace struct {
Time time.Duration `json:"time,omitempty"`
Calls []*InternalTxTrace `json:"calls,omitempty"`

Reverted *RevertedInfo `json:"reverted,omitempty"`
RevertReason string `json:"revertReason,omitempty"`
Reverted *RevertedInfo `json:"reverted,omitempty"`
}

type RevertedInfo struct {
Expand Down
6 changes: 5 additions & 1 deletion datasync/chaindatafetcher/chaindata_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,11 @@ func (f *ChainDataFetcher) makeChainEvent(blockNumber uint64) (blockchain.ChainE
}
for _, r := range results {
if r.Result != nil {
internalTraces = append(internalTraces, r.Result.(*vm.InternalTxTrace))
switch r.Result.(type) {
case vm.CallFrame:
cf := r.Result.(vm.CallFrame)
internalTraces = append(internalTraces, cf.ToInternalTxTrace())
}
} else {
traceAPIErrorCounter.Inc(1)
logger.Error("the trace result is nil", "err", r.Error, "blockNumber", blockNumber)
Expand Down
8 changes: 6 additions & 2 deletions node/cn/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,8 +901,8 @@ func (api *CommonAPI) traceTx(ctx context.Context, message blockchain.Message, b
}
}

if *config.Tracer == fastCallTracer {
tracer = vm.NewInternalTxTracer()
if *config.Tracer == "fastCallTracer" || *config.Tracer == "callTracer" {
tracer = vm.NewCallTracer()
} else {
// Construct the JavaScript tracer to execute with
if tracer, err = New(*config.Tracer, new(Context), api.unsafeTrace); err != nil {
Expand All @@ -919,6 +919,8 @@ func (api *CommonAPI) traceTx(ctx context.Context, message blockchain.Message, b
t.Stop(errors.New("execution timeout"))
case *vm.InternalTxTracer:
t.Stop(errors.New("execution timeout"))
case *vm.CallTracer:
t.Stop(errors.New("execution timeout"))
default:
logger.Warn("unknown tracer type", "type", reflect.TypeOf(t).String())
}
Expand Down Expand Up @@ -963,6 +965,8 @@ func (api *CommonAPI) traceTx(ctx context.Context, message blockchain.Message, b
return tracer.GetResult()
case *vm.InternalTxTracer:
return tracer.GetResult()
case *vm.CallTracer:
return tracer.GetResult()

default:
panic(fmt.Sprintf("bad tracer type %T", tracer))
Expand Down
7 changes: 5 additions & 2 deletions node/cn/tracers/tracers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,13 @@ func runTracer(t *testing.T, tc *tracerTestdata, tracer vm.Tracer) (*types.Trans
switch tracer := tracer.(type) {
case *Tracer:
tracerResult, err = tracer.GetResult()
require.NoError(t, err)
case *vm.CallTracer:
tracerResult, err = tracer.GetResult()
callFrame, err := tracer.GetResult()
require.NoError(t, err)
tracerResult, err = json.Marshal(callFrame)
require.NoError(t, err)
}
require.NoError(t, err)
assert.JSONEq(t, string(tc.Result), string(tracerResult))

return msg, execResult, tracerResult
Expand Down

0 comments on commit 3f0d609

Please sign in to comment.