github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/state/journal.go (about) 1 package state 2 3 import ( 4 "math/big" 5 6 "github.com/quickchainproject/quickchain/common" 7 ) 8 9 // journalEntry is a modification entry in the state change journal that can be 10 // reverted on demand. 11 type journalEntry interface { 12 // revert undoes the changes introduced by this journal entry. 13 revert(*StateDB) 14 15 // dirtied returns the Ethereum address modified by this journal entry. 16 dirtied() *common.Address 17 } 18 19 // journal contains the list of state modifications applied since the last state 20 // commit. These are tracked to be able to be reverted in case of an execution 21 // exception or revertal request. 22 type journal struct { 23 entries []journalEntry // Current changes tracked by the journal 24 dirties map[common.Address]int // Dirty accounts and the number of changes 25 } 26 27 // newJournal create a new initialized journal. 28 func newJournal() *journal { 29 return &journal{ 30 dirties: make(map[common.Address]int), 31 } 32 } 33 34 // append inserts a new modification entry to the end of the change journal. 35 func (j *journal) append(entry journalEntry) { 36 j.entries = append(j.entries, entry) 37 if addr := entry.dirtied(); addr != nil { 38 j.dirties[*addr]++ 39 } 40 } 41 42 // revert undoes a batch of journalled modifications along with any reverted 43 // dirty handling too. 44 func (j *journal) revert(statedb *StateDB, snapshot int) { 45 for i := len(j.entries) - 1; i >= snapshot; i-- { 46 // Undo the changes made by the operation 47 j.entries[i].revert(statedb) 48 49 // Drop any dirty tracking induced by the change 50 if addr := j.entries[i].dirtied(); addr != nil { 51 if j.dirties[*addr]--; j.dirties[*addr] == 0 { 52 delete(j.dirties, *addr) 53 } 54 } 55 } 56 j.entries = j.entries[:snapshot] 57 } 58 59 // dirty explicitly sets an address to dirty, even if the change entries would 60 // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD 61 // precompile consensus exception. 62 func (j *journal) dirty(addr common.Address) { 63 j.dirties[addr]++ 64 } 65 66 // length returns the current number of entries in the journal. 67 func (j *journal) length() int { 68 return len(j.entries) 69 } 70 71 type ( 72 // Changes to the account trie. 73 createObjectChange struct { 74 account *common.Address 75 } 76 resetObjectChange struct { 77 prev *stateObject 78 } 79 suicideChange struct { 80 account *common.Address 81 prev bool // whether account had already suicided 82 prevbalance *big.Int 83 } 84 85 // Changes to individual accounts. 86 balanceChange struct { 87 account *common.Address 88 prev *big.Int 89 } 90 nonceChange struct { 91 account *common.Address 92 prev uint64 93 } 94 storageChange struct { 95 account *common.Address 96 key, prevalue common.Hash 97 } 98 codeChange struct { 99 account *common.Address 100 prevcode, prevhash []byte 101 } 102 103 // Changes to other state values. 104 refundChange struct { 105 prev uint64 106 } 107 addLogChange struct { 108 txhash common.Hash 109 } 110 addPreimageChange struct { 111 hash common.Hash 112 } 113 touchChange struct { 114 account *common.Address 115 prev bool 116 prevDirty bool 117 } 118 ) 119 120 func (ch createObjectChange) revert(s *StateDB) { 121 delete(s.stateObjects, *ch.account) 122 delete(s.stateObjectsDirty, *ch.account) 123 } 124 125 func (ch createObjectChange) dirtied() *common.Address { 126 return ch.account 127 } 128 129 func (ch resetObjectChange) revert(s *StateDB) { 130 s.setStateObject(ch.prev) 131 } 132 133 func (ch resetObjectChange) dirtied() *common.Address { 134 return nil 135 } 136 137 func (ch suicideChange) revert(s *StateDB) { 138 obj := s.getStateObject(*ch.account) 139 if obj != nil { 140 obj.suicided = ch.prev 141 obj.setBalance(ch.prevbalance) 142 } 143 } 144 145 func (ch suicideChange) dirtied() *common.Address { 146 return ch.account 147 } 148 149 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 150 151 func (ch touchChange) revert(s *StateDB) { 152 } 153 154 func (ch touchChange) dirtied() *common.Address { 155 return ch.account 156 } 157 158 func (ch balanceChange) revert(s *StateDB) { 159 s.getStateObject(*ch.account).setBalance(ch.prev) 160 } 161 162 func (ch balanceChange) dirtied() *common.Address { 163 return ch.account 164 } 165 166 func (ch nonceChange) revert(s *StateDB) { 167 s.getStateObject(*ch.account).setNonce(ch.prev) 168 } 169 170 func (ch nonceChange) dirtied() *common.Address { 171 return ch.account 172 } 173 174 func (ch codeChange) revert(s *StateDB) { 175 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 176 } 177 178 func (ch codeChange) dirtied() *common.Address { 179 return ch.account 180 } 181 182 func (ch storageChange) revert(s *StateDB) { 183 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 184 } 185 186 func (ch storageChange) dirtied() *common.Address { 187 return ch.account 188 } 189 190 func (ch refundChange) revert(s *StateDB) { 191 s.refund = ch.prev 192 } 193 194 func (ch refundChange) dirtied() *common.Address { 195 return nil 196 } 197 198 func (ch addLogChange) revert(s *StateDB) { 199 logs := s.logs[ch.txhash] 200 if len(logs) == 1 { 201 delete(s.logs, ch.txhash) 202 } else { 203 s.logs[ch.txhash] = logs[:len(logs)-1] 204 } 205 s.logSize-- 206 } 207 208 func (ch addLogChange) dirtied() *common.Address { 209 return nil 210 } 211 212 func (ch addPreimageChange) revert(s *StateDB) { 213 delete(s.preimages, ch.hash) 214 } 215 216 func (ch addPreimageChange) dirtied() *common.Address { 217 return nil 218 }