fix: handle empty callstacks in call tracers (#1171)

This commit is contained in:
Ömer Faruk Irmak 2025-04-24 10:59:28 +03:00 committed by GitHub
parent d178b00fb2
commit 5e956fe264
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 13 additions and 9 deletions

View file

@ -18,7 +18,6 @@ package native
import (
"encoding/json"
"errors"
"math/big"
"strconv"
"strings"
@ -60,21 +59,21 @@ type callTracer struct {
func newCallTracer(ctx *tracers.Context) tracers.Tracer {
// First callframe contains tx context info
// and is populated on start and end.
t := &callTracer{callstack: make([]callFrame, 1)}
t := &callTracer{callstack: make([]callFrame, 0, 1)}
return t
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int, authorizationResults []types.AuthorizationResult) {
t.env = env
t.callstack[0] = callFrame{
t.callstack = append(t.callstack, callFrame{
Type: "CALL",
From: addrToHex(from),
To: addrToHex(to),
Input: bytesToHex(input),
Gas: uintToHex(gas),
Value: bigToHex(value),
}
})
if create {
t.callstack[0].Type = "CREATE"
}
@ -152,7 +151,10 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
// error arising from the encoding or forceful termination (via `Stop`).
func (t *callTracer) GetResult() (json.RawMessage, error) {
if len(t.callstack) != 1 {
return nil, errors.New("incorrect number of top-level calls")
// If the callstack is empty, return an empty JSON object instead of erroring
// Callstack can be empty due to an edge case where an L1 message is reverted even
// before entering the first call.
return json.RawMessage("{}"), nil
}
res, err := json.Marshal(t.callstack[0])
if err != nil {

View file

@ -18,7 +18,6 @@ package native
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"strings"
@ -115,7 +114,7 @@ type flatCallTracer struct {
// newFlatCallTracer returns a new flatCallTracer.
func newFlatCallTracer(ctx *tracers.Context) tracers.Tracer {
t := &callTracer{callstack: make([]callFrame, 1)}
t := &callTracer{callstack: make([]callFrame, 0, 1)}
return &flatCallTracer{callTracer: t, ctx: ctx}
@ -133,7 +132,10 @@ func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com
// error arising from the encoding or forceful termination (via `Stop`).
func (t *flatCallTracer) GetResult() (json.RawMessage, error) {
if len(t.callTracer.callstack) < 1 {
return nil, errors.New("invalid number of calls")
// If the callstack is empty, return an empty JSON list instead of erroring
// Callstack can be empty due to an edge case where an L1 message is reverted even
// before entering the first call.
return json.RawMessage("[]"), nil
}
flat, err := flatFromNested(&t.callTracer.callstack[0], []int{}, true, t.ctx)

View file

@ -24,7 +24,7 @@ import (
const (
VersionMajor = 5 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release
VersionPatch = 39 // Patch version component of the current release
VersionPatch = 40 // Patch version component of the current release
VersionMeta = "mainnet" // Version metadata to append to the version string
)