github.com/dim4egster/coreth@v0.10.2/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 multiCoinEnable struct { 118 account *common.Address 119 } 120 nonceChange struct { 121 account *common.Address 122 prev uint64 123 } 124 storageChange struct { 125 account *common.Address 126 key, prevalue common.Hash 127 } 128 codeChange struct { 129 account *common.Address 130 prevcode, prevhash []byte 131 } 132 133 // Changes to other state values. 134 refundChange struct { 135 prev uint64 136 } 137 addLogChange struct { 138 txhash common.Hash 139 } 140 addPreimageChange struct { 141 hash common.Hash 142 } 143 touchChange struct { 144 account *common.Address 145 } 146 // Changes to the access list 147 accessListAddAccountChange struct { 148 address *common.Address 149 } 150 accessListAddSlotChange struct { 151 address *common.Address 152 slot *common.Hash 153 } 154 ) 155 156 func (ch createObjectChange) revert(s *StateDB) { 157 delete(s.stateObjects, *ch.account) 158 delete(s.stateObjectsDirty, *ch.account) 159 } 160 161 func (ch createObjectChange) dirtied() *common.Address { 162 return ch.account 163 } 164 165 func (ch resetObjectChange) revert(s *StateDB) { 166 s.setStateObject(ch.prev) 167 if !ch.prevdestruct && s.snap != nil { 168 delete(s.snapDestructs, ch.prev.addrHash) 169 } 170 } 171 172 func (ch resetObjectChange) dirtied() *common.Address { 173 return nil 174 } 175 176 func (ch suicideChange) revert(s *StateDB) { 177 obj := s.getStateObject(*ch.account) 178 if obj != nil { 179 obj.suicided = ch.prev 180 obj.setBalance(ch.prevbalance) 181 } 182 } 183 184 func (ch suicideChange) dirtied() *common.Address { 185 return ch.account 186 } 187 188 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 189 190 func (ch touchChange) revert(s *StateDB) { 191 } 192 193 func (ch touchChange) dirtied() *common.Address { 194 return ch.account 195 } 196 197 func (ch balanceChange) revert(s *StateDB) { 198 s.getStateObject(*ch.account).setBalance(ch.prev) 199 } 200 201 func (ch balanceChange) dirtied() *common.Address { 202 return ch.account 203 } 204 205 func (ch multiCoinEnable) revert(s *StateDB) { 206 s.getStateObject(*ch.account).data.IsMultiCoin = false 207 } 208 209 func (ch multiCoinEnable) dirtied() *common.Address { 210 return ch.account 211 } 212 213 func (ch nonceChange) revert(s *StateDB) { 214 s.getStateObject(*ch.account).setNonce(ch.prev) 215 } 216 217 func (ch nonceChange) dirtied() *common.Address { 218 return ch.account 219 } 220 221 func (ch codeChange) revert(s *StateDB) { 222 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 223 } 224 225 func (ch codeChange) dirtied() *common.Address { 226 return ch.account 227 } 228 229 func (ch storageChange) revert(s *StateDB) { 230 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 231 } 232 233 func (ch storageChange) dirtied() *common.Address { 234 return ch.account 235 } 236 237 func (ch refundChange) revert(s *StateDB) { 238 s.refund = ch.prev 239 } 240 241 func (ch refundChange) dirtied() *common.Address { 242 return nil 243 } 244 245 func (ch addLogChange) revert(s *StateDB) { 246 logs := s.logs[ch.txhash] 247 if len(logs) == 1 { 248 delete(s.logs, ch.txhash) 249 } else { 250 s.logs[ch.txhash] = logs[:len(logs)-1] 251 } 252 s.logSize-- 253 } 254 255 func (ch addLogChange) dirtied() *common.Address { 256 return nil 257 } 258 259 func (ch addPreimageChange) revert(s *StateDB) { 260 delete(s.preimages, ch.hash) 261 } 262 263 func (ch addPreimageChange) dirtied() *common.Address { 264 return nil 265 } 266 267 func (ch accessListAddAccountChange) revert(s *StateDB) { 268 /* 269 One important invariant here, is that whenever a (addr, slot) is added, if the 270 addr is not already present, the add causes two journal entries: 271 - one for the address, 272 - one for the (address,slot) 273 Therefore, when unrolling the change, we can always blindly delete the 274 (addr) at this point, since no storage adds can remain when come upon 275 a single (addr) change. 276 */ 277 s.accessList.DeleteAddress(*ch.address) 278 } 279 280 func (ch accessListAddAccountChange) dirtied() *common.Address { 281 return nil 282 } 283 284 func (ch accessListAddSlotChange) revert(s *StateDB) { 285 s.accessList.DeleteSlot(*ch.address, *ch.slot) 286 } 287 288 func (ch accessListAddSlotChange) dirtied() *common.Address { 289 return nil 290 }