github.com/ethereum/go-ethereum@v1.16.1/core/tracing/hooks.go (about)

     1  // Copyright 2024 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package tracing defines hooks for 'live tracing' of block processing and transaction
    18  // execution. Here we define the low-level [Hooks] object that carries hooks which are
    19  // invoked by the go-ethereum core at various points in the state transition.
    20  //
    21  // To create a tracer that can be invoked with Geth, you need to register it using
    22  // [github.com/ethereum/go-ethereum/eth/tracers.LiveDirectory.Register].
    23  //
    24  // See https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing for a tutorial.
    25  package tracing
    26  
    27  import (
    28  	"math/big"
    29  
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/core/types"
    32  	"github.com/ethereum/go-ethereum/params"
    33  	"github.com/holiman/uint256"
    34  )
    35  
    36  // OpContext provides the context at which the opcode is being
    37  // executed in, including the memory, stack and various contract-level information.
    38  type OpContext interface {
    39  	MemoryData() []byte
    40  	StackData() []uint256.Int
    41  	Caller() common.Address
    42  	Address() common.Address
    43  	CallValue() *uint256.Int
    44  	CallInput() []byte
    45  	ContractCode() []byte
    46  }
    47  
    48  // StateDB gives tracers access to the whole state.
    49  type StateDB interface {
    50  	GetBalance(common.Address) *uint256.Int
    51  	GetNonce(common.Address) uint64
    52  	GetCode(common.Address) []byte
    53  	GetCodeHash(common.Address) common.Hash
    54  	GetState(common.Address, common.Hash) common.Hash
    55  	GetTransientState(common.Address, common.Hash) common.Hash
    56  	Exist(common.Address) bool
    57  	GetRefund() uint64
    58  }
    59  
    60  // VMContext provides the context for the EVM execution.
    61  type VMContext struct {
    62  	Coinbase    common.Address
    63  	BlockNumber *big.Int
    64  	Time        uint64
    65  	Random      *common.Hash
    66  	BaseFee     *big.Int
    67  	StateDB     StateDB
    68  }
    69  
    70  // BlockEvent is emitted upon tracing an incoming block.
    71  // It contains the block as well as consensus related information.
    72  type BlockEvent struct {
    73  	Block     *types.Block
    74  	Finalized *types.Header
    75  	Safe      *types.Header
    76  }
    77  
    78  type (
    79  	/*
    80  		- VM events -
    81  	*/
    82  
    83  	// TxStartHook is called before the execution of a transaction starts.
    84  	// Call simulations don't come with a valid signature. `from` field
    85  	// to be used for address of the caller.
    86  	TxStartHook = func(vm *VMContext, tx *types.Transaction, from common.Address)
    87  
    88  	// TxEndHook is called after the execution of a transaction ends.
    89  	TxEndHook = func(receipt *types.Receipt, err error)
    90  
    91  	// EnterHook is invoked when the processing of a message starts.
    92  	//
    93  	// Take note that EnterHook, when in the context of a live tracer, can be invoked
    94  	// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
    95  	// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
    96  	EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
    97  
    98  	// ExitHook is invoked when the processing of a message ends.
    99  	// `revert` is true when there was an error during the execution.
   100  	// Exceptionally, before the homestead hardfork a contract creation that
   101  	// ran out of gas when attempting to persist the code to database did not
   102  	// count as a call failure and did not cause a revert of the call. This will
   103  	// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
   104  	//
   105  	// Take note that ExitHook, when in the context of a live tracer, can be invoked
   106  	// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
   107  	// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
   108  	ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
   109  
   110  	// OpcodeHook is invoked just prior to the execution of an opcode.
   111  	OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error)
   112  
   113  	// FaultHook is invoked when an error occurs during the execution of an opcode.
   114  	FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error)
   115  
   116  	// GasChangeHook is invoked when the gas changes.
   117  	GasChangeHook = func(old, new uint64, reason GasChangeReason)
   118  
   119  	/*
   120  		- Chain events -
   121  	*/
   122  
   123  	// BlockchainInitHook is called when the blockchain is initialized.
   124  	BlockchainInitHook = func(chainConfig *params.ChainConfig)
   125  
   126  	// CloseHook is called when the blockchain closes.
   127  	CloseHook = func()
   128  
   129  	// BlockStartHook is called before executing `block`.
   130  	// `td` is the total difficulty prior to `block`.
   131  	BlockStartHook = func(event BlockEvent)
   132  
   133  	// BlockEndHook is called after executing a block.
   134  	BlockEndHook = func(err error)
   135  
   136  	// SkippedBlockHook indicates a block was skipped during processing
   137  	// due to it being known previously. This can happen e.g. when recovering
   138  	// from a crash.
   139  	SkippedBlockHook = func(event BlockEvent)
   140  
   141  	// GenesisBlockHook is called when the genesis block is being processed.
   142  	GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc)
   143  
   144  	// OnSystemCallStartHook is called when a system call is about to be executed. Today,
   145  	// this hook is invoked when the EIP-4788 system call is about to be executed to set the
   146  	// beacon block root.
   147  	//
   148  	// After this hook, the EVM call tracing will happened as usual so you will receive a `OnEnter/OnExit`
   149  	// as well as state hooks between this hook and the `OnSystemCallEndHook`.
   150  	//
   151  	// Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks
   152  	// will not be invoked.
   153  	OnSystemCallStartHook = func()
   154  
   155  	// OnSystemCallStartHookV2 is called when a system call is about to be executed. Refer
   156  	// to `OnSystemCallStartHook` for more information.
   157  	OnSystemCallStartHookV2 = func(vm *VMContext)
   158  
   159  	// OnSystemCallEndHook is called when a system call has finished executing. Today,
   160  	// this hook is invoked when the EIP-4788 system call is about to be executed to set the
   161  	// beacon block root.
   162  	OnSystemCallEndHook = func()
   163  
   164  	/*
   165  		- State events -
   166  	*/
   167  
   168  	// BalanceChangeHook is called when the balance of an account changes.
   169  	BalanceChangeHook = func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason)
   170  
   171  	// NonceChangeHook is called when the nonce of an account changes.
   172  	NonceChangeHook = func(addr common.Address, prev, new uint64)
   173  
   174  	// NonceChangeHookV2 is called when the nonce of an account changes.
   175  	NonceChangeHookV2 = func(addr common.Address, prev, new uint64, reason NonceChangeReason)
   176  
   177  	// CodeChangeHook is called when the code of an account changes.
   178  	CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)
   179  
   180  	// StorageChangeHook is called when the storage of an account changes.
   181  	StorageChangeHook = func(addr common.Address, slot common.Hash, prev, new common.Hash)
   182  
   183  	// LogHook is called when a log is emitted.
   184  	LogHook = func(log *types.Log)
   185  
   186  	// BlockHashReadHook is called when EVM reads the blockhash of a block.
   187  	BlockHashReadHook = func(blockNumber uint64, hash common.Hash)
   188  )
   189  
   190  type Hooks struct {
   191  	// VM events
   192  	OnTxStart   TxStartHook
   193  	OnTxEnd     TxEndHook
   194  	OnEnter     EnterHook
   195  	OnExit      ExitHook
   196  	OnOpcode    OpcodeHook
   197  	OnFault     FaultHook
   198  	OnGasChange GasChangeHook
   199  	// Chain events
   200  	OnBlockchainInit    BlockchainInitHook
   201  	OnClose             CloseHook
   202  	OnBlockStart        BlockStartHook
   203  	OnBlockEnd          BlockEndHook
   204  	OnSkippedBlock      SkippedBlockHook
   205  	OnGenesisBlock      GenesisBlockHook
   206  	OnSystemCallStart   OnSystemCallStartHook
   207  	OnSystemCallStartV2 OnSystemCallStartHookV2
   208  	OnSystemCallEnd     OnSystemCallEndHook
   209  	// State events
   210  	OnBalanceChange BalanceChangeHook
   211  	OnNonceChange   NonceChangeHook
   212  	OnNonceChangeV2 NonceChangeHookV2
   213  	OnCodeChange    CodeChangeHook
   214  	OnStorageChange StorageChangeHook
   215  	OnLog           LogHook
   216  	// Block hash read
   217  	OnBlockHashRead BlockHashReadHook
   218  }
   219  
   220  // BalanceChangeReason is used to indicate the reason for a balance change, useful
   221  // for tracing and reporting.
   222  type BalanceChangeReason byte
   223  
   224  //go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -trimprefix=BalanceChange -output gen_balance_change_reason_stringer.go
   225  
   226  const (
   227  	BalanceChangeUnspecified BalanceChangeReason = 0
   228  
   229  	// Issuance
   230  	// BalanceIncreaseRewardMineUncle is a reward for mining an uncle block.
   231  	BalanceIncreaseRewardMineUncle BalanceChangeReason = 1
   232  	// BalanceIncreaseRewardMineBlock is a reward for mining a block.
   233  	BalanceIncreaseRewardMineBlock BalanceChangeReason = 2
   234  	// BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain.
   235  	BalanceIncreaseWithdrawal BalanceChangeReason = 3
   236  	// BalanceIncreaseGenesisBalance is ether allocated at the genesis block.
   237  	BalanceIncreaseGenesisBalance BalanceChangeReason = 4
   238  
   239  	// Transaction fees
   240  	// BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance.
   241  	BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5
   242  	// BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction.
   243  	// Part of this gas will be burnt as per EIP-1559 rules.
   244  	BalanceDecreaseGasBuy BalanceChangeReason = 6
   245  	// BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution.
   246  	BalanceIncreaseGasReturn BalanceChangeReason = 7
   247  
   248  	// DAO fork
   249  	// BalanceIncreaseDaoContract is ether sent to the DAO refund contract.
   250  	BalanceIncreaseDaoContract BalanceChangeReason = 8
   251  	// BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract.
   252  	BalanceDecreaseDaoAccount BalanceChangeReason = 9
   253  
   254  	// BalanceChangeTransfer is ether transferred via a call.
   255  	// it is a decrease for the sender and an increase for the recipient.
   256  	BalanceChangeTransfer BalanceChangeReason = 10
   257  	// BalanceChangeTouchAccount is a transfer of zero value. It is only there to
   258  	// touch-create an account.
   259  	BalanceChangeTouchAccount BalanceChangeReason = 11
   260  
   261  	// BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account.
   262  	BalanceIncreaseSelfdestruct BalanceChangeReason = 12
   263  	// BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct.
   264  	BalanceDecreaseSelfdestruct BalanceChangeReason = 13
   265  	// BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed
   266  	// account within the same tx (captured at end of tx).
   267  	// Note it doesn't account for a self-destruct which appoints itself as recipient.
   268  	BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14
   269  
   270  	// BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure.
   271  	// It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
   272  	BalanceChangeRevert BalanceChangeReason = 15
   273  )
   274  
   275  // GasChangeReason is used to indicate the reason for a gas change, useful
   276  // for tracing and reporting.
   277  //
   278  // There is essentially two types of gas changes, those that can be emitted once per transaction
   279  // and those that can be emitted on a call basis, so possibly multiple times per transaction.
   280  //
   281  // They can be recognized easily by their name, those that start with `GasChangeTx` are emitted
   282  // once per transaction, while those that start with `GasChangeCall` are emitted on a call basis.
   283  type GasChangeReason byte
   284  
   285  //go:generate go run golang.org/x/tools/cmd/stringer -type=GasChangeReason -trimprefix=GasChange -output gen_gas_change_reason_stringer.go
   286  
   287  const (
   288  	GasChangeUnspecified GasChangeReason = 0
   289  
   290  	// GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
   291  	// one such gas change per transaction.
   292  	GasChangeTxInitialBalance GasChangeReason = 1
   293  	// GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is
   294  	// always exactly one of those per transaction.
   295  	GasChangeTxIntrinsicGas GasChangeReason = 2
   296  	// GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared)
   297  	// this generates an increase in gas. There is at most one of such gas change per transaction.
   298  	GasChangeTxRefunds GasChangeReason = 3
   299  	// GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned
   300  	// to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas
   301  	// left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller.
   302  	// There is at most one of such gas change per transaction.
   303  	GasChangeTxLeftOverReturned GasChangeReason = 4
   304  
   305  	// GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
   306  	// one such gas change per call.
   307  	GasChangeCallInitialBalance GasChangeReason = 5
   308  	// GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always
   309  	// be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even
   310  	// will be emitted.
   311  	GasChangeCallLeftOverReturned GasChangeReason = 6
   312  	// GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it
   313  	// executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child.
   314  	// If there was no gas left to be refunded, no such even will be emitted.
   315  	GasChangeCallLeftOverRefunded GasChangeReason = 7
   316  	// GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE.
   317  	GasChangeCallContractCreation GasChangeReason = 8
   318  	// GasChangeCallContractCreation2 is the amount of gas that will be burned for a CREATE2.
   319  	GasChangeCallContractCreation2 GasChangeReason = 9
   320  	// GasChangeCallCodeStorage is the amount of gas that will be charged for code storage.
   321  	GasChangeCallCodeStorage GasChangeReason = 10
   322  	// GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was
   323  	// performed can be check by `OnOpcode` handling.
   324  	GasChangeCallOpCode GasChangeReason = 11
   325  	// GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution.
   326  	GasChangeCallPrecompiledContract GasChangeReason = 12
   327  	// GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules.
   328  	GasChangeCallStorageColdAccess GasChangeReason = 13
   329  	// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
   330  	GasChangeCallFailedExecution GasChangeReason = 14
   331  	// GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step.
   332  	GasChangeWitnessContractInit GasChangeReason = 15
   333  	// GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step.
   334  	GasChangeWitnessContractCreation GasChangeReason = 16
   335  	// GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness.
   336  	GasChangeWitnessCodeChunk GasChangeReason = 17
   337  	// GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision.
   338  	GasChangeWitnessContractCollisionCheck GasChangeReason = 18
   339  	// GasChangeTxDataFloor is the amount of extra gas the transaction has to pay to reach the minimum gas requirement for the
   340  	// transaction data. This change will always be a negative change.
   341  	GasChangeTxDataFloor GasChangeReason = 19
   342  
   343  	// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
   344  	// it will be "manually" tracked by a direct emit of the gas change event.
   345  	GasChangeIgnored GasChangeReason = 0xFF
   346  )
   347  
   348  // NonceChangeReason is used to indicate the reason for a nonce change.
   349  type NonceChangeReason byte
   350  
   351  //go:generate go run golang.org/x/tools/cmd/stringer -type=NonceChangeReason -trimprefix NonceChange -output gen_nonce_change_reason_stringer.go
   352  
   353  const (
   354  	NonceChangeUnspecified NonceChangeReason = 0
   355  
   356  	// NonceChangeGenesis is the nonce allocated to accounts at genesis.
   357  	NonceChangeGenesis NonceChangeReason = 1
   358  
   359  	// NonceChangeEoACall is the nonce change due to an EoA call.
   360  	NonceChangeEoACall NonceChangeReason = 2
   361  
   362  	// NonceChangeContractCreator is the nonce change of an account creating a contract.
   363  	NonceChangeContractCreator NonceChangeReason = 3
   364  
   365  	// NonceChangeNewContract is the nonce change of a newly created contract.
   366  	NonceChangeNewContract NonceChangeReason = 4
   367  
   368  	// NonceChangeTransaction is the nonce change due to a EIP-7702 authorization.
   369  	NonceChangeAuthorization NonceChangeReason = 5
   370  
   371  	// NonceChangeRevert is emitted when the nonce is reverted back to a previous value due to call failure.
   372  	// It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
   373  	NonceChangeRevert NonceChangeReason = 6
   374  )