Skip to content

Commit

Permalink
Merge pull request Fantom-foundation#114 from Fantom-foundation/tx-tr…
Browse files Browse the repository at this point in the history
…acing-fix-tests

Add tx tracing tests, fix gasUsed value and error reporting in traces
  • Loading branch information
jenikd authored Apr 12, 2024
2 parents f4c1aad + 6142001 commit 675af9f
Show file tree
Hide file tree
Showing 3 changed files with 482 additions and 6 deletions.
12 changes: 8 additions & 4 deletions ethapi/tx_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,11 @@ func (s *PublicTxTraceAPI) replayBlock(ctx context.Context, block *evmcore.EvmBl
return nil, fmt.Errorf("cannot get message from transaction %s, error %s", tx.Hash().String(), err)
}

txTraces, err := s.traceTx(ctx, s.b, block.Header(), msg, state, block, tx, uint64(receipts[i].TransactionIndex), receipts[i].Status)
if len(receipts) <= i || receipts[i] == nil {
return nil, fmt.Errorf("no receipt found for transaction %s", tx.Hash().String())
}

txTraces, err := s.traceTx(ctx, s.b, block.Header(), msg, state, block, tx, uint64(receipts[i].TransactionIndex), receipts[i].Status, receipts[i].GasUsed)
if err != nil {
return nil, fmt.Errorf("cannot get transaction trace for transaction %s, error %s", tx.Hash().String(), err)
} else {
Expand All @@ -148,7 +152,7 @@ func (s *PublicTxTraceAPI) replayBlock(ctx context.Context, block *evmcore.EvmBl
break
}

} else if txHash != nil {
} else {

// Replay transaction without tracing to prepare state for next transaction
log.Debug("Replaying transaction without trace", "txHash", tx.Hash().String())
Expand Down Expand Up @@ -205,12 +209,12 @@ func (s *PublicTxTraceAPI) replayBlock(ctx context.Context, block *evmcore.EvmBl
func (s *PublicTxTraceAPI) traceTx(
ctx context.Context, b Backend, header *evmcore.EvmHeader, msg types.Message,
state state.StateDB, block *evmcore.EvmBlock, tx *types.Transaction, index uint64,
status uint64) (*[]txtrace.ActionTrace, error) {
status uint64, gasUsed uint64) (*[]txtrace.ActionTrace, error) {

// Providing default config with tracer
cfg := opera.DefaultVMConfig
cfg.Debug = true
txTracer := txtrace.NewTraceStructLogger(block, tx, msg, uint(index))
txTracer := txtrace.NewTraceStructLogger(block, tx, msg, uint(index), gasUsed)
cfg.Tracer = txTracer
cfg.NoBaseFee = true

Expand Down
35 changes: 33 additions & 2 deletions txtrace/trace_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type TraceStructLogger struct {
value big.Int

gasLimit uint64
gasUsed uint64
rootTrace *CallTrace
inputData []byte
traceAddress []uint32
Expand Down Expand Up @@ -84,7 +85,7 @@ type TraceActionResult struct {
}

// NewTraceStructLogger creates new instance of trace creator
func NewTraceStructLogger(block *evmcore.EvmBlock, tx *types.Transaction, msg types.Message, index uint) *TraceStructLogger {
func NewTraceStructLogger(block *evmcore.EvmBlock, tx *types.Transaction, msg types.Message, index uint, gasUsed uint64) *TraceStructLogger {
traceStructLogger := TraceStructLogger{
tx: tx.Hash(),
from: msg.From(),
Expand All @@ -94,6 +95,7 @@ func NewTraceStructLogger(block *evmcore.EvmBlock, tx *types.Transaction, msg ty
blockNumber: *block.Number,
txIndex: index,
gasLimit: tx.Gas(),
gasUsed: gasUsed,
}
return &traceStructLogger
}
Expand Down Expand Up @@ -155,6 +157,10 @@ func (tr *TraceStructLogger) CaptureStart(env *vm.EVM, from common.Address, to c
Actions: make([]ActionTrace, 0),
}

if value == nil {
value = big.NewInt(0)
}

// Check if To is defined. If not, it is create address call
callType := CREATE
var newAddress *common.Address
Expand Down Expand Up @@ -296,7 +302,9 @@ func (tr *TraceStructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Du
trace := tr.rootTrace.lastTrace()
trace.processOutput(output, err, true)
if trace.Result != nil {
trace.Result.GasUsed = hexutil.Uint64(tr.gasLimit)
// set gas used of the root call with the gas from transaction receipt
// to present all cumulative gas used by this call and its inner calls
trace.Result.GasUsed = hexutil.Uint64(tr.gasUsed)
}

tr.rootTrace.processTraces()
Expand Down Expand Up @@ -333,6 +341,17 @@ func (trace *ActionTrace) processOutput(output []byte, err error, rootTrace bool
if trace.TraceType == CREATE {
trace.Action.To = nil
}
if traceError, ok := traceErrorMapping[err.Error()]; ok {
trace.Error = traceError
return
}

switch err.(type) {
case *vm.ErrStackOverflow:
trace.Error = "Out of stack"
return
}

if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 {
return
}
Expand Down Expand Up @@ -458,3 +477,15 @@ func createErrorTrace(blockHash common.Hash, blockNumber big.Int,
}
return blockTrace
}

var traceErrorMapping = map[string]string{
vm.ErrCodeStoreOutOfGas.Error(): "Out of gas",
vm.ErrOutOfGas.Error(): "Out of gas",
vm.ErrGasUintOverflow.Error(): "Out of gas",
vm.ErrMaxCodeSizeExceeded.Error(): "Out of gas",
vm.ErrInvalidJump.Error(): "Bad jump destination",
vm.ErrExecutionReverted.Error(): "Reverted",
vm.ErrReturnDataOutOfBounds.Error(): "Out of bounds",
"precompiled failed": "Built-in failed",
"invalid input length": "Built-in failed",
}
Loading

0 comments on commit 675af9f

Please sign in to comment.