github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/state_object.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/big" 8 "sync" 9 10 "github.com/VictoriaMetrics/fastcache" 11 ethcmn "github.com/ethereum/go-ethereum/common" 12 ethstate "github.com/ethereum/go-ethereum/core/state" 13 ethtypes "github.com/ethereum/go-ethereum/core/types" 14 ethcrypto "github.com/ethereum/go-ethereum/crypto" 15 "github.com/ethereum/go-ethereum/rlp" 16 "github.com/fibonacci-chain/fbc/app/types" 17 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt" 18 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 19 authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported" 20 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 21 lru "github.com/hashicorp/golang-lru" 22 ) 23 24 const keccak256HashSize = 100000 25 26 var ( 27 _ StateObject = (*stateObject)(nil) 28 29 emptyCodeHash = ethcrypto.Keccak256(nil) 30 keccak256HashCache, _ = lru.NewARC(keccak256HashSize) 31 keccak256HashFastCache = fastcache.New(128 * keccak256HashSize) // 32 + 20 + 32 32 33 keccakStatePool = &sync.Pool{ 34 New: func() interface{} { 35 return ethcrypto.NewKeccakState() 36 }, 37 } 38 39 addressKeyBytesPool = &sync.Pool{ 40 New: func() interface{} { 41 return &[ethcmn.AddressLength + ethcmn.HashLength]byte{} 42 }, 43 } 44 ) 45 46 func keccak256HashWithSyncPool(data ...[]byte) (h ethcmn.Hash) { 47 d := keccakStatePool.Get().(ethcrypto.KeccakState) 48 defer keccakStatePool.Put(d) 49 d.Reset() 50 for _, b := range data { 51 d.Write(b) 52 } 53 d.Read(h[:]) 54 return h 55 } 56 57 func keccak256HashWithLruCache(compositeKey []byte) ethcmn.Hash { 58 cacheKey := string(compositeKey) 59 if value, ok := keccak256HashCache.Get(cacheKey); ok { 60 return value.(ethcmn.Hash) 61 } 62 value := keccak256HashWithSyncPool(compositeKey) 63 keccak256HashCache.Add(cacheKey, value) 64 return value 65 } 66 67 func keccak256HashWithFastCache(compositeKey []byte) (hash ethcmn.Hash) { 68 if _, ok := keccak256HashFastCache.HasGet(hash[:0], compositeKey); ok { 69 return 70 } 71 hash = keccak256HashWithSyncPool(compositeKey) 72 keccak256HashFastCache.Set(compositeKey, hash[:]) 73 return 74 } 75 76 // Keccak256HashWithCache returns the Keccak256 hash of the given data. 77 // this function should not keep the reference of the input data after return. 78 func Keccak256HashWithCache(compositeKey []byte) ethcmn.Hash { 79 // if length of compositeKey + hash size is greater than 128, use lru cache 80 if len(compositeKey) > 128-ethcmn.HashLength { 81 return keccak256HashWithLruCache(compositeKey) 82 } else { 83 return keccak256HashWithFastCache(compositeKey) 84 } 85 } 86 87 // StateObject interface for interacting with state object 88 type StateObject interface { 89 GetCommittedState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash 90 GetState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash 91 SetState(db ethstate.Database, key, value ethcmn.Hash) 92 93 Code(db ethstate.Database) []byte 94 SetCode(codeHash ethcmn.Hash, code []byte) 95 CodeHash() []byte 96 97 AddBalance(amount *big.Int) 98 SubBalance(amount *big.Int) 99 SetBalance(amount *big.Int) 100 101 Balance() *big.Int 102 ReturnGas(gas *big.Int) 103 Address() ethcmn.Address 104 105 SetNonce(nonce uint64) 106 Nonce() uint64 107 108 SetStorage(storage map[ethcmn.Hash]ethcmn.Hash) 109 } 110 111 // stateObject represents an Ethereum account which is being modified. 112 // 113 // The usage pattern is as follows: 114 // First you need to obtain a state object. 115 // Account values can be accessed and modified through the object. 116 // Finally, call CommitTrie to write the modified storage trie into a database. 117 type stateObject struct { 118 trie ethstate.Trie // storage trie, which becomes non-nil on first access 119 stateRoot ethcmn.Hash // merkle root of the storage trie 120 121 code types.Code // contract bytecode, which gets set when code is loaded 122 // State objects are used by the consensus core and VM which are 123 // unable to deal with database-level errors. Any error that occurs 124 // during a database read is memoized here and will eventually be returned 125 // by StateDB.Commit. 126 originStorage ethstate.Storage // Storage cache of original entries to dedup rewrites 127 dirtyStorage ethstate.Storage // Storage entries that need to be flushed to disk 128 pendingStorage ethstate.Storage // Storage entries that need to be flushed to disk, at the end of an entire block 129 fakeStorage ethstate.Storage // Fake storage which constructed by caller for debugging purpose. 130 131 // DB error 132 dbErr error 133 stateDB *CommitStateDB 134 account *types.EthAccount 135 136 address ethcmn.Address 137 addrHash ethcmn.Hash 138 139 // cache flags 140 // 141 // When an object is marked suicided it will be delete from the trie during 142 // the "update" phase of the state transition. 143 dirtyCode bool // true if the code was updated 144 suicided bool 145 deleted bool 146 } 147 148 func newStateObject(db *CommitStateDB, accProto authexported.Account, stateRoot ethcmn.Hash) *stateObject { 149 ethermintAccount, ok := accProto.(*types.EthAccount) 150 if !ok { 151 panic(fmt.Sprintf("invalid account type for state object: %T", accProto)) 152 } 153 154 // set empty code hash 155 if ethermintAccount.CodeHash == nil { 156 ethermintAccount.CodeHash = emptyCodeHash 157 } 158 if stateRoot == (ethcmn.Hash{}) { 159 stateRoot = ethtypes.EmptyRootHash 160 } 161 162 ethAddr := ethermintAccount.EthAddress() 163 return &stateObject{ 164 stateDB: db, 165 stateRoot: stateRoot, 166 account: ethermintAccount, 167 address: ethAddr, 168 addrHash: ethcrypto.Keccak256Hash(ethAddr[:]), 169 originStorage: make(ethstate.Storage), 170 pendingStorage: make(ethstate.Storage), 171 dirtyStorage: make(ethstate.Storage), 172 } 173 } 174 175 // ---------------------------------------------------------------------------- 176 // Setters 177 // ---------------------------------------------------------------------------- 178 179 // SetState updates a value in account storage. Note, the key will be prefixed 180 // with the address of the state object. 181 func (so *stateObject) SetState(db ethstate.Database, key, value ethcmn.Hash) { 182 // If the fake storage is set, put the temporary state update here. 183 if so.fakeStorage != nil { 184 so.fakeStorage[key] = value 185 return 186 } 187 // If the new value is the same as old, don't set 188 prev := so.GetState(db, key) 189 if prev == value { 190 return 191 } 192 193 // New value is different, update and journal the change 194 so.stateDB.journal.append(storageChange{ 195 account: &so.address, 196 key: key, 197 prevValue: prev, 198 }) 199 so.setState(key, value) 200 } 201 202 // setState sets a state with a prefixed key and value to the dirty storage. 203 func (so *stateObject) setState(key, value ethcmn.Hash) { 204 so.dirtyStorage[key] = value 205 } 206 207 // SetCode sets the state object's code. 208 func (so *stateObject) SetCode(codeHash ethcmn.Hash, code []byte) { 209 prevCode := so.Code(so.stateDB.db) 210 so.stateDB.journal.append(codeChange{ 211 account: &so.address, 212 prevHash: so.CodeHash(), 213 prevCode: prevCode, 214 }) 215 so.setCode(codeHash, code) 216 } 217 218 func (so *stateObject) setCode(codeHash ethcmn.Hash, code []byte) { 219 so.code = code 220 so.account.CodeHash = codeHash.Bytes() 221 so.dirtyCode = true 222 } 223 224 // AddBalance adds an amount to a state object's balance. It is used to add 225 // funds to the destination account of a transfer. 226 func (so *stateObject) AddBalance(amount *big.Int) { 227 amt := sdk.NewDecFromBigIntWithPrec(amount, sdk.Precision) // int2dec 228 // EIP158: We must check emptiness for the objects such that the account 229 // clearing (0,0,0 objects) can take effect. 230 231 // NOTE: this will panic if amount is nil 232 if amt.IsZero() { 233 if so.empty() { 234 so.touch() 235 } 236 return 237 } 238 239 newBalance := so.account.GetCoins().AmountOf(sdk.DefaultBondDenom).Add(amt) 240 so.SetBalance(newBalance.BigInt()) 241 } 242 243 // SubBalance removes an amount from the stateObject's balance. It is used to 244 // remove funds from the origin account of a transfer. 245 func (so *stateObject) SubBalance(amount *big.Int) { 246 amt := sdk.NewDecFromBigIntWithPrec(amount, sdk.Precision) // int2dec 247 if amt.IsZero() { 248 return 249 } 250 newBalance := so.account.GetCoins().AmountOf(sdk.DefaultBondDenom).Sub(amt) 251 so.SetBalance(newBalance.BigInt()) 252 } 253 254 // SetBalance sets the state object's balance. 255 func (so *stateObject) SetBalance(amount *big.Int) { 256 amt := sdk.NewDecFromBigIntWithPrec(amount, sdk.Precision) // int2dec 257 258 so.stateDB.journal.append(balanceChange{ 259 account: &so.address, 260 prev: so.account.GetCoins().AmountOf(sdk.DefaultBondDenom), // int2dec 261 }) 262 263 so.setBalance(sdk.DefaultBondDenom, amt) 264 } 265 266 func (so *stateObject) setBalance(denom string, amount sdk.Dec) { 267 so.account.SetBalance(denom, amount) 268 } 269 270 // SetNonce sets the state object's nonce (i.e sequence number of the account). 271 func (so *stateObject) SetNonce(nonce uint64) { 272 so.stateDB.journal.append(nonceChange{ 273 account: &so.address, 274 prev: so.account.Sequence, 275 }) 276 277 so.setNonce(nonce) 278 } 279 280 func (so *stateObject) setNonce(nonce uint64) { 281 if so.account == nil { 282 panic("state object account is empty") 283 } 284 so.account.Sequence = nonce 285 } 286 287 // setError remembers the first non-nil error it is called with. 288 func (so *stateObject) setError(err error) { 289 if err != nil { 290 so.stateDB.Logger().Debug("stateObject", "error", err) 291 } 292 if so.dbErr == nil { 293 so.dbErr = err 294 } 295 } 296 297 func (so *stateObject) markSuicided() { 298 so.suicided = true 299 } 300 301 // commitState commits all dirty storage to a KVStore and resets 302 // the dirty storage slice to the empty state. 303 func (so *stateObject) commitState(db ethstate.Database) { 304 // Make sure all dirty slots are finalized into the pending storage area 305 so.finalise(false) // Don't prefetch any more, pull directly if need be 306 if len(so.pendingStorage) == 0 { 307 return 308 } 309 310 var tr ethstate.Trie = nil 311 if mpt.TrieWriteAhead { 312 tr = so.getTrie(db) 313 } 314 usedStorage := make([][]byte, 0, len(so.pendingStorage)) 315 316 ctx := so.stateDB.ctx 317 store := so.stateDB.dbAdapter.NewStore(ctx.KVStore(so.stateDB.storeKey), AddressStoragePrefix(so.Address())) 318 for key, value := range so.pendingStorage { 319 // Skip noop changes, persist actual changes 320 if value == so.originStorage[key] { 321 continue 322 } 323 so.originStorage[key] = value 324 325 prefixKey := GetStorageByAddressKey(so.Address().Bytes(), key.Bytes()) 326 if (value == ethcmn.Hash{}) { 327 store.Delete(prefixKey.Bytes()) 328 so.stateDB.ctx.Cache().UpdateStorage(so.address, prefixKey, value.Bytes(), true) 329 if !so.stateDB.ctx.IsCheckTx() { 330 if so.stateDB.ctx.GetWatcher().Enabled() { 331 so.stateDB.ctx.GetWatcher().SaveState(so.Address(), prefixKey.Bytes(), ethcmn.Hash{}.Bytes()) 332 } 333 } 334 } else { 335 store.Set(prefixKey.Bytes(), value.Bytes()) 336 so.stateDB.ctx.Cache().UpdateStorage(so.address, prefixKey, value.Bytes(), true) 337 if !so.stateDB.ctx.IsCheckTx() { 338 if so.stateDB.ctx.GetWatcher().Enabled() { 339 so.stateDB.ctx.GetWatcher().SaveState(so.Address(), prefixKey.Bytes(), value.Bytes()) 340 } 341 } 342 } 343 if mpt.TrieWriteAhead { 344 if TrieUseCompositeKey { 345 key = prefixKey 346 } 347 348 usedStorage = append(usedStorage, ethcmn.CopyBytes(key[:])) // Copy needed for closure 349 if (value == ethcmn.Hash{}) { 350 so.setError(tr.TryDelete(key[:])) 351 } else { 352 // Encoding []byte cannot fail, ok to ignore the error. 353 v, _ := rlp.EncodeToBytes(ethcmn.TrimLeftZeroes(value[:])) 354 so.setError(tr.TryUpdate(key[:], v)) 355 } 356 } 357 } 358 359 if so.stateDB.prefetcher != nil && mpt.TrieWriteAhead { 360 so.stateDB.prefetcher.Used(so.stateRoot, usedStorage) 361 } 362 363 if len(so.pendingStorage) > 0 { 364 so.pendingStorage = make(ethstate.Storage) 365 } 366 367 return 368 } 369 370 // commitCode persists the state object's code to the KVStore. 371 func (so *stateObject) commitCode() { 372 ctx := so.stateDB.ctx 373 store := so.stateDB.dbAdapter.NewStore(ctx.KVStore(so.stateDB.storeKey), KeyPrefixCode) 374 store.Set(so.CodeHash(), so.code) 375 ctx.Cache().UpdateCode(so.CodeHash(), so.code, true) 376 } 377 378 // ---------------------------------------------------------------------------- 379 // Getters 380 // ---------------------------------------------------------------------------- 381 382 // Address returns the address of the state object. 383 func (so *stateObject) Address() ethcmn.Address { 384 return so.address 385 } 386 387 // Balance returns the state object's current balance. 388 func (so *stateObject) Balance() *big.Int { 389 balance := so.account.Balance(sdk.DefaultBondDenom).BigInt() 390 if balance == nil { 391 return zeroBalance 392 } 393 return balance 394 } 395 396 // CodeHash returns the state object's code hash. 397 func (so *stateObject) CodeHash() []byte { 398 if so.account == nil || len(so.account.CodeHash) == 0 { 399 return emptyCodeHash 400 } 401 return so.account.CodeHash 402 } 403 404 // Nonce returns the state object's current nonce (sequence number). 405 func (so *stateObject) Nonce() uint64 { 406 if so.account == nil { 407 return 0 408 } 409 return so.account.Sequence 410 } 411 412 // Code returns the contract code associated with this object, if any. 413 func (so *stateObject) Code(db ethstate.Database) []byte { 414 if tmtypes.HigherThanMars(so.stateDB.ctx.BlockHeight()) { 415 return so.CodeInRawDB(db) 416 } 417 418 if len(so.code) > 0 { 419 return so.code 420 } 421 422 if bytes.Equal(so.CodeHash(), emptyCodeHash) { 423 return nil 424 } 425 426 code := make([]byte, 0) 427 ctx := &so.stateDB.ctx 428 if data, ok := ctx.Cache().GetCode(so.CodeHash()); ok { 429 code = data 430 } else { 431 store := so.stateDB.dbAdapter.NewStore(ctx.KVStore(so.stateDB.storeKey), KeyPrefixCode) 432 code = store.Get(so.CodeHash()) 433 ctx.Cache().UpdateCode(so.CodeHash(), code, false) 434 } 435 436 if len(code) == 0 { 437 so.setError(fmt.Errorf("failed to get code hash %x for address %s", so.CodeHash(), so.Address().String())) 438 } else { 439 so.code = code 440 } 441 442 return code 443 } 444 445 // GetState retrieves a value from the account storage trie. Note, the key will 446 // be prefixed with the address of the state object. 447 func (so *stateObject) GetState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash { 448 // If the fake storage is set, only lookup the state here(in the debugging mode) 449 if so.fakeStorage != nil { 450 return so.fakeStorage[key] 451 } 452 // if we have a dirty value for this state entry, return it 453 value, dirty := so.dirtyStorage[key] 454 if dirty { 455 return value 456 } 457 458 // otherwise return the entry's original value 459 return so.GetCommittedState(db, key) 460 } 461 462 // GetCommittedState retrieves a value from the committed account storage trie. 463 // 464 // NOTE: the key will be prefixed with the address of the state object. 465 func (so *stateObject) GetCommittedState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash { 466 if tmtypes.HigherThanMars(so.stateDB.ctx.BlockHeight()) { 467 return so.GetCommittedStateMpt(db, key) 468 } 469 470 // If the fake storage is set, only lookup the state here(in the debugging mode) 471 if so.fakeStorage != nil { 472 return so.fakeStorage[key] 473 } 474 475 // If we have a pending write or clean cached, return that 476 if value, pending := so.pendingStorage[key]; pending { 477 return value 478 } 479 if value, cached := so.originStorage[key]; cached { 480 return value 481 } 482 483 // otherwise load the value from the KVStore 484 state := NewState(key, ethcmn.Hash{}) 485 486 ctx := &so.stateDB.ctx 487 rawValue := make([]byte, 0) 488 var ok bool 489 490 prefixKey := GetStorageByAddressKey(so.Address().Bytes(), key.Bytes()) 491 rawValue, ok = ctx.Cache().GetStorage(so.address, prefixKey) 492 if !ok { 493 store := so.stateDB.dbAdapter.NewStore(ctx.KVStore(so.stateDB.storeKey), AddressStoragePrefix(so.Address())) 494 rawValue = store.Get(prefixKey.Bytes()) 495 ctx.Cache().UpdateStorage(so.address, prefixKey, rawValue, false) 496 } 497 498 if len(rawValue) > 0 { 499 state.Value.SetBytes(rawValue) 500 } 501 502 so.originStorage[key] = state.Value 503 return state.Value 504 } 505 506 // ---------------------------------------------------------------------------- 507 // Auxiliary 508 // ---------------------------------------------------------------------------- 509 510 // ReturnGas returns the gas back to the origin. Used by the Virtual machine or 511 // Closures. It performs a no-op. 512 func (so *stateObject) ReturnGas(gas *big.Int) {} 513 514 func (so *stateObject) deepCopy(db *CommitStateDB) *stateObject { 515 if tmtypes.HigherThanMars(so.stateDB.ctx.BlockHeight()) { 516 return so.deepCopyMpt(db) 517 } 518 519 newAccount := types.ProtoAccount().(*types.EthAccount) 520 jsonAccount, err := so.account.MarshalJSON() 521 if err != nil { 522 return nil 523 } 524 err = newAccount.UnmarshalJSON(jsonAccount) 525 if err != nil { 526 return nil 527 } 528 newStateObj := newStateObject(db, newAccount, so.stateRoot) 529 530 newStateObj.code = make(types.Code, len(so.code)) 531 copy(newStateObj.code, so.code) 532 newStateObj.dirtyStorage = so.dirtyStorage.Copy() 533 newStateObj.originStorage = so.originStorage.Copy() 534 newStateObj.suicided = so.suicided 535 newStateObj.dirtyCode = so.dirtyCode 536 newStateObj.deleted = so.deleted 537 538 return newStateObj 539 } 540 541 // empty returns whether the account is considered empty. 542 func (so *stateObject) empty() bool { 543 balace := so.account.Balance(sdk.DefaultBondDenom) 544 return so.account == nil || 545 (so.account != nil && 546 so.account.Sequence == 0 && 547 (balace.BigInt() == nil || balace.IsZero()) && 548 bytes.Equal(so.account.CodeHash, emptyCodeHash)) 549 } 550 551 // EncodeRLP implements rlp.Encoder. 552 func (so *stateObject) EncodeRLP(w io.Writer) error { 553 return rlp.Encode(w, so.account) 554 } 555 556 func (so *stateObject) touch() { 557 so.stateDB.journal.append(touchChange{ 558 account: &so.address, 559 }) 560 561 if so.address == ripemd { 562 // Explicitly put it in the dirty-cache, which is otherwise generated from 563 // flattened journals. 564 so.stateDB.journal.dirty(so.address) 565 } 566 } 567 568 // GetStorageByAddressKey returns a hash of the composite key for a state 569 // object's storage prefixed with it's address. 570 func GetStorageByAddressKey(prefix, key []byte) ethcmn.Hash { 571 var compositeKey []byte 572 if len(prefix)+len(key) == ethcmn.AddressLength+ethcmn.HashLength { 573 p := addressKeyBytesPool.Get().(*[ethcmn.AddressLength + ethcmn.HashLength]byte) 574 defer addressKeyBytesPool.Put(p) 575 compositeKey = p[:] 576 } else { 577 compositeKey = make([]byte, len(prefix)+len(key)) 578 } 579 580 copy(compositeKey, prefix) 581 copy(compositeKey[len(prefix):], key) 582 return Keccak256HashWithCache(compositeKey) 583 } 584 585 // stateEntry represents a single key value pair from the StateDB's stateObject mappindg. 586 // This is to prevent non determinism at genesis initialization or export. 587 type stateEntry struct { 588 // address key of the state object 589 address ethcmn.Address 590 stateObject *stateObject 591 }