github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/journal.go (about) 1 package types 2 3 import ( 4 ethcmn "github.com/ethereum/go-ethereum/common" 5 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 6 ) 7 8 var ripemd = ethcmn.HexToAddress("0000000000000000000000000000000000000003") 9 10 // journalEntry is a modification entry in the state change journal that can be 11 // reverted on demand. 12 type journalEntry interface { 13 // revert undoes the changes introduced by this journal entry. 14 revert(*CommitStateDB) 15 16 // dirtied returns the Ethereum address modified by this journal entry. 17 dirtied() *ethcmn.Address 18 } 19 20 // journal contains the list of state modifications applied since the last state 21 // commit. These are tracked to be able to be reverted in case of an execution 22 // exception or revertal request. 23 type journal struct { 24 entries []journalEntry // Current changes tracked by the journal 25 dirties map[ethcmn.Address]int // Dirty accounts and the number of changes 26 } 27 28 // newJournal create a new initialized journal. 29 func newJournal() *journal { 30 return &journal{ 31 dirties: make(map[ethcmn.Address]int), 32 } 33 } 34 35 // append inserts a new modification entry to the end of the change journal. 36 func (j *journal) append(entry journalEntry) { 37 j.entries = append(j.entries, entry) 38 if addr := entry.dirtied(); addr != nil { 39 j.dirties[*addr]++ 40 } 41 } 42 43 // revert undoes a batch of journalled modifications along with any reverted 44 // dirty handling too. 45 func (j *journal) revert(statedb *CommitStateDB, snapshot int) { 46 for i := len(j.entries) - 1; i >= snapshot; i-- { 47 // Undo the changes made by the operation 48 j.entries[i].revert(statedb) 49 50 // Drop any dirty tracking induced by the change 51 if addr := j.entries[i].dirtied(); addr != nil { 52 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 53 delete(j.dirties, *addr) 54 } 55 } 56 } 57 j.entries = j.entries[:snapshot] 58 } 59 60 // dirty explicitly sets an address to dirty, even if the change entries would 61 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 62 // precompile consensus exception. 63 func (j *journal) dirty(addr ethcmn.Address) { 64 j.dirties[addr]++ 65 } 66 67 // length returns the current number of entries in the journal. 68 func (j *journal) length() int { 69 return len(j.entries) 70 } 71 72 type ( 73 // Changes to the account trie. 74 createObjectChange struct { 75 account *ethcmn.Address 76 } 77 78 resetObjectChange struct { 79 prev *stateObject 80 } 81 82 suicideChange struct { 83 account *ethcmn.Address 84 prev bool // whether account had already suicided 85 prevBalance sdk.Dec 86 } 87 88 // Changes to individual accounts. 89 balanceChange struct { 90 account *ethcmn.Address 91 prev sdk.Dec 92 } 93 94 nonceChange struct { 95 account *ethcmn.Address 96 prev uint64 97 } 98 99 storageChange struct { 100 account *ethcmn.Address 101 key, prevValue ethcmn.Hash 102 } 103 104 codeChange struct { 105 account *ethcmn.Address 106 prevCode, prevHash []byte 107 } 108 109 // Changes to other state values. 110 refundChange struct { 111 prev uint64 112 } 113 114 addLogChange struct { 115 txhash ethcmn.Hash 116 } 117 118 addPreimageChange struct { 119 hash ethcmn.Hash 120 } 121 122 touchChange struct { 123 account *ethcmn.Address 124 // prev bool 125 // prevDirty bool 126 } 127 accessListAddAccountChange struct { 128 address *ethcmn.Address 129 } 130 accessListAddSlotChange struct { 131 address *ethcmn.Address 132 slot *ethcmn.Hash 133 } 134 ) 135 136 func (ch createObjectChange) revert(s *CommitStateDB) { 137 delete(s.stateObjects, *ch.account) 138 delete(s.stateObjectsDirty, *ch.account) 139 } 140 141 func (ch createObjectChange) dirtied() *ethcmn.Address { 142 return ch.account 143 } 144 145 func (ch resetObjectChange) revert(s *CommitStateDB) { 146 s.setStateObject(ch.prev) 147 } 148 149 func (ch resetObjectChange) dirtied() *ethcmn.Address { 150 return nil 151 } 152 153 func (ch suicideChange) revert(s *CommitStateDB) { 154 so := s.getStateObject(*ch.account) 155 if so != nil { 156 so.suicided = ch.prev 157 so.setBalance(sdk.DefaultBondDenom, ch.prevBalance) 158 } 159 } 160 161 func (ch suicideChange) dirtied() *ethcmn.Address { 162 return ch.account 163 } 164 165 func (ch touchChange) revert(s *CommitStateDB) { 166 } 167 168 func (ch touchChange) dirtied() *ethcmn.Address { 169 return ch.account 170 } 171 172 func (ch balanceChange) revert(s *CommitStateDB) { 173 s.getStateObject(*ch.account).setBalance(sdk.DefaultBondDenom, ch.prev) 174 } 175 176 func (ch balanceChange) dirtied() *ethcmn.Address { 177 return ch.account 178 } 179 180 func (ch nonceChange) revert(s *CommitStateDB) { 181 s.getStateObject(*ch.account).setNonce(ch.prev) 182 } 183 184 func (ch nonceChange) dirtied() *ethcmn.Address { 185 return ch.account 186 } 187 188 func (ch codeChange) revert(s *CommitStateDB) { 189 s.getStateObject(*ch.account).setCode(ethcmn.BytesToHash(ch.prevHash), ch.prevCode) 190 } 191 192 func (ch codeChange) dirtied() *ethcmn.Address { 193 return ch.account 194 } 195 196 func (ch storageChange) revert(s *CommitStateDB) { 197 s.getStateObject(*ch.account).setState(ch.key, ch.prevValue) 198 } 199 200 func (ch storageChange) dirtied() *ethcmn.Address { 201 return ch.account 202 } 203 204 func (ch refundChange) revert(s *CommitStateDB) { 205 s.refund = ch.prev 206 } 207 208 func (ch refundChange) dirtied() *ethcmn.Address { 209 return nil 210 } 211 212 func (ch addLogChange) revert(s *CommitStateDB) { 213 logs, err := s.GetLogs(ch.txhash) 214 if err != nil { 215 // panic on unmarshal error 216 panic(err) 217 } 218 219 // delete logs if entry is empty or has only one item 220 if len(logs) <= 1 { 221 s.DeleteLogs(ch.txhash) 222 } else if err := s.SetLogs(ch.txhash, logs[:len(logs)-1]); err != nil { 223 // panic on marshal error 224 panic(err) 225 } 226 227 s.logSize-- 228 } 229 230 func (ch addLogChange) dirtied() *ethcmn.Address { 231 return nil 232 } 233 234 func (ch addPreimageChange) revert(s *CommitStateDB) { 235 delete(s.preimages, ch.hash) 236 } 237 238 func (ch addPreimageChange) dirtied() *ethcmn.Address { 239 return nil 240 } 241 242 func (ch accessListAddAccountChange) revert(s *CommitStateDB) { 243 /* 244 One important invariant here, is that whenever a (addr, slot) is added, if the 245 addr is not already present, the add causes two journal entries: 246 - one for the address, 247 - one for the (address,slot) 248 Therefore, when unrolling the change, we can always blindly delete the 249 (addr) at this point, since no storage adds can remain when come upon 250 a single (addr) change. 251 */ 252 s.accessList.DeleteAddress(*ch.address) 253 } 254 255 func (ch accessListAddAccountChange) dirtied() *ethcmn.Address { 256 return nil 257 } 258 259 func (ch accessListAddSlotChange) revert(s *CommitStateDB) { 260 s.accessList.DeleteSlot(*ch.address, *ch.slot) 261 } 262 263 func (ch accessListAddSlotChange) dirtied() *ethcmn.Address { 264 return nil 265 }