github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/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
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  	"github.com/ethereum/go-ethereum/params"
    25  	"github.com/holiman/uint256"
    26  )
    27  
    28  // OpContext provides the context at which the opcode is being
    29  // executed in, including the memory, stack and various contract-level information.
    30  type OpContext interface {
    31  	MemoryData() []byte
    32  	StackData() []uint256.Int
    33  	Caller() common.Address
    34  	Address() common.Address
    35  	CallValue() *uint256.Int
    36  	CallInput() []byte
    37  }
    38  
    39  // StateDB gives tracers access to the whole state.
    40  type StateDB interface {
    41  	GetBalance(common.Address) *uint256.Int
    42  	GetNonce(common.Address) uint64
    43  	GetCode(common.Address) []byte
    44  	GetState(common.Address, common.Hash) common.Hash
    45  	Exist(common.Address) bool
    46  	GetRefund() uint64
    47  }
    48  
    49  // VMContext provides the context for the EVM execution.
    50  type VMContext struct {
    51  	Coinbase    common.Address
    52  	BlockNumber *big.Int
    53  	Time        uint64
    54  	Random      *common.Hash
    55  	// Effective tx gas price
    56  	GasPrice    *big.Int
    57  	ChainConfig *params.ChainConfig
    58  	StateDB     StateDB
    59  }
    60  
    61  // BlockEvent is emitted upon tracing an incoming block.
    62  // It contains the block as well as consensus related information.
    63  type BlockEvent struct {
    64  	Block     *types.Block
    65  	TD        *big.Int
    66  	Finalized *types.Header
    67  	Safe      *types.Header
    68  }
    69  
    70  type (
    71  	/*
    72  		- VM events -
    73  	*/
    74  
    75  	// TxStartHook is called before the execution of a transaction starts.
    76  	// Call simulations don't come with a valid signature. `from` field
    77  	// to be used for address of the caller.
    78  	TxStartHook = func(vm *VMContext, tx *types.Transaction, from common.Address)
    79  
    80  	// TxEndHook is called after the execution of a transaction ends.
    81  	TxEndHook = func(receipt *types.Receipt, err error)
    82  
    83  	// EnterHook is invoked when the processing of a message starts.
    84  	//
    85  	// Take note that EnterHook, when in the context of a live tracer, can be invoked
    86  	// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
    87  	// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
    88  	EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
    89  
    90  	// ExitHook is invoked when the processing of a message ends.
    91  	// `revert` is true when there was an error during the execution.
    92  	// Exceptionally, before the homestead hardfork a contract creation that
    93  	// ran out of gas when attempting to persist the code to database did not
    94  	// count as a call failure and did not cause a revert of the call. This will
    95  	// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
    96  	//
    97  	// Take note that ExitHook, when in the context of a live tracer, can be invoked
    98  	// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
    99  	// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
   100  	ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
   101  
   102  	// OpcodeHook is invoked just prior to the execution of an opcode.
   103  	OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error)
   104  
   105  	// FaultHook is invoked when an error occurs during the execution of an opcode.
   106  	FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error)
   107  
   108  	// GasChangeHook is invoked when the gas changes.
   109  	GasChangeHook = func(old, new uint64, reason GasChangeReason)
   110  
   111  	/*
   112  		- Chain events -
   113  	*/
   114  
   115  	// BlockchainInitHook is called when the blockchain is initialized.
   116  	BlockchainInitHook = func(chainConfig *params.ChainConfig)
   117  
   118  	// CloseHook is called when the blockchain closes.
   119  	CloseHook = func()
   120  
   121  	// BlockStartHook is called before executing `block`.
   122  	// `td` is the total difficulty prior to `block`.
   123  	BlockStartHook = func(event BlockEvent)
   124  
   125  	// BlockEndHook is called after executing a block.
   126  	BlockEndHook = func(err error)
   127  
   128  	// SkippedBlockHook indicates a block was skipped during processing
   129  	// due to it being known previously. This can happen e.g. when recovering
   130  	// from a crash.
   131  	SkippedBlockHook = func(event BlockEvent)
   132  
   133  	// GenesisBlockHook is called when the genesis block is being processed.
   134  	GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc)
   135  
   136  	// OnSystemCallStartHook is called when a system call is about to be executed. Today,
   137  	// this hook is invoked when the EIP-4788 system call is about to be executed to set the
   138  	// beacon block root.
   139  	//
   140  	// After this hook, the EVM call tracing will happened as usual so you will receive a `OnEnter/OnExit`
   141  	// as well as state hooks between this hook and the `OnSystemCallEndHook`.
   142  	//
   143  	// Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks
   144  	// will not be invoked.
   145  	OnSystemCallStartHook = func()
   146  
   147  	// OnSystemCallEndHook is called when a system call has finished executing. Today,
   148  	// this hook is invoked when the EIP-4788 system call is about to be executed to set the
   149  	// beacon block root.
   150  	OnSystemCallEndHook = func()
   151  
   152  	/*
   153  		- State events -
   154  	*/
   155  
   156  	// BalanceChangeHook is called when the balance of an account changes.
   157  	BalanceChangeHook = func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason)
   158  
   159  	// NonceChangeHook is called when the nonce of an account changes.
   160  	NonceChangeHook = func(addr common.Address, prev, new uint64)
   161  
   162  	// CodeChangeHook is called when the code of an account changes.
   163  	CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)
   164  
   165  	// StorageChangeHook is called when the storage of an account changes.
   166  	StorageChangeHook = func(addr common.Address, slot common.Hash, prev, new common.Hash)
   167  
   168  	// LogHook is called when a log is emitted.
   169  	LogHook = func(log *types.Log)
   170  )
   171  
   172  type Hooks struct {
   173  	// VM events
   174  	OnTxStart   TxStartHook
   175  	OnTxEnd     TxEndHook
   176  	OnEnter     EnterHook
   177  	OnExit      ExitHook
   178  	OnOpcode    OpcodeHook
   179  	OnFault     FaultHook
   180  	OnGasChange GasChangeHook
   181  	// Chain events
   182  	OnBlockchainInit  BlockchainInitHook
   183  	OnClose           CloseHook
   184  	OnBlockStart      BlockStartHook
   185  	OnBlockEnd        BlockEndHook
   186  	OnSkippedBlock    SkippedBlockHook
   187  	OnGenesisBlock    GenesisBlockHook
   188  	OnSystemCallStart OnSystemCallStartHook
   189  	OnSystemCallEnd   OnSystemCallEndHook
   190  	// State events
   191  	OnBalanceChange BalanceChangeHook
   192  	OnNonceChange   NonceChangeHook
   193  	OnCodeChange    CodeChangeHook
   194  	OnStorageChange StorageChangeHook
   195  	OnLog           LogHook
   196  }
   197  
   198  // BalanceChangeReason is used to indicate the reason for a balance change, useful
   199  // for tracing and reporting.
   200  type BalanceChangeReason byte
   201  
   202  const (
   203  	BalanceChangeUnspecified BalanceChangeReason = 0
   204  
   205  	// Issuance
   206  	// BalanceIncreaseRewardMineUncle is a reward for mining an uncle block.
   207  	BalanceIncreaseRewardMineUncle BalanceChangeReason = 1
   208  	// BalanceIncreaseRewardMineBlock is a reward for mining a block.
   209  	BalanceIncreaseRewardMineBlock BalanceChangeReason = 2
   210  	// BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain.
   211  	BalanceIncreaseWithdrawal BalanceChangeReason = 3
   212  	// BalanceIncreaseGenesisBalance is ether allocated at the genesis block.
   213  	BalanceIncreaseGenesisBalance BalanceChangeReason = 4
   214  
   215  	// Transaction fees
   216  	// BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance.
   217  	BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5
   218  	// BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction.
   219  	// Part of this gas will be burnt as per EIP-1559 rules.
   220  	BalanceDecreaseGasBuy BalanceChangeReason = 6
   221  	// BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution.
   222  	BalanceIncreaseGasReturn BalanceChangeReason = 7
   223  
   224  	// DAO fork
   225  	// BalanceIncreaseDaoContract is ether sent to the DAO refund contract.
   226  	BalanceIncreaseDaoContract BalanceChangeReason = 8
   227  	// BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract.
   228  	BalanceDecreaseDaoAccount BalanceChangeReason = 9
   229  
   230  	// BalanceChangeTransfer is ether transferred via a call.
   231  	// it is a decrease for the sender and an increase for the recipient.
   232  	BalanceChangeTransfer BalanceChangeReason = 10
   233  	// BalanceChangeTouchAccount is a transfer of zero value. It is only there to
   234  	// touch-create an account.
   235  	BalanceChangeTouchAccount BalanceChangeReason = 11
   236  
   237  	// BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account.
   238  	BalanceIncreaseSelfdestruct BalanceChangeReason = 12
   239  	// BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct.
   240  	BalanceDecreaseSelfdestruct BalanceChangeReason = 13
   241  	// BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed
   242  	// account within the same tx (captured at end of tx).
   243  	// Note it doesn't account for a self-destruct which appoints itself as recipient.
   244  	BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14
   245  )
   246  
   247  // GasChangeReason is used to indicate the reason for a gas change, useful
   248  // for tracing and reporting.
   249  //
   250  // There is essentially two types of gas changes, those that can be emitted once per transaction
   251  // and those that can be emitted on a call basis, so possibly multiple times per transaction.
   252  //
   253  // They can be recognized easily by their name, those that start with `GasChangeTx` are emitted
   254  // once per transaction, while those that start with `GasChangeCall` are emitted on a call basis.
   255  type GasChangeReason byte
   256  
   257  const (
   258  	GasChangeUnspecified GasChangeReason = 0
   259  
   260  	// GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
   261  	// one such gas change per transaction.
   262  	GasChangeTxInitialBalance GasChangeReason = 1
   263  	// GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is
   264  	// always exactly one of those per transaction.
   265  	GasChangeTxIntrinsicGas GasChangeReason = 2
   266  	// GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared)
   267  	// this generates an increase in gas. There is at most one of such gas change per transaction.
   268  	GasChangeTxRefunds GasChangeReason = 3
   269  	// GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned
   270  	// to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas
   271  	// left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller.
   272  	// There is at most one of such gas change per transaction.
   273  	GasChangeTxLeftOverReturned GasChangeReason = 4
   274  
   275  	// GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
   276  	// one such gas change per call.
   277  	GasChangeCallInitialBalance GasChangeReason = 5
   278  	// GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always
   279  	// 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
   280  	// will be emitted.
   281  	GasChangeCallLeftOverReturned GasChangeReason = 6
   282  	// GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it
   283  	// executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child.
   284  	// If there was no gas left to be refunded, no such even will be emitted.
   285  	GasChangeCallLeftOverRefunded GasChangeReason = 7
   286  	// GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE.
   287  	GasChangeCallContractCreation GasChangeReason = 8
   288  	// GasChangeContractCreation is the amount of gas that will be burned for a CREATE2.
   289  	GasChangeCallContractCreation2 GasChangeReason = 9
   290  	// GasChangeCallCodeStorage is the amount of gas that will be charged for code storage.
   291  	GasChangeCallCodeStorage GasChangeReason = 10
   292  	// GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was
   293  	// performed can be check by `OnOpcode` handling.
   294  	GasChangeCallOpCode GasChangeReason = 11
   295  	// GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution.
   296  	GasChangeCallPrecompiledContract GasChangeReason = 12
   297  	// GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules.
   298  	GasChangeCallStorageColdAccess GasChangeReason = 13
   299  	// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
   300  	GasChangeCallFailedExecution GasChangeReason = 14
   301  	// GasChangeWitnessContractInit is the amount charged for adding to the witness during the contract creation initialization step
   302  	GasChangeWitnessContractInit GasChangeReason = 15
   303  	// GasChangeWitnessContractCreation is the amount charged for adding to the witness during the contract creation finalization step
   304  	GasChangeWitnessContractCreation GasChangeReason = 16
   305  	// GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks
   306  	GasChangeWitnessCodeChunk GasChangeReason = 17
   307  
   308  	// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
   309  	// it will be "manually" tracked by a direct emit of the gas change event.
   310  	GasChangeIgnored GasChangeReason = 0xFF
   311  )