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