github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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 } 136 codeChange struct { 137 account *common.Address 138 prevcode, prevhash []byte 139 } 140 141 // Changes to other state values. 142 refundChange struct { 143 prev uint64 144 } 145 addLogChange struct { 146 txhash common.Hash 147 } 148 addPreimageChange struct { 149 hash common.Hash 150 } 151 touchChange struct { 152 account *common.Address 153 } 154 155 // Changes to the access list 156 accessListAddAccountChange struct { 157 address *common.Address 158 } 159 accessListAddSlotChange struct { 160 address *common.Address 161 slot *common.Hash 162 } 163 164 // Changes to transient storage 165 transientStorageChange struct { 166 account *common.Address 167 key, prevalue common.Hash 168 } 169 ) 170 171 func (ch createObjectChange) revert(s *StateDB) { 172 delete(s.stateObjects, *ch.account) 173 } 174 175 func (ch createObjectChange) dirtied() *common.Address { 176 return ch.account 177 } 178 179 func (ch createObjectChange) copy() journalEntry { 180 return createObjectChange{ 181 account: ch.account, 182 } 183 } 184 185 func (ch createContractChange) revert(s *StateDB) { 186 s.getStateObject(ch.account).newContract = false 187 } 188 189 func (ch createContractChange) dirtied() *common.Address { 190 return nil 191 } 192 193 func (ch createContractChange) copy() journalEntry { 194 return createContractChange{ 195 account: ch.account, 196 } 197 } 198 199 func (ch selfDestructChange) revert(s *StateDB) { 200 obj := s.getStateObject(*ch.account) 201 if obj != nil { 202 obj.selfDestructed = ch.prev 203 obj.setBalance(ch.prevbalance) 204 } 205 } 206 207 func (ch selfDestructChange) dirtied() *common.Address { 208 return ch.account 209 } 210 211 func (ch selfDestructChange) copy() journalEntry { 212 return selfDestructChange{ 213 account: ch.account, 214 prev: ch.prev, 215 prevbalance: new(uint256.Int).Set(ch.prevbalance), 216 } 217 } 218 219 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 220 221 func (ch touchChange) revert(s *StateDB) { 222 } 223 224 func (ch touchChange) dirtied() *common.Address { 225 return ch.account 226 } 227 228 func (ch touchChange) copy() journalEntry { 229 return touchChange{ 230 account: ch.account, 231 } 232 } 233 234 func (ch balanceChange) revert(s *StateDB) { 235 s.getStateObject(*ch.account).setBalance(ch.prev) 236 } 237 238 func (ch balanceChange) dirtied() *common.Address { 239 return ch.account 240 } 241 242 func (ch balanceChange) copy() journalEntry { 243 return balanceChange{ 244 account: ch.account, 245 prev: new(uint256.Int).Set(ch.prev), 246 } 247 } 248 249 func (ch nonceChange) revert(s *StateDB) { 250 s.getStateObject(*ch.account).setNonce(ch.prev) 251 } 252 253 func (ch nonceChange) dirtied() *common.Address { 254 return ch.account 255 } 256 257 func (ch nonceChange) copy() journalEntry { 258 return nonceChange{ 259 account: ch.account, 260 prev: ch.prev, 261 } 262 } 263 264 func (ch codeChange) revert(s *StateDB) { 265 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 266 } 267 268 func (ch codeChange) dirtied() *common.Address { 269 return ch.account 270 } 271 272 func (ch codeChange) copy() journalEntry { 273 return codeChange{ 274 account: ch.account, 275 prevhash: common.CopyBytes(ch.prevhash), 276 prevcode: common.CopyBytes(ch.prevcode), 277 } 278 } 279 280 func (ch storageChange) revert(s *StateDB) { 281 s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue) 282 } 283 284 func (ch storageChange) dirtied() *common.Address { 285 return ch.account 286 } 287 288 func (ch storageChange) copy() journalEntry { 289 return storageChange{ 290 account: ch.account, 291 key: ch.key, 292 prevvalue: ch.prevvalue, 293 } 294 } 295 296 func (ch transientStorageChange) revert(s *StateDB) { 297 s.setTransientState(*ch.account, ch.key, ch.prevalue) 298 } 299 300 func (ch transientStorageChange) dirtied() *common.Address { 301 return nil 302 } 303 304 func (ch transientStorageChange) copy() journalEntry { 305 return transientStorageChange{ 306 account: ch.account, 307 key: ch.key, 308 prevalue: ch.prevalue, 309 } 310 } 311 312 func (ch refundChange) revert(s *StateDB) { 313 s.refund = ch.prev 314 } 315 316 func (ch refundChange) dirtied() *common.Address { 317 return nil 318 } 319 320 func (ch refundChange) copy() journalEntry { 321 return refundChange{ 322 prev: ch.prev, 323 } 324 } 325 326 func (ch addLogChange) revert(s *StateDB) { 327 logs := s.logs[ch.txhash] 328 if len(logs) == 1 { 329 delete(s.logs, ch.txhash) 330 } else { 331 s.logs[ch.txhash] = logs[:len(logs)-1] 332 } 333 s.logSize-- 334 } 335 336 func (ch addLogChange) dirtied() *common.Address { 337 return nil 338 } 339 340 func (ch addLogChange) copy() journalEntry { 341 return addLogChange{ 342 txhash: ch.txhash, 343 } 344 } 345 346 func (ch addPreimageChange) revert(s *StateDB) { 347 delete(s.preimages, ch.hash) 348 } 349 350 func (ch addPreimageChange) dirtied() *common.Address { 351 return nil 352 } 353 354 func (ch addPreimageChange) copy() journalEntry { 355 return addPreimageChange{ 356 hash: ch.hash, 357 } 358 } 359 360 func (ch accessListAddAccountChange) revert(s *StateDB) { 361 /* 362 One important invariant here, is that whenever a (addr, slot) is added, if the 363 addr is not already present, the add causes two journal entries: 364 - one for the address, 365 - one for the (address,slot) 366 Therefore, when unrolling the change, we can always blindly delete the 367 (addr) at this point, since no storage adds can remain when come upon 368 a single (addr) change. 369 */ 370 s.accessList.DeleteAddress(*ch.address) 371 } 372 373 func (ch accessListAddAccountChange) dirtied() *common.Address { 374 return nil 375 } 376 377 func (ch accessListAddAccountChange) copy() journalEntry { 378 return accessListAddAccountChange{ 379 address: ch.address, 380 } 381 } 382 383 func (ch accessListAddSlotChange) revert(s *StateDB) { 384 s.accessList.DeleteSlot(*ch.address, *ch.slot) 385 } 386 387 func (ch accessListAddSlotChange) dirtied() *common.Address { 388 return nil 389 } 390 391 func (ch accessListAddSlotChange) copy() journalEntry { 392 return accessListAddSlotChange{ 393 address: ch.address, 394 slot: ch.slot, 395 } 396 }