github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state/journal.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2016 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package state 28 29 import ( 30 "math/big" 31 32 "github.com/ethereum/go-ethereum/common" 33 ) 34 35 // journalEntry is a modification entry in the state change journal that can be 36 // reverted on demand. 37 type journalEntry interface { 38 // revert undoes the changes introduced by this journal entry. 39 revert(*StateDB) 40 41 // dirtied returns the Ethereum address modified by this journal entry. 42 dirtied() *common.Address 43 } 44 45 // journal contains the list of state modifications applied since the last state 46 // commit. These are tracked to be able to be reverted in the case of an execution 47 // exception or request for reversal. 48 type journal struct { 49 entries []journalEntry // Current changes tracked by the journal 50 dirties map[common.Address]int // Dirty accounts and the number of changes 51 } 52 53 // newJournal creates a new initialized journal. 54 func newJournal() *journal { 55 return &journal{ 56 dirties: make(map[common.Address]int), 57 } 58 } 59 60 // append inserts a new modification entry to the end of the change journal. 61 func (j *journal) append(entry journalEntry) { 62 j.entries = append(j.entries, entry) 63 if addr := entry.dirtied(); addr != nil { 64 j.dirties[*addr]++ 65 } 66 } 67 68 // revert undoes a batch of journalled modifications along with any reverted 69 // dirty handling too. 70 func (j *journal) revert(statedb *StateDB, snapshot int) { 71 for i := len(j.entries) - 1; i >= snapshot; i-- { 72 // Undo the changes made by the operation 73 j.entries[i].revert(statedb) 74 75 // Drop any dirty tracking induced by the change 76 if addr := j.entries[i].dirtied(); addr != nil { 77 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 78 delete(j.dirties, *addr) 79 } 80 } 81 } 82 j.entries = j.entries[:snapshot] 83 } 84 85 // dirty explicitly sets an address to dirty, even if the change entries would 86 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 87 // precompile consensus exception. 88 func (j *journal) dirty(addr common.Address) { 89 j.dirties[addr]++ 90 } 91 92 // length returns the current number of entries in the journal. 93 func (j *journal) length() int { 94 return len(j.entries) 95 } 96 97 type ( 98 // Changes to the account trie. 99 createObjectChange struct { 100 account *common.Address 101 } 102 resetObjectChange struct { 103 prev *stateObject 104 prevdestruct bool 105 } 106 suicideChange struct { 107 account *common.Address 108 prev bool // whether account had already suicided 109 prevbalance *big.Int 110 } 111 112 // Changes to individual accounts. 113 balanceChange struct { 114 account *common.Address 115 prev *big.Int 116 } 117 nonceChange struct { 118 account *common.Address 119 prev uint64 120 } 121 storageChange struct { 122 account *common.Address 123 key, prevalue common.Hash 124 } 125 codeChange struct { 126 account *common.Address 127 prevcode, prevhash []byte 128 } 129 130 // Changes to other state values. 131 refundChange struct { 132 prev uint64 133 } 134 addLogChange struct { 135 txhash common.Hash 136 } 137 addPreimageChange struct { 138 hash common.Hash 139 } 140 touchChange struct { 141 account *common.Address 142 } 143 // Changes to the access list 144 accessListAddAccountChange struct { 145 address *common.Address 146 } 147 accessListAddSlotChange struct { 148 address *common.Address 149 slot *common.Hash 150 } 151 ) 152 153 func (ch createObjectChange) revert(s *StateDB) { 154 delete(s.stateObjects, *ch.account) 155 delete(s.stateObjectsDirty, *ch.account) 156 } 157 158 func (ch createObjectChange) dirtied() *common.Address { 159 return ch.account 160 } 161 162 func (ch resetObjectChange) revert(s *StateDB) { 163 s.setStateObject(ch.prev) 164 if !ch.prevdestruct && s.snap != nil { 165 delete(s.snapDestructs, ch.prev.addrHash) 166 } 167 } 168 169 func (ch resetObjectChange) dirtied() *common.Address { 170 return nil 171 } 172 173 func (ch suicideChange) revert(s *StateDB) { 174 obj := s.getStateObject(*ch.account) 175 if obj != nil { 176 obj.suicided = ch.prev 177 obj.setBalance(ch.prevbalance) 178 } 179 } 180 181 func (ch suicideChange) dirtied() *common.Address { 182 return ch.account 183 } 184 185 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 186 187 func (ch touchChange) revert(s *StateDB) { 188 } 189 190 func (ch touchChange) dirtied() *common.Address { 191 return ch.account 192 } 193 194 func (ch balanceChange) revert(s *StateDB) { 195 s.getStateObject(*ch.account).setBalance(ch.prev) 196 } 197 198 func (ch balanceChange) dirtied() *common.Address { 199 return ch.account 200 } 201 202 func (ch nonceChange) revert(s *StateDB) { 203 s.getStateObject(*ch.account).setNonce(ch.prev) 204 } 205 206 func (ch nonceChange) dirtied() *common.Address { 207 return ch.account 208 } 209 210 func (ch codeChange) revert(s *StateDB) { 211 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 212 } 213 214 func (ch codeChange) dirtied() *common.Address { 215 return ch.account 216 } 217 218 func (ch storageChange) revert(s *StateDB) { 219 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 220 } 221 222 func (ch storageChange) dirtied() *common.Address { 223 return ch.account 224 } 225 226 func (ch refundChange) revert(s *StateDB) { 227 s.refund = ch.prev 228 } 229 230 func (ch refundChange) dirtied() *common.Address { 231 return nil 232 } 233 234 func (ch addLogChange) revert(s *StateDB) { 235 logs := s.logs[ch.txhash] 236 if len(logs) == 1 { 237 delete(s.logs, ch.txhash) 238 } else { 239 s.logs[ch.txhash] = logs[:len(logs)-1] 240 } 241 s.logSize-- 242 } 243 244 func (ch addLogChange) dirtied() *common.Address { 245 return nil 246 } 247 248 func (ch addPreimageChange) revert(s *StateDB) { 249 delete(s.preimages, ch.hash) 250 } 251 252 func (ch addPreimageChange) dirtied() *common.Address { 253 return nil 254 } 255 256 func (ch accessListAddAccountChange) revert(s *StateDB) { 257 /* 258 One important invariant here, is that whenever a (addr, slot) is added, if the 259 addr is not already present, the add causes two journal entries: 260 - one for the address, 261 - one for the (address,slot) 262 Therefore, when unrolling the change, we can always blindly delete the 263 (addr) at this point, since no storage adds can remain when come upon 264 a single (addr) change. 265 */ 266 s.accessList.DeleteAddress(*ch.address) 267 } 268 269 func (ch accessListAddAccountChange) dirtied() *common.Address { 270 return nil 271 } 272 273 func (ch accessListAddSlotChange) revert(s *StateDB) { 274 s.accessList.DeleteSlot(*ch.address, *ch.slot) 275 } 276 277 func (ch accessListAddSlotChange) dirtied() *common.Address { 278 return nil 279 }