github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/core/state/state_object.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "math/big" 24 "time" 25 26 "github.com/ebakus/go-ebakus/common" 27 "github.com/ebakus/go-ebakus/crypto" 28 "github.com/ebakus/go-ebakus/metrics" 29 "github.com/ebakus/go-ebakus/rlp" 30 ) 31 32 var emptyCodeHash = crypto.Keccak256(nil) 33 34 type Code []byte 35 36 func (c Code) String() string { 37 return string(c) //strings.Join(Disassemble(c), " ") 38 } 39 40 type Storage map[common.Hash]common.Hash 41 42 func (s Storage) String() (str string) { 43 for key, value := range s { 44 str += fmt.Sprintf("%X : %X\n", key, value) 45 } 46 47 return 48 } 49 50 func (s Storage) Copy() Storage { 51 cpy := make(Storage) 52 for key, value := range s { 53 cpy[key] = value 54 } 55 56 return cpy 57 } 58 59 // stateObject represents an Ebakus account which is being modified. 60 // 61 // The usage pattern is as follows: 62 // First you need to obtain a state object. 63 // Account values can be accessed and modified through the object. 64 // Finally, call CommitTrie to write the modified storage trie into a database. 65 type stateObject struct { 66 address common.Address 67 addrHash common.Hash // hash of ebakus address of the account 68 data Account 69 db *StateDB 70 71 // DB error. 72 // State objects are used by the consensus core and VM which are 73 // unable to deal with database-level errors. Any error that occurs 74 // during a database read is memoized here and will eventually be returned 75 // by StateDB.Commit. 76 dbErr error 77 78 // Write caches. 79 trie Trie // storage trie, which becomes non-nil on first access 80 code Code // contract bytecode, which gets set when code is loaded 81 82 originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction 83 pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block 84 dirtyStorage Storage // Storage entries that have been modified in the current transaction execution 85 fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. 86 87 // Cache flags. 88 // When an object is marked suicided it will be delete from the trie 89 // during the "update" phase of the state transition. 90 dirtyCode bool // true if the code was updated 91 suicided bool 92 deleted bool 93 } 94 95 // empty returns whether the account is considered empty. 96 func (s *stateObject) empty() bool { 97 return s.data.Nonce == 0 && 98 s.data.Balance.Sign() == 0 && 99 bytes.Equal(s.data.CodeHash, emptyCodeHash) 100 } 101 102 // Account is the Ebakus consensus representation of accounts. 103 // These objects are stored in the main account trie. 104 type Account struct { 105 Nonce uint64 106 Balance *big.Int 107 Root common.Hash // merkle root of the storage trie 108 CodeHash []byte 109 } 110 111 // newObject creates a state object. 112 func newObject(db *StateDB, address common.Address, data Account) *stateObject { 113 if data.Balance == nil { 114 data.Balance = new(big.Int) 115 } 116 if data.CodeHash == nil { 117 data.CodeHash = emptyCodeHash 118 } 119 if data.Root == (common.Hash{}) { 120 data.Root = emptyRoot 121 } 122 return &stateObject{ 123 db: db, 124 address: address, 125 addrHash: crypto.Keccak256Hash(address[:]), 126 data: data, 127 originStorage: make(Storage), 128 pendingStorage: make(Storage), 129 dirtyStorage: make(Storage), 130 } 131 } 132 133 // EncodeRLP implements rlp.Encoder. 134 func (s *stateObject) EncodeRLP(w io.Writer) error { 135 return rlp.Encode(w, s.data) 136 } 137 138 // setError remembers the first non-nil error it is called with. 139 func (s *stateObject) setError(err error) { 140 if s.dbErr == nil { 141 s.dbErr = err 142 } 143 } 144 145 func (s *stateObject) markSuicided() { 146 s.suicided = true 147 } 148 149 func (s *stateObject) touch() { 150 s.db.journal.append(touchChange{ 151 account: &s.address, 152 }) 153 if s.address == ripemd { 154 // Explicitly put it in the dirty-cache, which is otherwise generated from 155 // flattened journals. 156 s.db.journal.dirty(s.address) 157 } 158 } 159 160 func (s *stateObject) getTrie(db Database) Trie { 161 if s.trie == nil { 162 var err error 163 s.trie, err = db.OpenStorageTrie(s.addrHash, s.data.Root) 164 if err != nil { 165 s.trie, _ = db.OpenStorageTrie(s.addrHash, common.Hash{}) 166 s.setError(fmt.Errorf("can't create storage trie: %v", err)) 167 } 168 } 169 return s.trie 170 } 171 172 // GetState retrieves a value from the account storage trie. 173 func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { 174 // If the fake storage is set, only lookup the state here(in the debugging mode) 175 if s.fakeStorage != nil { 176 return s.fakeStorage[key] 177 } 178 // If we have a dirty value for this state entry, return it 179 value, dirty := s.dirtyStorage[key] 180 if dirty { 181 return value 182 } 183 // Otherwise return the entry's original value 184 return s.GetCommittedState(db, key) 185 } 186 187 // GetCommittedState retrieves a value from the committed account storage trie. 188 func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { 189 // If the fake storage is set, only lookup the state here(in the debugging mode) 190 if s.fakeStorage != nil { 191 return s.fakeStorage[key] 192 } 193 // If we have a pending write or clean cached, return that 194 if value, pending := s.pendingStorage[key]; pending { 195 return value 196 } 197 if value, cached := s.originStorage[key]; cached { 198 return value 199 } 200 // Track the amount of time wasted on reading the storage trie 201 if metrics.EnabledExpensive { 202 defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now()) 203 } 204 // Otherwise load the value from the database 205 enc, err := s.getTrie(db).TryGet(key[:]) 206 if err != nil { 207 s.setError(err) 208 return common.Hash{} 209 } 210 var value common.Hash 211 if len(enc) > 0 { 212 _, content, _, err := rlp.Split(enc) 213 if err != nil { 214 s.setError(err) 215 } 216 value.SetBytes(content) 217 } 218 s.originStorage[key] = value 219 return value 220 } 221 222 // SetState updates a value in account storage. 223 func (s *stateObject) SetState(db Database, key, value common.Hash) { 224 // If the fake storage is set, put the temporary state update here. 225 if s.fakeStorage != nil { 226 s.fakeStorage[key] = value 227 return 228 } 229 // If the new value is the same as old, don't set 230 prev := s.GetState(db, key) 231 if prev == value { 232 return 233 } 234 // New value is different, update and journal the change 235 s.db.journal.append(storageChange{ 236 account: &s.address, 237 key: key, 238 prevalue: prev, 239 }) 240 s.setState(key, value) 241 } 242 243 // SetStorage replaces the entire state storage with the given one. 244 // 245 // After this function is called, all original state will be ignored and state 246 // lookup only happens in the fake state storage. 247 // 248 // Note this function should only be used for debugging purpose. 249 func (s *stateObject) SetStorage(storage map[common.Hash]common.Hash) { 250 // Allocate fake storage if it's nil. 251 if s.fakeStorage == nil { 252 s.fakeStorage = make(Storage) 253 } 254 for key, value := range storage { 255 s.fakeStorage[key] = value 256 } 257 // Don't bother journal since this function should only be used for 258 // debugging and the `fake` storage won't be committed to database. 259 } 260 261 func (s *stateObject) setState(key, value common.Hash) { 262 s.dirtyStorage[key] = value 263 } 264 265 // finalise moves all dirty storage slots into the pending area to be hashed or 266 // committed later. It is invoked at the end of every transaction. 267 func (s *stateObject) finalise() { 268 for key, value := range s.dirtyStorage { 269 s.pendingStorage[key] = value 270 } 271 if len(s.dirtyStorage) > 0 { 272 s.dirtyStorage = make(Storage) 273 } 274 } 275 276 // updateTrie writes cached storage modifications into the object's storage trie. 277 func (s *stateObject) updateTrie(db Database) Trie { 278 // Make sure all dirty slots are finalized into the pending storage area 279 s.finalise() 280 281 // Track the amount of time wasted on updating the storge trie 282 if metrics.EnabledExpensive { 283 defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) 284 } 285 // Insert all the pending updates into the trie 286 tr := s.getTrie(db) 287 for key, value := range s.pendingStorage { 288 // Skip noop changes, persist actual changes 289 if value == s.originStorage[key] { 290 continue 291 } 292 s.originStorage[key] = value 293 294 if (value == common.Hash{}) { 295 s.setError(tr.TryDelete(key[:])) 296 continue 297 } 298 // Encoding []byte cannot fail, ok to ignore the error. 299 v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) 300 s.setError(tr.TryUpdate(key[:], v)) 301 } 302 if len(s.pendingStorage) > 0 { 303 s.pendingStorage = make(Storage) 304 } 305 return tr 306 } 307 308 // UpdateRoot sets the trie root to the current root hash of 309 func (s *stateObject) updateRoot(db Database) { 310 s.updateTrie(db) 311 312 // Track the amount of time wasted on hashing the storge trie 313 if metrics.EnabledExpensive { 314 defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) 315 } 316 s.data.Root = s.trie.Hash() 317 } 318 319 // CommitTrie the storage trie of the object to db. 320 // This updates the trie root. 321 func (s *stateObject) CommitTrie(db Database) error { 322 s.updateTrie(db) 323 if s.dbErr != nil { 324 return s.dbErr 325 } 326 // Track the amount of time wasted on committing the storge trie 327 if metrics.EnabledExpensive { 328 defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) 329 } 330 root, err := s.trie.Commit(nil) 331 if err == nil { 332 s.data.Root = root 333 } 334 return err 335 } 336 337 // AddBalance adds amount to c's balance. 338 // It is used to add funds to the destination account of a transfer. 339 func (s *stateObject) AddBalance(amount *big.Int) { 340 // EIP158: We must check emptiness for the objects such that the account 341 // clearing (0,0,0 objects) can take effect. 342 if amount.Sign() == 0 { 343 if s.empty() { 344 s.touch() 345 } 346 347 return 348 } 349 s.SetBalance(new(big.Int).Add(s.Balance(), amount)) 350 } 351 352 // SubBalance removes amount from c's balance. 353 // It is used to remove funds from the origin account of a transfer. 354 func (s *stateObject) SubBalance(amount *big.Int) { 355 if amount.Sign() == 0 { 356 return 357 } 358 s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) 359 } 360 361 func (s *stateObject) SetBalance(amount *big.Int) { 362 s.db.journal.append(balanceChange{ 363 account: &s.address, 364 prev: new(big.Int).Set(s.data.Balance), 365 }) 366 s.setBalance(amount) 367 } 368 369 func (s *stateObject) setBalance(amount *big.Int) { 370 s.data.Balance = amount 371 } 372 373 // Return the gas back to the origin. Used by the Virtual machine or Closures 374 func (s *stateObject) ReturnGas(gas *big.Int) {} 375 376 func (s *stateObject) deepCopy(db *StateDB) *stateObject { 377 stateObject := newObject(db, s.address, s.data) 378 if s.trie != nil { 379 stateObject.trie = db.db.CopyTrie(s.trie) 380 } 381 stateObject.code = s.code 382 stateObject.dirtyStorage = s.dirtyStorage.Copy() 383 stateObject.originStorage = s.originStorage.Copy() 384 stateObject.pendingStorage = s.pendingStorage.Copy() 385 stateObject.suicided = s.suicided 386 stateObject.dirtyCode = s.dirtyCode 387 stateObject.deleted = s.deleted 388 return stateObject 389 } 390 391 // 392 // Attribute accessors 393 // 394 395 // Returns the address of the contract/account 396 func (s *stateObject) Address() common.Address { 397 return s.address 398 } 399 400 // Code returns the contract code associated with this object, if any. 401 func (s *stateObject) Code(db Database) []byte { 402 if s.code != nil { 403 return s.code 404 } 405 if bytes.Equal(s.CodeHash(), emptyCodeHash) { 406 return nil 407 } 408 code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) 409 if err != nil { 410 s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) 411 } 412 s.code = code 413 return code 414 } 415 416 func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { 417 prevcode := s.Code(s.db.db) 418 s.db.journal.append(codeChange{ 419 account: &s.address, 420 prevhash: s.CodeHash(), 421 prevcode: prevcode, 422 }) 423 s.setCode(codeHash, code) 424 } 425 426 func (s *stateObject) setCode(codeHash common.Hash, code []byte) { 427 s.code = code 428 s.data.CodeHash = codeHash[:] 429 s.dirtyCode = true 430 } 431 432 func (s *stateObject) SetNonce(nonce uint64) { 433 s.db.journal.append(nonceChange{ 434 account: &s.address, 435 prev: s.data.Nonce, 436 }) 437 s.setNonce(nonce) 438 } 439 440 func (s *stateObject) setNonce(nonce uint64) { 441 s.data.Nonce = nonce 442 } 443 444 func (s *stateObject) CodeHash() []byte { 445 return s.data.CodeHash 446 } 447 448 func (s *stateObject) Balance() *big.Int { 449 return s.data.Balance 450 } 451 452 func (s *stateObject) Nonce() uint64 { 453 return s.data.Nonce 454 } 455 456 // Never called, but must be present to allow stateObject to be used 457 // as a vm.Account interface that also satisfies the vm.ContractRef 458 // interface. Interfaces are awesome. 459 func (s *stateObject) Value() *big.Int { 460 panic("Value on stateObject should never be called") 461 }