github.com/theQRL/go-zond@v0.2.1/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/theQRL/go-zond/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 // length returns the current number of entries in the journal. 76 func (j *journal) length() int { 77 return len(j.entries) 78 } 79 80 type ( 81 // Changes to the account trie. 82 createObjectChange struct { 83 account *common.Address 84 } 85 resetObjectChange struct { 86 account *common.Address 87 prev *stateObject 88 prevdestruct bool 89 prevAccount []byte 90 prevStorage map[common.Hash][]byte 91 92 prevAccountOriginExist bool 93 prevAccountOrigin []byte 94 prevStorageOrigin map[common.Hash][]byte 95 } 96 97 // Changes to individual accounts. 98 balanceChange struct { 99 account *common.Address 100 prev *big.Int 101 } 102 nonceChange struct { 103 account *common.Address 104 prev uint64 105 } 106 storageChange struct { 107 account *common.Address 108 key, prevalue common.Hash 109 } 110 codeChange struct { 111 account *common.Address 112 prevcode, prevhash []byte 113 } 114 115 // Changes to other state values. 116 refundChange struct { 117 prev uint64 118 } 119 addLogChange struct { 120 txhash common.Hash 121 } 122 addPreimageChange struct { 123 hash common.Hash 124 } 125 touchChange struct { 126 account *common.Address 127 } 128 // Changes to the access list 129 accessListAddAccountChange struct { 130 address *common.Address 131 } 132 accessListAddSlotChange struct { 133 address *common.Address 134 slot *common.Hash 135 } 136 ) 137 138 func (ch createObjectChange) revert(s *StateDB) { 139 delete(s.stateObjects, *ch.account) 140 delete(s.stateObjectsDirty, *ch.account) 141 } 142 143 func (ch createObjectChange) dirtied() *common.Address { 144 return ch.account 145 } 146 147 func (ch resetObjectChange) revert(s *StateDB) { 148 s.setStateObject(ch.prev) 149 if !ch.prevdestruct { 150 delete(s.stateObjectsDestruct, ch.prev.address) 151 } 152 if ch.prevAccount != nil { 153 s.accounts[ch.prev.addrHash] = ch.prevAccount 154 } 155 if ch.prevStorage != nil { 156 s.storages[ch.prev.addrHash] = ch.prevStorage 157 } 158 if ch.prevAccountOriginExist { 159 s.accountsOrigin[ch.prev.address] = ch.prevAccountOrigin 160 } 161 if ch.prevStorageOrigin != nil { 162 s.storagesOrigin[ch.prev.address] = ch.prevStorageOrigin 163 } 164 } 165 166 func (ch resetObjectChange) dirtied() *common.Address { 167 return ch.account 168 } 169 170 func (ch touchChange) revert(s *StateDB) { 171 } 172 173 func (ch touchChange) dirtied() *common.Address { 174 return ch.account 175 } 176 177 func (ch balanceChange) revert(s *StateDB) { 178 s.getStateObject(*ch.account).setBalance(ch.prev) 179 } 180 181 func (ch balanceChange) dirtied() *common.Address { 182 return ch.account 183 } 184 185 func (ch nonceChange) revert(s *StateDB) { 186 s.getStateObject(*ch.account).setNonce(ch.prev) 187 } 188 189 func (ch nonceChange) dirtied() *common.Address { 190 return ch.account 191 } 192 193 func (ch codeChange) revert(s *StateDB) { 194 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 195 } 196 197 func (ch codeChange) dirtied() *common.Address { 198 return ch.account 199 } 200 201 func (ch storageChange) revert(s *StateDB) { 202 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 203 } 204 205 func (ch storageChange) dirtied() *common.Address { 206 return ch.account 207 } 208 209 func (ch refundChange) revert(s *StateDB) { 210 s.refund = ch.prev 211 } 212 213 func (ch refundChange) dirtied() *common.Address { 214 return nil 215 } 216 217 func (ch addLogChange) revert(s *StateDB) { 218 logs := s.logs[ch.txhash] 219 if len(logs) == 1 { 220 delete(s.logs, ch.txhash) 221 } else { 222 s.logs[ch.txhash] = logs[:len(logs)-1] 223 } 224 s.logSize-- 225 } 226 227 func (ch addLogChange) dirtied() *common.Address { 228 return nil 229 } 230 231 func (ch addPreimageChange) revert(s *StateDB) { 232 delete(s.preimages, ch.hash) 233 } 234 235 func (ch addPreimageChange) dirtied() *common.Address { 236 return nil 237 } 238 239 func (ch accessListAddAccountChange) revert(s *StateDB) { 240 /* 241 One important invariant here, is that whenever a (addr, slot) is added, if the 242 addr is not already present, the add causes two journal entries: 243 - one for the address, 244 - one for the (address,slot) 245 Therefore, when unrolling the change, we can always blindly delete the 246 (addr) at this point, since no storage adds can remain when come upon 247 a single (addr) change. 248 */ 249 s.accessList.DeleteAddress(*ch.address) 250 } 251 252 func (ch accessListAddAccountChange) dirtied() *common.Address { 253 return nil 254 } 255 256 func (ch accessListAddSlotChange) revert(s *StateDB) { 257 s.accessList.DeleteSlot(*ch.address, *ch.slot) 258 } 259 260 func (ch accessListAddSlotChange) dirtied() *common.Address { 261 return nil 262 }