github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/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 "math/big" 21 22 "github.com/tirogen/go-ethereum/common" 23 ) 24 25 // journalEntry is a modification entry in the state change journal that can be 26 // reverted on demand. 27 type journalEntry interface { 28 // revert undoes the changes introduced by this journal entry. 29 revert(*StateDB) 30 31 // dirtied returns the Ethereum address modified by this journal entry. 32 dirtied() *common.Address 33 } 34 35 // journal contains the list of state modifications applied since the last state 36 // commit. These are tracked to be able to be reverted in the case of an execution 37 // exception or request for reversal. 38 type journal struct { 39 entries []journalEntry // Current changes tracked by the journal 40 dirties map[common.Address]int // Dirty accounts and the number of changes 41 } 42 43 // newJournal creates a new initialized journal. 44 func newJournal() *journal { 45 return &journal{ 46 dirties: make(map[common.Address]int), 47 } 48 } 49 50 // append inserts a new modification entry to the end of the change journal. 51 func (j *journal) append(entry journalEntry) { 52 j.entries = append(j.entries, entry) 53 if addr := entry.dirtied(); addr != nil { 54 j.dirties[*addr]++ 55 } 56 } 57 58 // revert undoes a batch of journalled modifications along with any reverted 59 // dirty handling too. 60 func (j *journal) revert(statedb *StateDB, snapshot int) { 61 for i := len(j.entries) - 1; i >= snapshot; i-- { 62 // Undo the changes made by the operation 63 j.entries[i].revert(statedb) 64 65 // Drop any dirty tracking induced by the change 66 if addr := j.entries[i].dirtied(); addr != nil { 67 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 68 delete(j.dirties, *addr) 69 } 70 } 71 } 72 j.entries = j.entries[:snapshot] 73 } 74 75 // dirty explicitly sets an address to dirty, even if the change entries would 76 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 77 // precompile consensus exception. 78 func (j *journal) dirty(addr common.Address) { 79 j.dirties[addr]++ 80 } 81 82 // length returns the current number of entries in the journal. 83 func (j *journal) length() int { 84 return len(j.entries) 85 } 86 87 type ( 88 // Changes to the account trie. 89 createObjectChange struct { 90 account *common.Address 91 } 92 resetObjectChange struct { 93 prev *stateObject 94 prevdestruct bool 95 } 96 suicideChange struct { 97 account *common.Address 98 prev bool // whether account had already suicided 99 prevbalance *big.Int 100 } 101 102 // Changes to individual accounts. 103 balanceChange struct { 104 account *common.Address 105 prev *big.Int 106 } 107 nonceChange struct { 108 account *common.Address 109 prev uint64 110 } 111 storageChange struct { 112 account *common.Address 113 key, prevalue common.Hash 114 } 115 codeChange struct { 116 account *common.Address 117 prevcode, prevhash []byte 118 } 119 120 // Changes to other state values. 121 refundChange struct { 122 prev uint64 123 } 124 addLogChange struct { 125 txhash common.Hash 126 } 127 addPreimageChange struct { 128 hash common.Hash 129 } 130 touchChange struct { 131 account *common.Address 132 } 133 // Changes to the access list 134 accessListAddAccountChange struct { 135 address *common.Address 136 } 137 accessListAddSlotChange struct { 138 address *common.Address 139 slot *common.Hash 140 } 141 142 transientStorageChange struct { 143 account *common.Address 144 key, prevalue common.Hash 145 } 146 ) 147 148 func (ch createObjectChange) revert(s *StateDB) { 149 delete(s.stateObjects, *ch.account) 150 delete(s.stateObjectsDirty, *ch.account) 151 } 152 153 func (ch createObjectChange) dirtied() *common.Address { 154 return ch.account 155 } 156 157 func (ch resetObjectChange) revert(s *StateDB) { 158 s.setStateObject(ch.prev) 159 if !ch.prevdestruct && s.snap != nil { 160 delete(s.snapDestructs, ch.prev.addrHash) 161 } 162 } 163 164 func (ch resetObjectChange) dirtied() *common.Address { 165 return nil 166 } 167 168 func (ch suicideChange) revert(s *StateDB) { 169 obj := s.getStateObject(*ch.account) 170 if obj != nil { 171 obj.suicided = ch.prev 172 obj.setBalance(ch.prevbalance) 173 } 174 } 175 176 func (ch suicideChange) dirtied() *common.Address { 177 return ch.account 178 } 179 180 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 181 182 func (ch touchChange) revert(s *StateDB) { 183 } 184 185 func (ch touchChange) dirtied() *common.Address { 186 return ch.account 187 } 188 189 func (ch balanceChange) revert(s *StateDB) { 190 s.getStateObject(*ch.account).setBalance(ch.prev) 191 } 192 193 func (ch balanceChange) dirtied() *common.Address { 194 return ch.account 195 } 196 197 func (ch nonceChange) revert(s *StateDB) { 198 s.getStateObject(*ch.account).setNonce(ch.prev) 199 } 200 201 func (ch nonceChange) dirtied() *common.Address { 202 return ch.account 203 } 204 205 func (ch codeChange) revert(s *StateDB) { 206 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 207 } 208 209 func (ch codeChange) dirtied() *common.Address { 210 return ch.account 211 } 212 213 func (ch storageChange) revert(s *StateDB) { 214 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 215 } 216 217 func (ch storageChange) dirtied() *common.Address { 218 return ch.account 219 } 220 221 func (ch transientStorageChange) revert(s *StateDB) { 222 s.setTransientState(*ch.account, ch.key, ch.prevalue) 223 } 224 225 func (ch transientStorageChange) dirtied() *common.Address { 226 return nil 227 } 228 229 func (ch refundChange) revert(s *StateDB) { 230 s.refund = ch.prev 231 } 232 233 func (ch refundChange) dirtied() *common.Address { 234 return nil 235 } 236 237 func (ch addLogChange) revert(s *StateDB) { 238 logs := s.logs[ch.txhash] 239 if len(logs) == 1 { 240 delete(s.logs, ch.txhash) 241 } else { 242 s.logs[ch.txhash] = logs[:len(logs)-1] 243 } 244 s.logSize-- 245 } 246 247 func (ch addLogChange) dirtied() *common.Address { 248 return nil 249 } 250 251 func (ch addPreimageChange) revert(s *StateDB) { 252 delete(s.preimages, ch.hash) 253 } 254 255 func (ch addPreimageChange) dirtied() *common.Address { 256 return nil 257 } 258 259 func (ch accessListAddAccountChange) revert(s *StateDB) { 260 /* 261 One important invariant here, is that whenever a (addr, slot) is added, if the 262 addr is not already present, the add causes two journal entries: 263 - one for the address, 264 - one for the (address,slot) 265 Therefore, when unrolling the change, we can always blindly delete the 266 (addr) at this point, since no storage adds can remain when come upon 267 a single (addr) change. 268 */ 269 s.accessList.DeleteAddress(*ch.address) 270 } 271 272 func (ch accessListAddAccountChange) dirtied() *common.Address { 273 return nil 274 } 275 276 func (ch accessListAddSlotChange) revert(s *StateDB) { 277 s.accessList.DeleteSlot(*ch.address, *ch.slot) 278 } 279 280 func (ch accessListAddSlotChange) dirtied() *common.Address { 281 return nil 282 }