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