github.com/annchain/OG@v0.0.9/arefactor_core/core/state/preload_db.go (about) 1 package state 2 3 import ( 4 ogTypes "github.com/annchain/OG/arefactor/og_interface" 5 crypto "github.com/annchain/OG/arefactor/ogcrypto" 6 "github.com/annchain/OG/common/math" 7 "github.com/annchain/OG/types/token" 8 vmtypes "github.com/annchain/OG/vm/types" 9 log "github.com/sirupsen/logrus" 10 ) 11 12 type PreloadDB struct { 13 root ogTypes.Hash 14 15 db Database 16 sd *StateDB 17 18 trie Trie 19 worldTrie Trie 20 21 // journal records every action which will change statedb's data 22 // and it's for VM term revert only. 23 journal *journal 24 25 // states stores all the active state object, any changes on stateobject 26 // will also update states. 27 states map[ogTypes.AddressKey]*StateObject 28 dirtyset map[ogTypes.AddressKey]struct{} 29 } 30 31 func NewPreloadDB(db Database, statedb *StateDB) *PreloadDB { 32 return &PreloadDB{ 33 root: statedb.Root(), 34 db: db, 35 sd: statedb, 36 journal: newJournal(), 37 states: make(map[ogTypes.AddressKey]*StateObject), 38 dirtyset: make(map[ogTypes.AddressKey]struct{}), 39 } 40 } 41 42 func (pd *PreloadDB) Reset() { 43 pd.trie = nil 44 pd.journal = newJournal() 45 pd.states = make(map[ogTypes.AddressKey]*StateObject) 46 pd.dirtyset = make(map[ogTypes.AddressKey]struct{}) 47 } 48 49 func (pd *PreloadDB) getOrCreateStateObject(addr ogTypes.Address) *StateObject { 50 state := pd.getStateObject(addr) 51 if state == nil { 52 pd.CreateAccount(addr) 53 state = pd.getStateObject(addr) 54 } 55 return state 56 } 57 58 func (pd *PreloadDB) getStateObject(addr ogTypes.Address) *StateObject { 59 state, exist := pd.states[addr.AddressKey()] 60 if !exist { 61 sdState := pd.sd.GetStateObject(addr) 62 if sdState == nil { 63 return nil 64 } 65 state = NewStateObject(addr, pd) 66 state.Copy(sdState) 67 pd.states[addr.AddressKey()] = state 68 } 69 return state 70 } 71 72 func (pd *PreloadDB) CreateAccount(addr ogTypes.Address) { 73 newstate := NewStateObject(addr, pd) 74 oldstate := pd.sd.GetStateObject(addr) 75 if oldstate != nil { 76 pd.AppendJournal(&resetObjectChange{ 77 account: oldstate.address, 78 prev: oldstate, 79 }) 80 } else { 81 pd.AppendJournal(&createObjectChange{ 82 account: addr, 83 }) 84 } 85 pd.states[addr.AddressKey()] = newstate 86 87 } 88 89 func (pd *PreloadDB) SubBalance(addr ogTypes.Address, decrement *math.BigInt) { 90 pd.subBalance(addr, token.OGTokenID, decrement) 91 } 92 func (pd *PreloadDB) SubTokenBalance(addr ogTypes.Address, tokenID int32, decrement *math.BigInt) { 93 pd.subBalance(addr, tokenID, decrement) 94 } 95 func (pd *PreloadDB) subBalance(addr ogTypes.Address, tokenID int32, decrement *math.BigInt) { 96 // check if increment is zero 97 if decrement.Sign() == 0 { 98 return 99 } 100 state := pd.getOrCreateStateObject(addr) 101 pd.setBalance(addr, tokenID, state.data.Balances.PreSub(tokenID, decrement)) 102 } 103 104 func (pd *PreloadDB) AddBalance(addr ogTypes.Address, increment *math.BigInt) { 105 pd.addBalance(addr, token.OGTokenID, increment) 106 } 107 func (pd *PreloadDB) AddTokenBalance(addr ogTypes.Address, tokenID int32, increment *math.BigInt) { 108 pd.addBalance(addr, tokenID, increment) 109 } 110 func (pd *PreloadDB) addBalance(addr ogTypes.Address, tokenID int32, increment *math.BigInt) { 111 // check if increment is zero 112 if increment.Sign() == 0 { 113 return 114 } 115 state := pd.getOrCreateStateObject(addr) 116 pd.setBalance(addr, tokenID, state.data.Balances.PreAdd(tokenID, increment)) 117 } 118 119 func (ps *PreloadDB) SetTokenBalance(addr ogTypes.Address, tokenID int32, balance *math.BigInt) { 120 ps.setBalance(addr, tokenID, balance) 121 } 122 func (pd *PreloadDB) setBalance(addr ogTypes.Address, tokenID int32, balance *math.BigInt) { 123 state := pd.getOrCreateStateObject(addr) 124 state.SetBalance(tokenID, balance) 125 } 126 127 // Retrieve the balance from the given address or 0 if object not found 128 func (pd *PreloadDB) GetBalance(addr ogTypes.Address) *math.BigInt { 129 return pd.getBalance(addr, token.OGTokenID) 130 } 131 func (pd *PreloadDB) GetTokenBalance(addr ogTypes.Address, tokenID int32) *math.BigInt { 132 return pd.getBalance(addr, tokenID) 133 } 134 func (pd *PreloadDB) getBalance(addr ogTypes.Address, tokenID int32) *math.BigInt { 135 state := pd.getStateObject(addr) 136 if state == nil { 137 return math.NewBigInt(0) 138 } 139 return state.GetBalance(tokenID) 140 } 141 142 func (pd *PreloadDB) GetNonce(addr ogTypes.Address) uint64 { 143 state := pd.getStateObject(addr) 144 if state == nil { 145 return 0 146 } 147 return state.GetNonce() 148 } 149 func (pd *PreloadDB) SetNonce(addr ogTypes.Address, nonce uint64) { 150 state := pd.getOrCreateStateObject(addr) 151 state.SetNonce(nonce) 152 } 153 154 func (pd *PreloadDB) GetCodeHash(addr ogTypes.Address) ogTypes.Hash { 155 state := pd.getStateObject(addr) 156 if state == nil { 157 return nil 158 } 159 return state.GetCodeHash() 160 } 161 162 func (pd *PreloadDB) GetCode(addr ogTypes.Address) []byte { 163 state := pd.getStateObject(addr) 164 if state == nil { 165 return nil 166 } 167 return state.GetCode(pd.db) 168 } 169 170 func (pd *PreloadDB) SetCode(addr ogTypes.Address, code []byte) { 171 state := pd.getOrCreateStateObject(addr) 172 state.SetCode(ogTypes.BytesToHash32(crypto.Keccak256Hash(code)), code) 173 } 174 175 func (pd *PreloadDB) GetCodeSize(addr ogTypes.Address) int { 176 state := pd.getStateObject(addr) 177 if state == nil { 178 return 0 179 } 180 l, dberr := state.GetCodeSize(pd.db) 181 if dberr != nil { 182 log.Errorf("get code size from obj error: %v, obj: %s", dberr, state.address.AddressShortString()) 183 return 0 184 } 185 return l 186 } 187 188 func (pd *PreloadDB) AddRefund(uint64) {} 189 func (pd *PreloadDB) SubRefund(uint64) {} 190 func (pd *PreloadDB) GetRefund() uint64 { return 0 } 191 192 func (pd *PreloadDB) GetCommittedState(addr ogTypes.Address, key ogTypes.Hash) ogTypes.Hash { 193 state := pd.getStateObject(addr) 194 if state == nil { 195 return &emptyStateHash 196 } 197 return state.GetCommittedState(pd.db, key) 198 } 199 200 // GetState retrieves a value from the given account's storage trie. 201 func (pd *PreloadDB) GetState(addr ogTypes.Address, key ogTypes.Hash) ogTypes.Hash { 202 state := pd.getStateObject(addr) 203 if state == nil { 204 return &emptyStateHash 205 } 206 return state.GetState(pd.db, key) 207 } 208 209 func (pd *PreloadDB) SetState(addr ogTypes.Address, key, value ogTypes.Hash) { 210 state := pd.getOrCreateStateObject(addr) 211 if state == nil { 212 return 213 } 214 state.SetState(pd.db, key, value) 215 } 216 217 func (pd *PreloadDB) Commit() (ogTypes.Hash, error) { 218 trie, err := pd.db.OpenTrie(pd.sd.Root()) 219 if err != nil { 220 return nil, err 221 } 222 pd.trie = trie 223 224 // update dirtyset according to journal 225 for addr := range pd.journal.dirties { 226 pd.dirtyset[addr.AddressKey()] = struct{}{} 227 } 228 for addr, state := range pd.states { 229 if _, isdirty := pd.dirtyset[addr]; !isdirty { 230 continue 231 } 232 log.Tracef("commit preload state, addr: %s, state: %s", addr, state.String()) 233 // commit state's code 234 if state.code != nil && state.dirtycode { 235 pd.db.TrieDB().Insert(state.GetCodeHash(), state.code) 236 state.dirtycode = false 237 } 238 // commit state's storage 239 if err := state.CommitStorage(pd.db, true); err != nil { 240 log.Errorf("commit state's storage error: %v", err) 241 } 242 // update state data in current trie. 243 data, _ := state.Encode() 244 if err := pd.trie.TryUpdate(addr.Bytes(), data); err != nil { 245 log.Errorf("commit statedb error: %v", err) 246 } 247 delete(pd.dirtyset, addr) 248 } 249 // commit current trie into triedb. 250 rootHash, err := pd.trie.Commit(func(leaf []byte, parent ogTypes.Hash) error { 251 account := NewAccountData() 252 if _, err := account.UnmarshalMsg(leaf); err != nil { 253 return nil 254 } 255 // log.Tracef("onleaf called with address: %s, root: %v, codehash: %v", account.Address.Hex(), account.Root.ToBytes(), account.CodeHash) 256 if account.Root != emptyStateRoot { 257 // 258 //pd.db.TrieDB().Reference(account.Root, parent) 259 } 260 codehash := ogTypes.BytesToHash32(account.CodeHash) 261 if codehash.Cmp(emptyCodeHash) != 0 { 262 //pd.db.TrieDB().Reference(codehash, parent) 263 } 264 return nil 265 }, true) 266 267 //if trie commit fail ,nil root will write to db 268 if err != nil { 269 log.WithError(err).Warning("commit trie error") 270 } 271 log.WithField("rootHash", rootHash).Trace("state root set to") 272 pd.root = rootHash 273 274 pd.Reset() 275 return rootHash, err 276 } 277 278 func (pd *PreloadDB) AppendJournal(entry JournalEntry) { 279 pd.journal.append(entry) 280 } 281 282 func (pd *PreloadDB) Suicide(addr ogTypes.Address) bool { 283 state := pd.getStateObject(addr) 284 if state == nil { 285 return false 286 } 287 pd.AppendJournal(&suicideChange{ 288 account: addr, 289 prev: state.suicided, 290 prevbalance: state.data.Balances.Copy(), 291 }) 292 state.suicided = true 293 state.data.Balances = NewBalanceSet() 294 return true 295 } 296 297 func (pd *PreloadDB) HasSuicided(addr ogTypes.Address) bool { 298 state := pd.getStateObject(addr) 299 if state == nil { 300 return false 301 } 302 return state.suicided 303 } 304 305 // Exist reports whether the given account exists in state. 306 // Notably this should also return true for suicided accounts. 307 func (pd *PreloadDB) Exist(addr ogTypes.Address) bool { 308 if state := pd.getStateObject(addr); state != nil { 309 return true 310 } 311 return false 312 } 313 314 // Empty returns whether the given account is empty. Empty 315 // is defined according to EIP161 (balance = nonce = code = 0). 316 func (pd *PreloadDB) Empty(addr ogTypes.Address) bool { 317 state := pd.getStateObject(addr) 318 if state == nil { 319 return true 320 } 321 if len(state.code) != 0 { 322 return false 323 } 324 if state.data.Nonce != uint64(0) { 325 return false 326 } 327 if state.data.Balances.IsEmpty() { 328 return false 329 } 330 return true 331 } 332 333 // RevertToSnapshot reverts all state changes made since the given revision. 334 func (pd *PreloadDB) RevertToSnapshot(int) {} 335 336 // Snapshot creates a new revision 337 func (pd *PreloadDB) Snapshot() int { 338 return 0 339 } 340 341 func (pd *PreloadDB) AddLog(l *vmtypes.Log) {} 342 func (pd *PreloadDB) AddPreimage(ogTypes.Hash, []byte) {} 343 344 func (pd *PreloadDB) ForEachStorage(ogTypes.Address, func(ogTypes.Hash, ogTypes.Hash) bool) {} 345 346 // for debug. 347 func (pd *PreloadDB) String() string { 348 return "" 349 }