github.com/ethereum/go-ethereum@v1.16.1/core/state/statedb_hooked.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 state
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/stateless"
    24  	"github.com/ethereum/go-ethereum/core/tracing"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  	"github.com/ethereum/go-ethereum/params"
    28  	"github.com/ethereum/go-ethereum/trie/utils"
    29  	"github.com/holiman/uint256"
    30  )
    31  
    32  // hookedStateDB represents a statedb which emits calls to tracing-hooks
    33  // on state operations.
    34  type hookedStateDB struct {
    35  	inner *StateDB
    36  	hooks *tracing.Hooks
    37  }
    38  
    39  // NewHookedState wraps the given stateDb with the given hooks
    40  func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB {
    41  	s := &hookedStateDB{stateDb, hooks}
    42  	if s.hooks == nil {
    43  		s.hooks = new(tracing.Hooks)
    44  	}
    45  	return s
    46  }
    47  
    48  func (s *hookedStateDB) CreateAccount(addr common.Address) {
    49  	s.inner.CreateAccount(addr)
    50  }
    51  
    52  func (s *hookedStateDB) CreateContract(addr common.Address) {
    53  	s.inner.CreateContract(addr)
    54  }
    55  
    56  func (s *hookedStateDB) GetBalance(addr common.Address) *uint256.Int {
    57  	return s.inner.GetBalance(addr)
    58  }
    59  
    60  func (s *hookedStateDB) GetNonce(addr common.Address) uint64 {
    61  	return s.inner.GetNonce(addr)
    62  }
    63  
    64  func (s *hookedStateDB) GetCodeHash(addr common.Address) common.Hash {
    65  	return s.inner.GetCodeHash(addr)
    66  }
    67  
    68  func (s *hookedStateDB) GetCode(addr common.Address) []byte {
    69  	return s.inner.GetCode(addr)
    70  }
    71  
    72  func (s *hookedStateDB) GetCodeSize(addr common.Address) int {
    73  	return s.inner.GetCodeSize(addr)
    74  }
    75  
    76  func (s *hookedStateDB) AddRefund(u uint64) {
    77  	s.inner.AddRefund(u)
    78  }
    79  
    80  func (s *hookedStateDB) SubRefund(u uint64) {
    81  	s.inner.SubRefund(u)
    82  }
    83  
    84  func (s *hookedStateDB) GetRefund() uint64 {
    85  	return s.inner.GetRefund()
    86  }
    87  
    88  func (s *hookedStateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
    89  	return s.inner.GetCommittedState(addr, hash)
    90  }
    91  
    92  func (s *hookedStateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
    93  	return s.inner.GetState(addr, hash)
    94  }
    95  
    96  func (s *hookedStateDB) GetStorageRoot(addr common.Address) common.Hash {
    97  	return s.inner.GetStorageRoot(addr)
    98  }
    99  
   100  func (s *hookedStateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
   101  	return s.inner.GetTransientState(addr, key)
   102  }
   103  
   104  func (s *hookedStateDB) SetTransientState(addr common.Address, key, value common.Hash) {
   105  	s.inner.SetTransientState(addr, key, value)
   106  }
   107  
   108  func (s *hookedStateDB) HasSelfDestructed(addr common.Address) bool {
   109  	return s.inner.HasSelfDestructed(addr)
   110  }
   111  
   112  func (s *hookedStateDB) Exist(addr common.Address) bool {
   113  	return s.inner.Exist(addr)
   114  }
   115  
   116  func (s *hookedStateDB) Empty(addr common.Address) bool {
   117  	return s.inner.Empty(addr)
   118  }
   119  
   120  func (s *hookedStateDB) AddressInAccessList(addr common.Address) bool {
   121  	return s.inner.AddressInAccessList(addr)
   122  }
   123  
   124  func (s *hookedStateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) {
   125  	return s.inner.SlotInAccessList(addr, slot)
   126  }
   127  
   128  func (s *hookedStateDB) AddAddressToAccessList(addr common.Address) {
   129  	s.inner.AddAddressToAccessList(addr)
   130  }
   131  
   132  func (s *hookedStateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
   133  	s.inner.AddSlotToAccessList(addr, slot)
   134  }
   135  
   136  func (s *hookedStateDB) PointCache() *utils.PointCache {
   137  	return s.inner.PointCache()
   138  }
   139  
   140  func (s *hookedStateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) {
   141  	s.inner.Prepare(rules, sender, coinbase, dest, precompiles, txAccesses)
   142  }
   143  
   144  func (s *hookedStateDB) RevertToSnapshot(i int) {
   145  	s.inner.RevertToSnapshot(i)
   146  }
   147  
   148  func (s *hookedStateDB) Snapshot() int {
   149  	return s.inner.Snapshot()
   150  }
   151  
   152  func (s *hookedStateDB) AddPreimage(hash common.Hash, bytes []byte) {
   153  	s.inner.AddPreimage(hash, bytes)
   154  }
   155  
   156  func (s *hookedStateDB) Witness() *stateless.Witness {
   157  	return s.inner.Witness()
   158  }
   159  
   160  func (s *hookedStateDB) AccessEvents() *AccessEvents {
   161  	return s.inner.AccessEvents()
   162  }
   163  
   164  func (s *hookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
   165  	prev := s.inner.SubBalance(addr, amount, reason)
   166  	if s.hooks.OnBalanceChange != nil && !amount.IsZero() {
   167  		newBalance := new(uint256.Int).Sub(&prev, amount)
   168  		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
   169  	}
   170  	return prev
   171  }
   172  
   173  func (s *hookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
   174  	prev := s.inner.AddBalance(addr, amount, reason)
   175  	if s.hooks.OnBalanceChange != nil && !amount.IsZero() {
   176  		newBalance := new(uint256.Int).Add(&prev, amount)
   177  		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
   178  	}
   179  	return prev
   180  }
   181  
   182  func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64, reason tracing.NonceChangeReason) {
   183  	prev := s.inner.GetNonce(address)
   184  	s.inner.SetNonce(address, nonce, reason)
   185  	if s.hooks.OnNonceChangeV2 != nil {
   186  		s.hooks.OnNonceChangeV2(address, prev, nonce, reason)
   187  	} else if s.hooks.OnNonceChange != nil {
   188  		s.hooks.OnNonceChange(address, prev, nonce)
   189  	}
   190  }
   191  
   192  func (s *hookedStateDB) SetCode(address common.Address, code []byte) []byte {
   193  	prev := s.inner.SetCode(address, code)
   194  	if s.hooks.OnCodeChange != nil {
   195  		prevHash := types.EmptyCodeHash
   196  		if len(prev) != 0 {
   197  			prevHash = crypto.Keccak256Hash(prev)
   198  		}
   199  		s.hooks.OnCodeChange(address, prevHash, prev, crypto.Keccak256Hash(code), code)
   200  	}
   201  	return prev
   202  }
   203  
   204  func (s *hookedStateDB) SetState(address common.Address, key common.Hash, value common.Hash) common.Hash {
   205  	prev := s.inner.SetState(address, key, value)
   206  	if s.hooks.OnStorageChange != nil && prev != value {
   207  		s.hooks.OnStorageChange(address, key, prev, value)
   208  	}
   209  	return prev
   210  }
   211  
   212  func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int {
   213  	var prevCode []byte
   214  	var prevCodeHash common.Hash
   215  
   216  	if s.hooks.OnCodeChange != nil {
   217  		prevCode = s.inner.GetCode(address)
   218  		prevCodeHash = s.inner.GetCodeHash(address)
   219  	}
   220  
   221  	prev := s.inner.SelfDestruct(address)
   222  
   223  	if s.hooks.OnBalanceChange != nil && !prev.IsZero() {
   224  		s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
   225  	}
   226  
   227  	if s.hooks.OnCodeChange != nil && len(prevCode) > 0 {
   228  		s.hooks.OnCodeChange(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil)
   229  	}
   230  
   231  	return prev
   232  }
   233  
   234  func (s *hookedStateDB) SelfDestruct6780(address common.Address) (uint256.Int, bool) {
   235  	var prevCode []byte
   236  	var prevCodeHash common.Hash
   237  
   238  	if s.hooks.OnCodeChange != nil {
   239  		prevCodeHash = s.inner.GetCodeHash(address)
   240  		prevCode = s.inner.GetCode(address)
   241  	}
   242  
   243  	prev, changed := s.inner.SelfDestruct6780(address)
   244  
   245  	if s.hooks.OnBalanceChange != nil && changed && !prev.IsZero() {
   246  		s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
   247  	}
   248  
   249  	if s.hooks.OnCodeChange != nil && changed && len(prevCode) > 0 {
   250  		s.hooks.OnCodeChange(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil)
   251  	}
   252  
   253  	return prev, changed
   254  }
   255  
   256  func (s *hookedStateDB) AddLog(log *types.Log) {
   257  	// The inner will modify the log (add fields), so invoke that first
   258  	s.inner.AddLog(log)
   259  	if s.hooks.OnLog != nil {
   260  		s.hooks.OnLog(log)
   261  	}
   262  }
   263  
   264  func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) {
   265  	defer s.inner.Finalise(deleteEmptyObjects)
   266  	if s.hooks.OnBalanceChange == nil {
   267  		return
   268  	}
   269  	for addr := range s.inner.journal.dirties {
   270  		obj := s.inner.stateObjects[addr]
   271  		if obj != nil && obj.selfDestructed {
   272  			// If ether was sent to account post-selfdestruct it is burnt.
   273  			if bal := obj.Balance(); bal.Sign() != 0 {
   274  				s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
   275  			}
   276  		}
   277  	}
   278  }