Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions eth/tracers/native/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ type callLog struct {
// Position of the log relative to subcalls within the same trace
// See https://github.com/ethereum/go-ethereum/pull/28389 for details
Position hexutil.Uint `json:"position"`
Pc uint64 `json:"pc"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason to include the PC in the emitted logs?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same idea as the calls, map the logs to the appropriate LOG instruction in the emitting contract.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a bit more info on the purpose. It doesn't make sense to me on the first look.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PC in the call frames helps map back to the CALL instruction of the caller. Similarly, the PC in the log objects helps map back to the LOGX instruction that emitted the log. I included the PC in both because both are "entities" in the call tracers return payload.

This kind of information is really useful when debugging transactions/working with call traces.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like a very advanced usage, or probably just over-complicated.

Do you really need to map the logs to the execution steps?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's weird to have the program counter for calls but not for the logs -- both are important entities in the trace that benefit from this information.

It's pretty standard in transaction debuggers, see this tx trace from Tenderly: https://dashboard.tenderly.co/tx/0x5a73efb84b8ba5ca688f4f6140dac5ba7222a1f980239a6942137e6a3dabe2e7?trace=0.1.8

With the program counter for the last emitted LOG, we can map it to the correct emit line in source, which is very useful when debugging transactions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any update on this? I don't find having a PC for the logs an advanced use case -- every tool/use case that can map calls to callsites using the PC in the call frames, they can do the same for emitted logs.

}

type callFrame struct {
Type vm.OpCode `json:"-"`
Pc uint64 `json:"pc"`
From common.Address `json:"from"`
Gas uint64 `json:"gas"`
GasUsed uint64 `json:"gasUsed"`
Expand Down Expand Up @@ -117,6 +119,7 @@ type callTracer struct {
depth int
interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
lastPc uint64
}

type callTracerConfig struct {
Expand All @@ -138,6 +141,7 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param
OnEnter: t.OnEnter,
OnExit: t.OnExit,
OnLog: t.OnLog,
OnOpcode: t.OnOpcode,
},
GetResult: t.GetResult,
Stop: t.Stop,
Expand Down Expand Up @@ -173,6 +177,7 @@ func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common
Input: common.CopyBytes(input),
Gas: gas,
Value: value,
Pc: t.lastPc,
}
if depth == 0 {
call.Gas = t.gasLimit
Expand Down Expand Up @@ -219,6 +224,10 @@ func (t *callTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, fr
t.gasLimit = tx.Gas()
}

func (t *callTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
t.lastPc = pc
}

func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) {
// Error happened during tx validation.
if err != nil {
Expand Down Expand Up @@ -251,6 +260,7 @@ func (t *callTracer) OnLog(log *types.Log) {
Topics: log.Topics,
Data: log.Data,
Position: hexutil.Uint(len(t.callstack[len(t.callstack)-1].Calls)),
Pc: t.lastPc,
}
t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, l)
}
Expand Down
6 changes: 6 additions & 0 deletions eth/tracers/native/gen_callframe_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading