diff --git a/core/state_processor.go b/core/state_processor.go index b1a8938f67..7166ed8bd8 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -186,6 +186,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { + vmenv.Config.Tracer.OnSystemCallStart() + } + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { + defer vmenv.Config.Tracer.OnSystemCallEnd() + } + // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 717de3f0a9..1ace857282 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -168,6 +168,11 @@ type Hooks struct { OnStorageChange StorageChangeHook OnLog LogHook + // This is being discussed in PR https://github.com/ethereum/go-ethereum/pull/29355 + // but Firehose needs them so we add handling for them in our patch + OnSystemCallStart func() + OnSystemCallEnd func() + // Firehose backward compatibility // This hook exist because some current Firehose supported chains requires it // but this field is going to be deprecated and newer chains will not produced diff --git a/eth/tracers/firehose.go b/eth/tracers/firehose.go index e5fa6e7a13..6d88acf4e2 100644 --- a/eth/tracers/firehose.go +++ b/eth/tracers/firehose.go @@ -94,6 +94,11 @@ func newTracingHooksFromFirehose(tracer *Firehose) *tracing.Hooks { OnGasChange: tracer.OnGasChange, OnLog: tracer.OnLog, + // This is being discussed in PR https://github.com/ethereum/go-ethereum/pull/29355 + // but Firehose needs them so we add handling for them in our patch. + OnSystemCallStart: tracer.OnSystemCallStart, + OnSystemCallEnd: tracer.OnSystemCallEnd, + // This should actually be conditional but it's not possible to do it in the hooks // directly because the chain ID will be known only after the `OnBlockchainInit` call. // So we register it unconditionally and the actual `OnNewAccount` hook will decide @@ -442,15 +447,15 @@ func (f *Firehose) reorderCallOrdinals(call *pbeth.Call, ordinalBase uint64) (or return call.EndOrdinal } -func (f *Firehose) OnBeaconBlockRootStart(root common.Hash) { - firehoseInfo("system call start (for=%s)", "beacon_block_root") +func (f *Firehose) OnSystemCallStart() { + firehoseInfo("system call start (for=%s)", callerView(3)) f.ensureInBlockAndNotInTrx() f.inSystemCall = true f.transaction = &pbeth.TransactionTrace{} } -func (f *Firehose) OnBeaconBlockRootEnd() { +func (f *Firehose) OnSystemCallEnd() { f.ensureInBlockAndInTrx() f.ensureInSystemCall() @@ -1963,6 +1968,35 @@ func (r *receiptView) String() string { return fmt.Sprintf("[status=%s, gasUsed=%d, logs=%d]", status, r.GasUsed, len(r.Logs)) } +type callerViewer struct { + skipFrame int +} + +func (v callerViewer) String() string { + _, file, line, found := runtime.Caller(v.skipFrame) + if !found { + return "" + } + + return fmt.Sprintf("%s:%d", file, line) +} + +// callerView returns a fmt.Stringer that will print the caller of the function. You need +// to specify how many frames to skip from the callstack. The minimum is 1 and usually 2. +// +// Imagine you have the call stack +// - callerView(3) +// - firehoseDebug(..., callerView(3)) +// - OnOpcode(...) +// - ProcessCall(...) +// - ... +// +// In this example, with `callerView(2)` which means skip 3 call frames, you would get +// you to ProcessCall frame and `callerView` would print that. +func callerView(skipFrame int) fmt.Stringer { + return callerViewer{skipFrame} +} + func emptyBytesToNil(in []byte) []byte { if len(in) == 0 { return nil