github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/core/state/journal.go (about) 1 // Copyright 2016 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 "maps" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/holiman/uint256" 24 ) 25 26 // journalEntry is a modification entry in the state change journal that can be 27 // reverted on demand. 28 type journalEntry interface { 29 // revert undoes the changes introduced by this journal entry. 30 revert(*StateDB) 31 32 // dirtied returns the Ethereum address modified by this journal entry. 33 dirtied() *common.Address 34 35 // copy returns a deep-copied journal entry. 36 copy() journalEntry 37 } 38 39 // journal contains the list of state modifications applied since the last state 40 // commit. These are tracked to be able to be reverted in the case of an execution 41 // exception or request for reversal. 42 type journal struct { 43 entries []journalEntry // Current changes tracked by the journal 44 dirties map[common.Address]int // Dirty accounts and the number of changes 45 } 46 47 // newJournal creates a new initialized journal. 48 func newJournal() *journal { 49 return &journal{ 50 dirties: make(map[common.Address]int), 51 } 52 } 53 54 // append inserts a new modification entry to the end of the change journal. 55 func (j *journal) append(entry journalEntry) { 56 j.entries = append(j.entries, entry) 57 if addr := entry.dirtied(); addr != nil { 58 j.dirties[*addr]++ 59 } 60 } 61 62 // revert undoes a batch of journalled modifications along with any reverted 63 // dirty handling too. 64 func (j *journal) revert(statedb *StateDB, snapshot int) { 65 for i := len(j.entries) - 1; i >= snapshot; i-- { 66 // Undo the changes made by the operation 67 j.entries[i].revert(statedb) 68 69 // Drop any dirty tracking induced by the change 70 if addr := j.entries[i].dirtied(); addr != nil { 71 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 72 delete(j.dirties, *addr) 73 } 74 } 75 } 76 j.entries = j.entries[:snapshot] 77 } 78 79 // dirty explicitly sets an address to dirty, even if the change entries would 80 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 81 // precompile consensus exception. 82 func (j *journal) dirty(addr common.Address) { 83 j.dirties[addr]++ 84 } 85 86 // length returns the current number of entries in the journal. 87 func (j *journal) length() int { 88 return len(j.entries) 89 } 90 91 // copy returns a deep-copied journal. 92 func (j *journal) copy() *journal { 93 entries := make([]journalEntry, 0, j.length()) 94 for i := 0; i < j.length(); i++ { 95 entries = append(entries, j.entries[i].copy()) 96 } 97 return &journal{ 98 entries: entries, 99 dirties: maps.Clone(j.dirties), 100 } 101 } 102 103 type ( 104 // Changes to the account trie. 105 createObjectChange struct { 106 account *common.Address 107 } 108 109 // createContractChange represents an account becoming a contract-account. 110 // This event happens prior to executing initcode. The journal-event simply 111 // manages the created-flag, in order to allow same-tx destruction. 112 createContractChange struct { 113 account common.Address 114 } 115 116 selfDestructChange struct { 117 account *common.Address 118 prev bool // whether account had already self-destructed 119 prevbalance *uint256.Int 120 } 121 122 // Changes to individual accounts. 123 balanceChange struct { 124 account *common.Address 125 prev *uint256.Int 126 } 127 nonceChange struct { 128 account *common.Address 129 prev uint64 130 } 131 storageChange struct { 132 account *common.Address 133 key common.Hash 134 prevvalue common.Hash 135 origvalue common.Hash 136 } 137 codeChange struct { 138 account *common.Address 139 prevcode, prevhash []byte 140 } 141 142 // Changes to other state values. 143 refundChange struct { 144 prev uint64 145 } 146 addLogChange struct { 147 txhash common.Hash 148 } 149 addPreimageChange struct { 150 hash common.Hash 151 } 152 touchChange struct { 153 account *common.Address 154 } 155 156 // Changes to the access list 157 accessListAddAccountChange struct { 158 address *common.Address 159 } 160 accessListAddSlotChange struct { 161 address *common.Address 162 slot *common.Hash 163 } 164 165 // Changes to transient storage 166 transientStorageChange struct { 167 account *common.Address 168 key, prevalue common.Hash 169 } 170 ) 171 172 func (ch createObjectChange) revert(s *StateDB) { 173 delete(s.stateObjects, *ch.account) 174 } 175 176 func (ch createObjectChange) dirtied() *common.Address { 177 return ch.account 178 } 179 180 func (ch createObjectChange) copy() journalEntry { 181 return createObjectChange{ 182 account: ch.account, 183 } 184 } 185 186 func (ch createContractChange) revert(s *StateDB) { 187 s.getStateObject(ch.account).newContract = false 188 } 189 190 func (ch createContractChange) dirtied() *common.Address { 191 return nil 192 } 193 194 func (ch createContractChange) copy() journalEntry { 195 return createContractChange{ 196 account: ch.account, 197 } 198 } 199 200 func (ch selfDestructChange) revert(s *StateDB) { 201 obj := s.getStateObject(*ch.account) 202 if obj != nil { 203 obj.selfDestructed = ch.prev 204 obj.setBalance(ch.prevbalance) 205 } 206 } 207 208 func (ch selfDestructChange) dirtied() *common.Address { 209 return ch.account 210 } 211 212 func (ch selfDestructChange) copy() journalEntry { 213 return selfDestructChange{ 214 account: ch.account, 215 prev: ch.prev, 216 prevbalance: new(uint256.Int).Set(ch.prevbalance), 217 } 218 } 219 220 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 221 222 func (ch touchChange) revert(s *StateDB) { 223 } 224 225 func (ch touchChange) dirtied() *common.Address { 226 return ch.account 227 } 228 229 func (ch touchChange) copy() journalEntry { 230 return touchChange{ 231 account: ch.account, 232 } 233 } 234 235 func (ch balanceChange) revert(s *StateDB) { 236 s.getStateObject(*ch.account).setBalance(ch.prev) 237 } 238 239 func (ch balanceChange) dirtied() *common.Address { 240 return ch.account 241 } 242 243 func (ch balanceChange) copy() journalEntry { 244 return balanceChange{ 245 account: ch.account, 246 prev: new(uint256.Int).Set(ch.prev), 247 } 248 } 249 250 func (ch nonceChange) revert(s *StateDB) { 251 s.getStateObject(*ch.account).setNonce(ch.prev) 252 } 253 254 func (ch nonceChange) dirtied() *common.Address { 255 return ch.account 256 } 257 258 func (ch nonceChange) copy() journalEntry { 259 return nonceChange{ 260 account: ch.account, 261 prev: ch.prev, 262 } 263 } 264 265 func (ch codeChange) revert(s *StateDB) { 266 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 267 } 268 269 func (ch codeChange) dirtied() *common.Address { 270 return ch.account 271 } 272 273 func (ch codeChange) copy() journalEntry { 274 return codeChange{ 275 account: ch.account, 276 prevhash: common.CopyBytes(ch.prevhash), 277 prevcode: common.CopyBytes(ch.prevcode), 278 } 279 } 280 281 func (ch storageChange) revert(s *StateDB) { 282 s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue) 283 } 284 285 func (ch storageChange) dirtied() *common.Address { 286 return ch.account 287 } 288 289 func (ch storageChange) copy() journalEntry { 290 return storageChange{ 291 account: ch.account, 292 key: ch.key, 293 prevvalue: ch.prevvalue, 294 } 295 } 296 297 func (ch transientStorageChange) revert(s *StateDB) { 298 s.setTransientState(*ch.account, ch.key, ch.prevalue) 299 } 300 301 func (ch transientStorageChange) dirtied() *common.Address { 302 return nil 303 } 304 305 func (ch transientStorageChange) copy() journalEntry { 306 return transientStorageChange{ 307 account: ch.account, 308 key: ch.key, 309 prevalue: ch.prevalue, 310 } 311 } 312 313 func (ch refundChange) revert(s *StateDB) { 314 s.refund = ch.prev 315 } 316 317 func (ch refundChange) dirtied() *common.Address { 318 return nil 319 } 320 321 func (ch refundChange) copy() journalEntry { 322 return refundChange{ 323 prev: ch.prev, 324 } 325 } 326 327 func (ch addLogChange) revert(s *StateDB) { 328 logs := s.logs[ch.txhash] 329 if len(logs) == 1 { 330 delete(s.logs, ch.txhash) 331 } else { 332 s.logs[ch.txhash] = logs[:len(logs)-1] 333 } 334 s.logSize-- 335 } 336 337 func (ch addLogChange) dirtied() *common.Address { 338 return nil 339 } 340 341 func (ch addLogChange) copy() journalEntry { 342 return addLogChange{ 343 txhash: ch.txhash, 344 } 345 } 346 347 func (ch addPreimageChange) revert(s *StateDB) { 348 delete(s.preimages, ch.hash) 349 } 350 351 func (ch addPreimageChange) dirtied() *common.Address { 352 return nil 353 } 354 355 func (ch addPreimageChange) copy() journalEntry { 356 return addPreimageChange{ 357 hash: ch.hash, 358 } 359 } 360 361 func (ch accessListAddAccountChange) revert(s *StateDB) { 362 /* 363 One important invariant here, is that whenever a (addr, slot) is added, if the 364 addr is not already present, the add causes two journal entries: 365 - one for the address, 366 - one for the (address,slot) 367 Therefore, when unrolling the change, we can always blindly delete the 368 (addr) at this point, since no storage adds can remain when come upon 369 a single (addr) change. 370 */ 371 s.accessList.DeleteAddress(*ch.address) 372 } 373 374 func (ch accessListAddAccountChange) dirtied() *common.Address { 375 return nil 376 } 377 378 func (ch accessListAddAccountChange) copy() journalEntry { 379 return accessListAddAccountChange{ 380 address: ch.address, 381 } 382 } 383 384 func (ch accessListAddSlotChange) revert(s *StateDB) { 385 s.accessList.DeleteSlot(*ch.address, *ch.slot) 386 } 387 388 func (ch accessListAddSlotChange) dirtied() *common.Address { 389 return nil 390 } 391 392 func (ch accessListAddSlotChange) copy() journalEntry { 393 return accessListAddSlotChange{ 394 address: ch.address, 395 slot: ch.slot, 396 } 397 }