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  }