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