github.com/jiajun1992/watercarver@v0.0.0-20191031150618-dfc2b17c0c4a/go-ethereum/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 crypto2 "github.com/ethereum/go-ethereum/ctcrypto/crypto" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/common" 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 case of an execution 38 // exception or revertal request. 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 create 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 } 96 suicideChange struct { 97 account *common.Address 98 prev bool // whether account had already suicided 99 prevbalance *big.Int 100 } 101 102 // Changes to individual accounts. 103 balanceChange struct { 104 account *common.Address 105 prev *big.Int 106 } 107 ctBalanceChange struct { 108 account *common.Address 109 prev crypto2.Key 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 ) 140 141 func (ch createObjectChange) revert(s *StateDB) { 142 delete(s.stateObjects, *ch.account) 143 delete(s.stateObjectsDirty, *ch.account) 144 } 145 146 func (ch createObjectChange) dirtied() *common.Address { 147 return ch.account 148 } 149 150 func (ch resetObjectChange) revert(s *StateDB) { 151 s.setStateObject(ch.prev) 152 } 153 154 func (ch resetObjectChange) dirtied() *common.Address { 155 return nil 156 } 157 158 func (ch suicideChange) revert(s *StateDB) { 159 obj := s.getStateObject(*ch.account) 160 if obj != nil { 161 obj.suicided = ch.prev 162 obj.setBalance(ch.prevbalance) 163 } 164 } 165 166 func (ch suicideChange) dirtied() *common.Address { 167 return ch.account 168 } 169 170 var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") 171 172 func (ch touchChange) revert(s *StateDB) { 173 } 174 175 func (ch touchChange) dirtied() *common.Address { 176 return ch.account 177 } 178 179 func (ch balanceChange) revert(s *StateDB) { 180 s.getStateObject(*ch.account).setBalance(ch.prev) 181 } 182 183 func (ch balanceChange) dirtied() *common.Address { 184 return ch.account 185 } 186 187 func (ch ctBalanceChange) revert(s *StateDB) { 188 s.getStateObject(*ch.account).setCTBalance(ch.prev) 189 } 190 191 func (ch ctBalanceChange) dirtied() *common.Address { 192 return ch.account 193 } 194 195 func (ch nonceChange) revert(s *StateDB) { 196 s.getStateObject(*ch.account).setNonce(ch.prev) 197 } 198 199 func (ch nonceChange) dirtied() *common.Address { 200 return ch.account 201 } 202 203 func (ch codeChange) revert(s *StateDB) { 204 s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) 205 } 206 207 func (ch codeChange) dirtied() *common.Address { 208 return ch.account 209 } 210 211 func (ch storageChange) revert(s *StateDB) { 212 s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) 213 } 214 215 func (ch storageChange) dirtied() *common.Address { 216 return ch.account 217 } 218 219 func (ch refundChange) revert(s *StateDB) { 220 s.refund = ch.prev 221 } 222 223 func (ch refundChange) dirtied() *common.Address { 224 return nil 225 } 226 227 func (ch addLogChange) revert(s *StateDB) { 228 logs := s.logs[ch.txhash] 229 if len(logs) == 1 { 230 delete(s.logs, ch.txhash) 231 } else { 232 s.logs[ch.txhash] = logs[:len(logs)-1] 233 } 234 s.logSize-- 235 } 236 237 func (ch addLogChange) dirtied() *common.Address { 238 return nil 239 } 240 241 func (ch addPreimageChange) revert(s *StateDB) { 242 delete(s.preimages, ch.hash) 243 } 244 245 func (ch addPreimageChange) dirtied() *common.Address { 246 return nil 247 }