github.com/onflow/flow-go@v0.33.17/fvm/evm/emulator/state/base.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	gethCommon "github.com/ethereum/go-ethereum/common"
     8  	gethTypes "github.com/ethereum/go-ethereum/core/types"
     9  	"github.com/onflow/atree"
    10  
    11  	"github.com/onflow/flow-go/fvm/evm/types"
    12  	"github.com/onflow/flow-go/model/flow"
    13  )
    14  
    15  const (
    16  	// AccountsStorageIDKey is the path where we store the collection ID for accounts
    17  	AccountsStorageIDKey = "AccountsStorageIDKey"
    18  	// CodesStorageIDKey is the path where we store the collection ID for codes
    19  	CodesStorageIDKey = "CodesStorageIDKey"
    20  )
    21  
    22  // BaseView implements a types.BaseView
    23  // it acts as the base layer of state queries for the stateDB
    24  // it stores accounts, codes and storage slots.
    25  //
    26  // under the hood it uses a set of collections,
    27  // one for account's meta data, one for codes
    28  // and one for each of account storage space.
    29  type BaseView struct {
    30  	rootAddress        flow.Address
    31  	ledger             atree.Ledger
    32  	collectionProvider *CollectionProvider
    33  
    34  	// collections
    35  	accounts *Collection
    36  	codes    *Collection
    37  	slots    map[gethCommon.Address]*Collection
    38  
    39  	// cached values
    40  	cachedAccounts map[gethCommon.Address]*Account
    41  	cachedCodes    map[gethCommon.Address][]byte
    42  	cachedSlots    map[types.SlotAddress]gethCommon.Hash
    43  
    44  	// flags
    45  	accountSetupOnCommit bool
    46  	codeSetupOnCommit    bool
    47  }
    48  
    49  var _ types.BaseView = &BaseView{}
    50  
    51  // NewBaseView constructs a new base view
    52  func NewBaseView(ledger atree.Ledger, rootAddress flow.Address) (*BaseView, error) {
    53  	cp, err := NewCollectionProvider(atree.Address(rootAddress), ledger)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	view := &BaseView{
    59  		ledger:             ledger,
    60  		rootAddress:        rootAddress,
    61  		collectionProvider: cp,
    62  
    63  		slots: make(map[gethCommon.Address]*Collection),
    64  
    65  		cachedAccounts: make(map[gethCommon.Address]*Account),
    66  		cachedCodes:    make(map[gethCommon.Address][]byte),
    67  		cachedSlots:    make(map[types.SlotAddress]gethCommon.Hash),
    68  	}
    69  
    70  	// fetch the account collection, if not exist, create one
    71  	view.accounts, view.accountSetupOnCommit, err = view.fetchOrCreateCollection(AccountsStorageIDKey)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// fetch the code collection, if not exist, create one
    77  	view.codes, view.codeSetupOnCommit, err = view.fetchOrCreateCollection(CodesStorageIDKey)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return view, nil
    83  }
    84  
    85  // Exist returns true if the address exist in the state
    86  func (v *BaseView) Exist(addr gethCommon.Address) (bool, error) {
    87  	acc, err := v.getAccount(addr)
    88  	return acc != nil, err
    89  }
    90  
    91  // IsCreated returns true if the address has been created in the context of this transaction
    92  func (v *BaseView) IsCreated(gethCommon.Address) bool {
    93  	return false
    94  }
    95  
    96  // HasSelfDestructed returns true if an address is flagged for destruction at the end of transaction
    97  func (v *BaseView) HasSelfDestructed(gethCommon.Address) (bool, *big.Int) {
    98  	return false, new(big.Int)
    99  }
   100  
   101  // GetBalance returns the balance of an address
   102  //
   103  // for non-existent accounts it returns a balance of zero
   104  func (v *BaseView) GetBalance(addr gethCommon.Address) (*big.Int, error) {
   105  	acc, err := v.getAccount(addr)
   106  	bal := big.NewInt(0)
   107  	if acc != nil {
   108  		bal = acc.Balance
   109  	}
   110  	return bal, err
   111  }
   112  
   113  // GetNonce returns the nonce of an address
   114  //
   115  // for non-existent accounts it returns zero
   116  func (v *BaseView) GetNonce(addr gethCommon.Address) (uint64, error) {
   117  	acc, err := v.getAccount(addr)
   118  	nonce := uint64(0)
   119  	if acc != nil {
   120  		nonce = acc.Nonce
   121  	}
   122  	return nonce, err
   123  }
   124  
   125  // GetCode returns the code of an address
   126  //
   127  // for non-existent accounts or accounts without a code (e.g. EOAs) it returns nil
   128  func (v *BaseView) GetCode(addr gethCommon.Address) ([]byte, error) {
   129  	return v.getCode(addr)
   130  }
   131  
   132  // GetCodeHash returns the code hash of an address
   133  //
   134  // for non-existent accounts or accounts without a code (e.g. EOAs) it returns default empty
   135  // hash value (gethTypes.EmptyCodeHash)
   136  func (v *BaseView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) {
   137  	acc, err := v.getAccount(addr)
   138  	codeHash := gethTypes.EmptyCodeHash
   139  	if acc != nil {
   140  		codeHash = acc.CodeHash
   141  	}
   142  	return codeHash, err
   143  }
   144  
   145  // GetCodeSize returns the code size of an address
   146  //
   147  // for non-existent accounts or accounts without a code (e.g. EOAs) it returns zero
   148  func (v *BaseView) GetCodeSize(addr gethCommon.Address) (int, error) {
   149  	code, err := v.GetCode(addr)
   150  	return len(code), err
   151  }
   152  
   153  // GetState returns values for a slot in the main storage
   154  //
   155  // for non-existent slots it returns the default empty hash value (gethTypes.EmptyCodeHash)
   156  func (v *BaseView) GetState(sk types.SlotAddress) (gethCommon.Hash, error) {
   157  	return v.getSlot(sk)
   158  }
   159  
   160  // UpdateSlot updates the value for a slot
   161  func (v *BaseView) UpdateSlot(sk types.SlotAddress, value gethCommon.Hash) error {
   162  	return v.storeSlot(sk, value)
   163  }
   164  
   165  // GetRefund returns the total amount of (gas) refund
   166  //
   167  // this method returns the value of zero
   168  func (v *BaseView) GetRefund() uint64 {
   169  	return 0
   170  }
   171  
   172  // GetTransientState returns values for an slot transient storage
   173  //
   174  // transient storage is not a functionality for the base view so it always
   175  // returns the default value for non-existent slots
   176  func (v *BaseView) GetTransientState(types.SlotAddress) gethCommon.Hash {
   177  	return gethCommon.Hash{}
   178  }
   179  
   180  // AddressInAccessList checks if an address is in the access list
   181  //
   182  // access list control is not a functionality of the base view
   183  // it always returns false
   184  func (v *BaseView) AddressInAccessList(gethCommon.Address) bool {
   185  	return false
   186  }
   187  
   188  // SlotInAccessList checks if a slot is in the access list
   189  //
   190  // access list control is not a functionality of the base view
   191  // it always returns false
   192  func (v *BaseView) SlotInAccessList(types.SlotAddress) (addressOk bool, slotOk bool) {
   193  	return false, false
   194  }
   195  
   196  // CreateAccount creates a new account
   197  func (v *BaseView) CreateAccount(
   198  	addr gethCommon.Address,
   199  	balance *big.Int,
   200  	nonce uint64,
   201  	code []byte,
   202  	codeHash gethCommon.Hash,
   203  ) error {
   204  	var colID []byte
   205  	// if is an smart contract account
   206  	if len(code) > 0 {
   207  		err := v.storeCode(addr, code)
   208  		if err != nil {
   209  			return err
   210  		}
   211  	}
   212  
   213  	// create a new account and store it
   214  	acc := NewAccount(addr, balance, nonce, codeHash, colID)
   215  
   216  	// no need to update the cache , storeAccount would update the cache
   217  	return v.storeAccount(acc)
   218  }
   219  
   220  // UpdateAccount updates an account's meta data
   221  func (v *BaseView) UpdateAccount(
   222  	addr gethCommon.Address,
   223  	balance *big.Int,
   224  	nonce uint64,
   225  	code []byte,
   226  	codeHash gethCommon.Hash,
   227  ) error {
   228  	acc, err := v.getAccount(addr)
   229  	if err != nil {
   230  		return err
   231  	}
   232  	// if update is called on a non existing account
   233  	// we gracefully call the create account
   234  	// TODO: but we might need to revisit this action in the future
   235  	if acc == nil {
   236  		return v.CreateAccount(addr, balance, nonce, code, codeHash)
   237  	}
   238  	// if it has a code change
   239  	if codeHash != acc.CodeHash {
   240  		err := v.storeCode(addr, code)
   241  		if err != nil {
   242  			return err
   243  		}
   244  		// TODO: maybe purge the state in the future as well
   245  		// currently the behaviour of stateDB doesn't purge the data
   246  		// We don't need to check if the code is empty and we purge the state
   247  		// this is not possible right now.
   248  	}
   249  	newAcc := NewAccount(addr, balance, nonce, codeHash, acc.CollectionID)
   250  	// no need to update the cache , storeAccount would update the cache
   251  	return v.storeAccount(newAcc)
   252  }
   253  
   254  // DeleteAccount deletes an account's meta data, code, and
   255  // storage slots associated with that address
   256  func (v *BaseView) DeleteAccount(addr gethCommon.Address) error {
   257  	// 1. check account exists
   258  	acc, err := v.getAccount(addr)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	if acc == nil {
   263  		return fmt.Errorf("account doesn't exist to be deleted")
   264  	}
   265  
   266  	// 2. update the cache
   267  	delete(v.cachedAccounts, addr)
   268  
   269  	// 3. collections
   270  	err = v.accounts.Remove(addr.Bytes())
   271  	if err != nil {
   272  		return err
   273  	}
   274  
   275  	// 4. remove the code
   276  	if acc.HasCode() {
   277  		err = v.storeCode(addr, nil)
   278  		if err != nil {
   279  			return err
   280  		}
   281  	}
   282  
   283  	// 5. remove storage slots
   284  	if len(acc.CollectionID) > 0 {
   285  		col, found := v.slots[addr]
   286  		if !found {
   287  			col, err = v.collectionProvider.CollectionByID(acc.CollectionID)
   288  			if err != nil {
   289  				return err
   290  			}
   291  		}
   292  		// delete all slots related to this account (eip-6780)
   293  		keys, err := col.Destroy()
   294  		if err != nil {
   295  			return err
   296  		}
   297  
   298  		delete(v.slots, addr)
   299  
   300  		for _, key := range keys {
   301  			delete(v.cachedSlots, types.SlotAddress{
   302  				Address: addr,
   303  				Key:     gethCommon.BytesToHash(key),
   304  			})
   305  		}
   306  	}
   307  	return nil
   308  }
   309  
   310  // Commit commits the changes to the underlying storage layers
   311  func (v *BaseView) Commit() error {
   312  	// commit collection changes
   313  	err := v.collectionProvider.Commit()
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	// if this is the first time we are setting up an
   319  	// account collection, store its collection id.
   320  	if v.accountSetupOnCommit {
   321  		err = v.ledger.SetValue(v.rootAddress[:], []byte(AccountsStorageIDKey), v.accounts.CollectionID())
   322  		if err != nil {
   323  			return err
   324  		}
   325  		v.accountSetupOnCommit = false
   326  
   327  	}
   328  
   329  	// if this is the first time we are setting up an
   330  	// code collection, store its collection id.
   331  	if v.codeSetupOnCommit {
   332  		err = v.ledger.SetValue(v.rootAddress[:], []byte(CodesStorageIDKey), v.codes.CollectionID())
   333  		if err != nil {
   334  			return err
   335  		}
   336  		v.codeSetupOnCommit = false
   337  	}
   338  	return nil
   339  }
   340  
   341  func (v *BaseView) fetchOrCreateCollection(path string) (collection *Collection, created bool, error error) {
   342  	collectionID, err := v.ledger.GetValue(v.rootAddress[:], []byte(path))
   343  	if err != nil {
   344  		return nil, false, err
   345  	}
   346  	if len(collectionID) == 0 {
   347  		collection, err = v.collectionProvider.NewCollection()
   348  		return collection, true, err
   349  	}
   350  	collection, err = v.collectionProvider.CollectionByID(collectionID)
   351  	return collection, false, err
   352  }
   353  
   354  func (v *BaseView) getAccount(addr gethCommon.Address) (*Account, error) {
   355  	// check cached accounts first
   356  	acc, found := v.cachedAccounts[addr]
   357  	if found {
   358  		return acc, nil
   359  	}
   360  
   361  	// then collect it from the account collection
   362  	data, err := v.accounts.Get(addr.Bytes())
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  	// decode it
   367  	acc, err = DecodeAccount(data)
   368  	if err != nil {
   369  		return nil, err
   370  	}
   371  	// cache it
   372  	if acc != nil {
   373  		v.cachedAccounts[addr] = acc
   374  	}
   375  	return acc, nil
   376  }
   377  
   378  func (v *BaseView) storeAccount(acc *Account) error {
   379  	data, err := acc.Encode()
   380  	if err != nil {
   381  		return err
   382  	}
   383  	// update the cache
   384  	v.cachedAccounts[acc.Address] = acc
   385  	return v.accounts.Set(acc.Address.Bytes(), data)
   386  }
   387  
   388  func (v *BaseView) getCode(addr gethCommon.Address) ([]byte, error) {
   389  	// check the cache first
   390  	code, found := v.cachedCodes[addr]
   391  	if found {
   392  		return code, nil
   393  	}
   394  	// check if account exist in cache and has codeHash
   395  	acc, found := v.cachedAccounts[addr]
   396  	if found && !acc.HasCode() {
   397  		return nil, nil
   398  	}
   399  	// then collect it from the code collection
   400  	code, err := v.codes.Get(addr.Bytes())
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	if code != nil {
   405  		v.cachedCodes[addr] = code
   406  	}
   407  	return code, nil
   408  }
   409  
   410  func (v *BaseView) storeCode(addr gethCommon.Address, code []byte) error {
   411  	if len(code) == 0 {
   412  		delete(v.cachedCodes, addr)
   413  		return v.codes.Remove(addr.Bytes())
   414  	}
   415  	v.cachedCodes[addr] = code
   416  	return v.codes.Set(addr.Bytes(), code)
   417  }
   418  
   419  func (v *BaseView) getSlot(sk types.SlotAddress) (gethCommon.Hash, error) {
   420  	value, found := v.cachedSlots[sk]
   421  	if found {
   422  		return value, nil
   423  	}
   424  
   425  	acc, err := v.getAccount(sk.Address)
   426  	if err != nil {
   427  		return gethCommon.Hash{}, err
   428  	}
   429  	if acc == nil || len(acc.CollectionID) == 0 {
   430  		return gethCommon.Hash{}, nil
   431  	}
   432  
   433  	col, err := v.getSlotCollection(acc)
   434  	if err != nil {
   435  		return gethCommon.Hash{}, err
   436  	}
   437  
   438  	val, err := col.Get(sk.Key.Bytes())
   439  	if err != nil {
   440  		return gethCommon.Hash{}, err
   441  	}
   442  	value = gethCommon.BytesToHash(val)
   443  	v.cachedSlots[sk] = value
   444  	return value, nil
   445  }
   446  
   447  func (v *BaseView) storeSlot(sk types.SlotAddress, data gethCommon.Hash) error {
   448  	acc, err := v.getAccount(sk.Address)
   449  	if err != nil {
   450  		return err
   451  	}
   452  	if acc == nil {
   453  		return fmt.Errorf("slot belongs to a non-existing account")
   454  	}
   455  	if !acc.HasCode() {
   456  		return fmt.Errorf("slot belongs to a non-smart contract account")
   457  	}
   458  	col, err := v.getSlotCollection(acc)
   459  	if err != nil {
   460  		return err
   461  	}
   462  
   463  	emptyValue := gethCommon.Hash{}
   464  	if data == emptyValue {
   465  		delete(v.cachedSlots, sk)
   466  		return col.Remove(sk.Key.Bytes())
   467  	}
   468  	v.cachedSlots[sk] = data
   469  	return col.Set(sk.Key.Bytes(), data.Bytes())
   470  }
   471  
   472  func (v *BaseView) getSlotCollection(acc *Account) (*Collection, error) {
   473  	var err error
   474  
   475  	if len(acc.CollectionID) == 0 {
   476  		// create a new collection for slots
   477  		col, err := v.collectionProvider.NewCollection()
   478  		if err != nil {
   479  			return nil, err
   480  		}
   481  		// cache collection
   482  		v.slots[acc.Address] = col
   483  		// update account's collection ID
   484  		acc.CollectionID = col.CollectionID()
   485  		err = v.storeAccount(acc)
   486  		if err != nil {
   487  			return nil, err
   488  		}
   489  		return col, nil
   490  	}
   491  
   492  	col, found := v.slots[acc.Address]
   493  	if !found {
   494  		col, err = v.collectionProvider.CollectionByID(acc.CollectionID)
   495  		if err != nil {
   496  			return nil, err
   497  		}
   498  		v.slots[acc.Address] = col
   499  	}
   500  	return col, nil
   501  }