mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-14 20:16:36 +00:00
core: introduce GasChangeHook v2 (#34946)
This PR introduces OnGasChangeV2 tracing hook, as the pre-requisite for landing EIP-8037. --------- Co-authored-by: Sina M <1591639+s1na@users.noreply.github.com>
This commit is contained in:
parent
21c5a287f9
commit
0494cdce23
10 changed files with 164 additions and 63 deletions
|
|
@ -420,8 +420,10 @@ func (st *stateTransition) buyGas() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil {
|
||||
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
|
||||
if st.evm.Config.Tracer.HasGasHook() {
|
||||
empty := vm.GasBudget{}
|
||||
initial := vm.NewGasBudget(st.msg.GasLimit)
|
||||
st.evm.Config.Tracer.EmitGasChange(empty.AsTracing(), initial.AsTracing(), tracing.GasChangeTxInitialBalance)
|
||||
}
|
||||
st.gasRemaining = vm.NewGasBudget(st.msg.GasLimit)
|
||||
st.initialBudget = st.gasRemaining.Copy()
|
||||
|
|
@ -566,8 +568,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
if !sufficient {
|
||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining.RegularGas, cost.RegularGas)
|
||||
}
|
||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||
t.OnGasChange(prior, st.gasRemaining.RegularGas, tracing.GasChangeTxIntrinsicGas)
|
||||
if st.evm.Config.Tracer.HasGasHook() {
|
||||
st.evm.Config.Tracer.EmitGasChange(prior.AsTracing(), st.gasRemaining.AsTracing(), tracing.GasChangeTxIntrinsicGas)
|
||||
}
|
||||
// Gas limit suffices for the floor data cost (EIP-7623)
|
||||
if rules.IsPrague {
|
||||
|
|
@ -651,8 +653,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
// After EIP-7623: Data-heavy transactions pay the floor gas.
|
||||
if used := st.gasUsed(); used < floorDataGas {
|
||||
prior, _ := st.gasRemaining.Charge(vm.GasCosts{RegularGas: floorDataGas - used})
|
||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||
t.OnGasChange(prior, st.gasRemaining.RegularGas, tracing.GasChangeTxDataFloor)
|
||||
if st.evm.Config.Tracer.HasGasHook() {
|
||||
st.evm.Config.Tracer.EmitGasChange(prior.AsTracing(), st.gasRemaining.AsTracing(), tracing.GasChangeTxDataFloor)
|
||||
}
|
||||
}
|
||||
if peakGasUsed < floorDataGas {
|
||||
|
|
@ -780,8 +782,11 @@ func (st *stateTransition) calcRefund() vm.GasBudget {
|
|||
if refund > st.state.GetRefund() {
|
||||
refund = st.state.GetRefund()
|
||||
}
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining.RegularGas, st.gasRemaining.RegularGas+refund, tracing.GasChangeTxRefunds)
|
||||
if refund > 0 && st.evm.Config.Tracer.HasGasHook() {
|
||||
after := st.gasRemaining
|
||||
after.RegularGas += refund
|
||||
|
||||
st.evm.Config.Tracer.EmitGasChange(st.gasRemaining.AsTracing(), after.AsTracing(), tracing.GasChangeTxRefunds)
|
||||
}
|
||||
return vm.NewGasBudget(refund)
|
||||
}
|
||||
|
|
@ -793,8 +798,10 @@ func (st *stateTransition) returnGas() {
|
|||
remaining.Mul(remaining, st.msg.GasPrice)
|
||||
st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn)
|
||||
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining.RegularGas > 0 {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining.RegularGas, 0, tracing.GasChangeTxLeftOverReturned)
|
||||
if st.gasRemaining.RegularGas > 0 && st.evm.Config.Tracer.HasGasHook() {
|
||||
after := st.gasRemaining
|
||||
after.RegularGas = 0
|
||||
st.evm.Config.Tracer.EmitGasChange(st.gasRemaining.AsTracing(), after.AsTracing(), tracing.GasChangeTxLeftOverReturned)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,10 +164,36 @@ type (
|
|||
// FaultHook is invoked when an error occurs during the execution of an opcode.
|
||||
FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error)
|
||||
|
||||
// GasChangeHook is invoked when the gas changes.
|
||||
// GasChangeHook reports changes to the regular execution gas. Tracers
|
||||
// that don't need visibility into the state-access gas dimension
|
||||
// introduced by EIP-8037 (Amsterdam) can implement only this hook; it
|
||||
// will continue to fire across the Amsterdam fork unchanged.
|
||||
//
|
||||
// If both this hook and GasChangeHookV2 are implemented on the same
|
||||
// tracer, only V2 will be invoked. Implement exactly one to avoid
|
||||
// double-counting.
|
||||
GasChangeHook = func(old, new uint64, reason GasChangeReason)
|
||||
|
||||
// TODO(sina, rjl), please add GasChangeV2Hook by landing the multi-dimensional gas
|
||||
// GasChangeHookV2 is invoked when any gas dimension changes. It is the
|
||||
// multi-dimensional successor to GasChangeHook, exposing the state-access
|
||||
// gas dimension introduced by EIP-8037 (Amsterdam) alongside the regular
|
||||
// dimension.
|
||||
//
|
||||
// Compatibility:
|
||||
// - Post-Amsterdam: fires for changes to either the regular or the
|
||||
// state-access dimension. The non-changing dimension is passed through
|
||||
// unchanged in both `old` and `new` so consumers always observe the
|
||||
// complete gas vector.
|
||||
// - Pre-Amsterdam: no state-access gas events occur, so the State field
|
||||
// of both `old` and `new` is always zero. Tracers that register only
|
||||
// V2 still receive every regular-gas change as Gas{State: 0} and
|
||||
// behave identically to a V1 tracer; there is no pre-Amsterdam event
|
||||
// a V2-only tracer misses.
|
||||
//
|
||||
// V1 and V2 coexist: when both are registered on a tracer, only V2 is
|
||||
// invoked. Tracers SHOULD register at most one of the two to avoid
|
||||
// double-counting.
|
||||
GasChangeHookV2 = func(old, new Gas, reason GasChangeReason)
|
||||
|
||||
/*
|
||||
- Chain events -
|
||||
|
|
@ -250,13 +276,14 @@ type (
|
|||
|
||||
type Hooks struct {
|
||||
// VM events
|
||||
OnTxStart TxStartHook
|
||||
OnTxEnd TxEndHook
|
||||
OnEnter EnterHook
|
||||
OnExit ExitHook
|
||||
OnOpcode OpcodeHook
|
||||
OnFault FaultHook
|
||||
OnGasChange GasChangeHook
|
||||
OnTxStart TxStartHook
|
||||
OnTxEnd TxEndHook
|
||||
OnEnter EnterHook
|
||||
OnExit ExitHook
|
||||
OnOpcode OpcodeHook
|
||||
OnFault FaultHook
|
||||
OnGasChange GasChangeHook
|
||||
OnGasChangeV2 GasChangeHookV2
|
||||
// Chain events
|
||||
OnBlockchainInit BlockchainInitHook
|
||||
OnClose CloseHook
|
||||
|
|
@ -280,6 +307,35 @@ type Hooks struct {
|
|||
OnBlockHashRead BlockHashReadHook
|
||||
}
|
||||
|
||||
// HasGasHook reports whether any gas-change hook is registered. Call sites
|
||||
// should use this to short-circuit before constructing the Gas / GasBudget
|
||||
// arguments to EmitGasChange when tracing is off — the dispatch is otherwise
|
||||
// always paid the cost of evaluating those args.
|
||||
func (h *Hooks) HasGasHook() bool {
|
||||
return h != nil && (h.OnGasChangeV2 != nil || h.OnGasChange != nil)
|
||||
}
|
||||
|
||||
// EmitGasChange dispatches a gas change event to the registered hooks. If the
|
||||
// multi-dimensional OnGasChangeV2 hook is set it is invoked with the full Gas
|
||||
// vectors; otherwise the single-dimensional OnGasChange hook is invoked with
|
||||
// the regular-gas dimension only. The call is a no-op when the receiver is
|
||||
// nil, when neither hook is registered, or when the reason is GasChangeIgnored.
|
||||
//
|
||||
// Call sites SHOULD use this helper instead of invoking the hooks directly so
|
||||
// that both variants stay consistent across the Amsterdam fork boundary.
|
||||
func (h *Hooks) EmitGasChange(old, new Gas, reason GasChangeReason) {
|
||||
if h == nil || reason == GasChangeIgnored {
|
||||
return
|
||||
}
|
||||
if h.OnGasChangeV2 != nil {
|
||||
h.OnGasChangeV2(old, new, reason)
|
||||
return
|
||||
}
|
||||
if h.OnGasChange != nil {
|
||||
h.OnGasChange(old.Regular, new.Regular, reason)
|
||||
}
|
||||
}
|
||||
|
||||
// BalanceChangeReason is used to indicate the reason for a balance change, useful
|
||||
// for tracing and reporting.
|
||||
type BalanceChangeReason byte
|
||||
|
|
@ -335,6 +391,19 @@ const (
|
|||
BalanceChangeRevert BalanceChangeReason = 15
|
||||
)
|
||||
|
||||
// Gas represents a multi-dimensional gas budget introduced by EIP-8037.
|
||||
// It carries the regular execution gas and the state-access gas, which are
|
||||
// metered independently from the Amsterdam fork onwards.
|
||||
//
|
||||
// Before Amsterdam, gas metering is single-dimensional and only the Regular
|
||||
// field is meaningful; State is always zero. The struct is shaped so that
|
||||
// pre-Amsterdam call sites can populate it as Gas{Regular: g} without loss
|
||||
// of fidelity relative to the legacy single-uint64 hook.
|
||||
type Gas struct {
|
||||
Regular uint64 // Regular is the budget for ordinary execution gas.
|
||||
State uint64 // State is the budget dedicated to state-access gas (zero pre-Amsterdam).
|
||||
}
|
||||
|
||||
// GasChangeReason is used to indicate the reason for a gas change, useful
|
||||
// for tracing and reporting.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ func (c *Contract) UseGas(cost GasCosts, logger *tracing.Hooks, reason tracing.G
|
|||
if !ok {
|
||||
return false
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
logger.OnGasChange(prior, c.Gas.RegularGas, reason)
|
||||
if logger.HasGasHook() && reason != tracing.GasChangeIgnored {
|
||||
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -143,8 +143,8 @@ func (c *Contract) RefundGas(refund GasBudget, logger *tracing.Hooks, reason tra
|
|||
if !changed {
|
||||
return
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
logger.OnGasChange(prior, c.Gas.RegularGas, reason)
|
||||
if logger.HasGasHook() && reason != tracing.GasChangeIgnored {
|
||||
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,8 +269,8 @@ func RunPrecompiledContract(stateDB StateDB, p PrecompiledContract, address comm
|
|||
gas.Exhaust()
|
||||
return nil, gas, ErrOutOfGas
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil {
|
||||
logger.OnGasChange(prior, gas.RegularGas, tracing.GasChangeCallPrecompiledContract)
|
||||
if logger.HasGasHook() {
|
||||
logger.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeCallPrecompiledContract)
|
||||
}
|
||||
// Touch the precompile for block-level accessList recording once Amsterdam
|
||||
// fork is activated.
|
||||
|
|
|
|||
|
|
@ -317,8 +317,8 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), tracing.Gas{}, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas.Exhaust()
|
||||
}
|
||||
|
|
@ -371,8 +371,8 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), tracing.Gas{}, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas.Exhaust()
|
||||
}
|
||||
|
|
@ -415,8 +415,8 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), tracing.Gas{}, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas.Exhaust()
|
||||
}
|
||||
|
|
@ -470,8 +470,8 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), tracing.Gas{}, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas.Exhaust()
|
||||
}
|
||||
|
|
@ -509,8 +509,8 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
gas.Exhaust()
|
||||
return nil, common.Address{}, gas, ErrOutOfGas
|
||||
}
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(prior, gas.RegularGas, tracing.GasChangeWitnessContractCollisionCheck)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -528,8 +528,8 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
if evm.StateDB.GetNonce(address) != 0 ||
|
||||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
|
||||
isEIP7610RejectedAccount(evm.ChainConfig().ChainID, address, evm.chainRules.IsEIP158) {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), tracing.Gas{}, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas.Exhaust()
|
||||
return nil, common.Address{}, gas, ErrContractAddressCollision
|
||||
|
|
@ -558,8 +558,8 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
return nil, common.Address{}, gas, ErrOutOfGas
|
||||
}
|
||||
prior, _ := gas.Charge(GasCosts{RegularGas: consumed})
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(prior, gas.RegularGas, tracing.GasChangeWitnessContractInit)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractInit)
|
||||
}
|
||||
}
|
||||
evm.Context.Transfer(evm.StateDB, caller, address, value, &evm.chainRules)
|
||||
|
|
@ -673,15 +673,17 @@ func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to comm
|
|||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value)
|
||||
}
|
||||
if tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
|
||||
if tracer.HasGasHook() {
|
||||
initial := NewGasBudget(startGas)
|
||||
tracer.EmitGasChange(tracing.Gas{}, initial.AsTracing(), tracing.GasChangeCallInitialBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) {
|
||||
tracer := evm.Config.Tracer
|
||||
if leftOverGas != 0 && tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
|
||||
if leftOverGas != 0 && tracer.HasGasHook() {
|
||||
leftover := NewGasBudget(leftOverGas)
|
||||
tracer.EmitGasChange(leftover.AsTracing(), tracing.Gas{}, tracing.GasChangeCallLeftOverReturned)
|
||||
}
|
||||
var reverted bool
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
package vm
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
)
|
||||
|
||||
// GasCosts denotes a vector of gas costs in the
|
||||
// multidimensional metering paradigm. It represents the cost
|
||||
|
|
@ -77,21 +81,26 @@ func (g GasBudget) CanAfford(cost GasCosts) bool {
|
|||
}
|
||||
|
||||
// Charge deducts the given gas cost from the budget. It returns the
|
||||
// pre-charge gas value and false if the budget does not have sufficient
|
||||
// pre-charge budget and false if the budget does not have sufficient
|
||||
// gas to cover the cost.
|
||||
func (g *GasBudget) Charge(cost GasCosts) (uint64, bool) {
|
||||
prior := g.RegularGas
|
||||
if prior < cost.RegularGas {
|
||||
func (g *GasBudget) Charge(cost GasCosts) (GasBudget, bool) {
|
||||
prior := *g
|
||||
if g.RegularGas < cost.RegularGas {
|
||||
return prior, false
|
||||
}
|
||||
g.RegularGas -= cost.RegularGas
|
||||
return prior, true
|
||||
}
|
||||
|
||||
// Refund adds the given gas budget back. It returns the pre-refund gas
|
||||
// value and whether the budget was actually changed.
|
||||
func (g *GasBudget) Refund(other GasBudget) (uint64, bool) {
|
||||
prior := g.RegularGas
|
||||
// Refund adds the given gas budget back. It returns the pre-refund budget
|
||||
// and whether the budget was actually changed.
|
||||
func (g *GasBudget) Refund(other GasBudget) (GasBudget, bool) {
|
||||
prior := *g
|
||||
g.RegularGas += other.RegularGas
|
||||
return prior, g.RegularGas != prior
|
||||
return prior, g.RegularGas != prior.RegularGas
|
||||
}
|
||||
|
||||
// AsTracing converts the GasBudget into the tracing-facing Gas vector.
|
||||
func (g GasBudget) AsTracing() tracing.Gas {
|
||||
return tracing.Gas{Regular: g.RegularGas, State: g.StateGas}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,8 +234,12 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte
|
|||
|
||||
// Do tracing before potential memory expansion
|
||||
if debug {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(
|
||||
tracing.Gas{Regular: gasCopy, State: contract.Gas.StateGas},
|
||||
tracing.Gas{Regular: gasCopy - cost, State: contract.Gas.StateGas},
|
||||
tracing.GasChangeCallOpCode,
|
||||
)
|
||||
}
|
||||
if evm.Config.Tracer.OnOpcode != nil {
|
||||
evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err))
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) {
|
|||
OnOpcode: t.OnOpcode,
|
||||
OnFault: t.OnFault,
|
||||
OnGasChange: t.OnGasChange,
|
||||
OnGasChangeV2: t.OnGasChangeV2,
|
||||
OnBlockchainInit: t.OnBlockchainInit,
|
||||
OnBlockStart: t.OnBlockStart,
|
||||
OnBlockEnd: t.OnBlockEnd,
|
||||
|
|
@ -113,3 +114,6 @@ func (t *noop) OnBlockHashRead(number uint64, hash common.Hash) {}
|
|||
|
||||
func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
|
||||
}
|
||||
|
||||
func (t *noop) OnGasChangeV2(old, new tracing.Gas, reason tracing.GasChangeReason) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ func newMuxTracerFromConfig(ctx *tracers.Context, cfg json.RawMessage, chainConf
|
|||
// the aggregated JSON result returned by GetResult.
|
||||
//
|
||||
// For hooks that have both a V1 and V2 form (OnCodeChange / OnCodeChangeV2,
|
||||
// OnNonceChange / OnNonceChangeV2, OnSystemCallStart / OnSystemCallStartV2),
|
||||
// the mux exposes only the V2 variant upward. The fanout then prefers each
|
||||
// child's V2 hook and falls back to V1 if only V1 is set, mirroring the
|
||||
// precedence already used in core/state_processor.go.
|
||||
// OnNonceChange / OnNonceChangeV2, OnGasChange / OnGasChangeV2,
|
||||
// OnSystemCallStart / OnSystemCallStartV2), the mux exposes only the V2
|
||||
// variant upward. The fanout then prefers each child's V2 hook and falls
|
||||
// back to V1 if only V1 is set, mirroring the precedence already used in
|
||||
// core/state_processor.go.
|
||||
func NewMuxTracer(names []string, objects []*tracers.Tracer) (*tracers.Tracer, error) {
|
||||
t := &muxTracer{names: names, tracers: objects}
|
||||
return &tracers.Tracer{
|
||||
|
|
@ -79,7 +80,7 @@ func NewMuxTracer(names []string, objects []*tracers.Tracer) (*tracers.Tracer, e
|
|||
OnExit: t.OnExit,
|
||||
OnOpcode: t.OnOpcode,
|
||||
OnFault: t.OnFault,
|
||||
OnGasChange: t.OnGasChange,
|
||||
OnGasChangeV2: t.OnGasChangeV2,
|
||||
OnBalanceChange: t.OnBalanceChange,
|
||||
OnNonceChangeV2: t.OnNonceChangeV2,
|
||||
OnCodeChangeV2: t.OnCodeChangeV2,
|
||||
|
|
@ -109,10 +110,12 @@ func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.
|
|||
}
|
||||
}
|
||||
|
||||
func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
|
||||
func (t *muxTracer) OnGasChangeV2(old, new tracing.Gas, reason tracing.GasChangeReason) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnGasChange != nil {
|
||||
t.OnGasChange(old, new, reason)
|
||||
if t.OnGasChangeV2 != nil {
|
||||
t.OnGasChangeV2(old, new, reason)
|
||||
} else if t.OnGasChange != nil {
|
||||
t.OnGasChange(old.Regular, new.Regular, reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param
|
|||
OnOpcode: t.OnOpcode,
|
||||
OnFault: t.OnFault,
|
||||
OnGasChange: t.OnGasChange,
|
||||
OnGasChangeV2: t.OnGasChangeV2,
|
||||
OnBalanceChange: t.OnBalanceChange,
|
||||
OnNonceChange: t.OnNonceChange,
|
||||
OnCodeChange: t.OnCodeChange,
|
||||
|
|
@ -66,6 +67,8 @@ func (t *noopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpC
|
|||
|
||||
func (t *noopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {}
|
||||
|
||||
func (t *noopTracer) OnGasChangeV2(old, new tracing.Gas, reason tracing.GasChangeReason) {}
|
||||
|
||||
func (t *noopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue