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 }