github.com/amazechain/amc@v0.1.3/modules/state/journal.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "github.com/amazechain/amc/common/types" 21 "github.com/holiman/uint256" 22 ) 23 24 // journalEntry is a modification entry in the state change journal that can be 25 // reverted on demand. 26 type journalEntry interface { 27 // revert undoes the changes introduced by this journal entry. 28 revert(*IntraBlockState) 29 30 // dirtied returns the Ethereum address modified by this journal entry. 31 dirtied() *types.Address 32 } 33 34 // journal contains the list of state modifications applied since the last state 35 // commit. These are tracked to be able to be reverted in case of an execution 36 // exception or revertal request. 37 type journal struct { 38 entries []journalEntry // Current changes tracked by the journal 39 dirties map[types.Address]int // Dirty accounts and the number of changes 40 } 41 42 // newJournal create a new initialized journal. 43 func newJournal() *journal { 44 return &journal{ 45 dirties: make(map[types.Address]int), 46 } 47 } 48 49 // append inserts a new modification entry to the end of the change journal. 50 func (j *journal) append(entry journalEntry) { 51 j.entries = append(j.entries, entry) 52 if addr := entry.dirtied(); addr != nil { 53 j.dirties[*addr]++ 54 } 55 } 56 57 // revert undoes a batch of journalled modifications along with any reverted 58 // dirty handling too. 59 func (j *journal) revert(statedb *IntraBlockState, snapshot int) { 60 for i := len(j.entries) - 1; i >= snapshot; i-- { 61 // Undo the changes made by the operation 62 j.entries[i].revert(statedb) 63 64 // Drop any dirty tracking induced by the change 65 if addr := j.entries[i].dirtied(); addr != nil { 66 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 67 delete(j.dirties, *addr) 68 } 69 } 70 } 71 j.entries = j.entries[:snapshot] 72 } 73 74 // dirty explicitly sets an address to dirty, even if the change entries would 75 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 76 // precompile consensus exception. 77 func (j *journal) dirty(addr types.Address) { 78 j.dirties[addr]++ 79 } 80 81 // length returns the current number of entries in the journal. 82 func (j *journal) length() int { 83 n := len(j.entries) 84 return n 85 } 86 87 type ( 88 // Changes to the account trie. 89 createObjectChange struct { 90 account *types.Address 91 } 92 resetObjectChange struct { 93 account *types.Address 94 prev *stateObject 95 } 96 selfdestructChange struct { 97 account *types.Address 98 prev bool // whether account had already selfdestructed 99 prevbalance uint256.Int 100 } 101 102 // Changes to individual accounts. 103 balanceChange struct { 104 account *types.Address 105 prev uint256.Int 106 } 107 balanceIncrease struct { 108 account *types.Address 109 increase uint256.Int 110 } 111 balanceIncreaseTransfer struct { 112 bi *BalanceIncrease 113 } 114 nonceChange struct { 115 account *types.Address 116 prev uint64 117 } 118 storageChange struct { 119 account *types.Address 120 key types.Hash 121 prevalue uint256.Int 122 } 123 fakeStorageChange struct { 124 account *types.Address 125 key types.Hash 126 prevalue uint256.Int 127 } 128 codeChange struct { 129 account *types.Address 130 prevcode []byte 131 prevhash types.Hash 132 } 133 134 // Changes to other state values. 135 refundChange struct { 136 prev uint64 137 } 138 addLogChange struct { 139 txhash types.Hash 140 } 141 touchChange struct { 142 account *types.Address 143 } 144 // Changes to the access list 145 accessListAddAccountChange struct { 146 address *types.Address 147 } 148 accessListAddSlotChange struct { 149 address *types.Address 150 slot *types.Hash 151 } 152 ) 153 154 func (ch createObjectChange) revert(s *IntraBlockState) { 155 delete(s.stateObjects, *ch.account) 156 delete(s.stateObjectsDirty, *ch.account) 157 } 158 159 func (ch createObjectChange) dirtied() *types.Address { 160 return ch.account 161 } 162 163 func (ch resetObjectChange) revert(s *IntraBlockState) { 164 s.setStateObject(*ch.account, ch.prev) 165 } 166 167 func (ch resetObjectChange) dirtied() *types.Address { 168 return nil 169 } 170 171 func (ch selfdestructChange) revert(s *IntraBlockState) { 172 obj := s.getStateObject(*ch.account) 173 if obj != nil { 174 obj.selfdestructed = ch.prev 175 obj.setBalance(&ch.prevbalance) 176 } 177 } 178 179 func (ch selfdestructChange) dirtied() *types.Address { 180 return ch.account 181 } 182 183 var ripemd = types.HexToAddress("0000000000000000000000000000000000000003") 184 185 func (ch touchChange) revert(s *IntraBlockState) { 186 } 187 188 func (ch touchChange) dirtied() *types.Address { 189 return ch.account 190 } 191 192 func (ch balanceChange) revert(s *IntraBlockState) { 193 s.getStateObject(*ch.account).setBalance(&ch.prev) 194 } 195 196 func (ch balanceChange) dirtied() *types.Address { 197 return ch.account 198 } 199 200 func (ch balanceIncrease) revert(s *IntraBlockState) { 201 if bi, ok := s.balanceInc[*ch.account]; ok { 202 bi.increase.Sub(&bi.increase, &ch.increase) 203 bi.count-- 204 if bi.count == 0 { 205 delete(s.balanceInc, *ch.account) 206 } 207 } 208 } 209 210 func (ch balanceIncrease) dirtied() *types.Address { 211 return ch.account 212 } 213 214 func (ch balanceIncreaseTransfer) dirtied() *types.Address { 215 return nil 216 } 217 218 func (ch balanceIncreaseTransfer) revert(s *IntraBlockState) { 219 ch.bi.transferred = false 220 } 221 func (ch nonceChange) revert(s *IntraBlockState) { 222 s.getStateObject(*ch.account).setNonce(ch.prev) 223 } 224 225 func (ch nonceChange) dirtied() *types.Address { 226 return ch.account 227 } 228 229 func (ch codeChange) revert(s *IntraBlockState) { 230 s.getStateObject(*ch.account).setCode(ch.prevhash, ch.prevcode) 231 } 232 233 func (ch codeChange) dirtied() *types.Address { 234 return ch.account 235 } 236 237 func (ch storageChange) revert(s *IntraBlockState) { 238 s.getStateObject(*ch.account).setState(&ch.key, ch.prevalue) 239 } 240 241 func (ch storageChange) dirtied() *types.Address { 242 return ch.account 243 } 244 245 func (ch fakeStorageChange) revert(s *IntraBlockState) { 246 s.getStateObject(*ch.account).fakeStorage[ch.key] = ch.prevalue 247 } 248 249 func (ch fakeStorageChange) dirtied() *types.Address { 250 return ch.account 251 } 252 253 func (ch refundChange) revert(s *IntraBlockState) { 254 s.refund = ch.prev 255 } 256 257 func (ch refundChange) dirtied() *types.Address { 258 return nil 259 } 260 261 func (ch addLogChange) revert(s *IntraBlockState) { 262 logs := s.logs[ch.txhash] 263 if len(logs) == 1 { 264 delete(s.logs, ch.txhash) 265 } else { 266 s.logs[ch.txhash] = logs[:len(logs)-1] 267 } 268 s.logSize-- 269 } 270 271 func (ch addLogChange) dirtied() *types.Address { 272 return nil 273 } 274 275 func (ch accessListAddAccountChange) revert(s *IntraBlockState) { 276 /* 277 One important invariant here, is that whenever a (addr, slot) is added, if the 278 addr is not already present, the add causes two journal entries: 279 - one for the address, 280 - one for the (address,slot) 281 Therefore, when unrolling the change, we can always blindly delete the 282 (addr) at this point, since no storage adds can remain when come upon 283 a single (addr) change. 284 */ 285 s.accessList.DeleteAddress(*ch.address) 286 } 287 288 func (ch accessListAddAccountChange) dirtied() *types.Address { 289 return nil 290 } 291 292 func (ch accessListAddSlotChange) revert(s *IntraBlockState) { 293 s.accessList.DeleteSlot(*ch.address, *ch.slot) 294 } 295 296 func (ch accessListAddSlotChange) dirtied() *types.Address { 297 return nil 298 }