github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/emulator/state/base.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	"github.com/onflow/atree"
     8  	gethCommon "github.com/onflow/go-ethereum/common"
     9  	gethTypes "github.com/onflow/go-ethereum/core/types"
    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 it returns gethCommon.Hash{}
   135  // and for accounts without a code (e.g. EOAs) it returns default empty
   136  // hash value (gethTypes.EmptyCodeHash)
   137  func (v *BaseView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) {
   138  	acc, err := v.getAccount(addr)
   139  	codeHash := gethCommon.Hash{}
   140  	if acc != nil {
   141  		codeHash = acc.CodeHash
   142  	}
   143  	return codeHash, err
   144  }
   145  
   146  // GetCodeSize returns the code size of an address
   147  //
   148  // for non-existent accounts or accounts without a code (e.g. EOAs) it returns zero
   149  func (v *BaseView) GetCodeSize(addr gethCommon.Address) (int, error) {
   150  	code, err := v.GetCode(addr)
   151  	return len(code), err
   152  }
   153  
   154  // GetState returns values for a slot in the main storage
   155  //
   156  // for non-existent slots it returns the default empty hash value (gethTypes.EmptyCodeHash)
   157  func (v *BaseView) GetState(sk types.SlotAddress) (gethCommon.Hash, error) {
   158  	return v.getSlot(sk)
   159  }
   160  
   161  // UpdateSlot updates the value for a slot
   162  func (v *BaseView) UpdateSlot(sk types.SlotAddress, value gethCommon.Hash) error {
   163  	return v.storeSlot(sk, value)
   164  }
   165  
   166  // GetRefund returns the total amount of (gas) refund
   167  //
   168  // this method returns the value of zero
   169  func (v *BaseView) GetRefund() uint64 {
   170  	return 0
   171  }
   172  
   173  // GetTransientState returns values for an slot transient storage
   174  //
   175  // transient storage is not a functionality for the base view so it always
   176  // returns the default value for non-existent slots
   177  func (v *BaseView) GetTransientState(types.SlotAddress) gethCommon.Hash {
   178  	return gethCommon.Hash{}
   179  }
   180  
   181  // AddressInAccessList checks if an address is in the access list
   182  //
   183  // access list control is not a functionality of the base view
   184  // it always returns false
   185  func (v *BaseView) AddressInAccessList(gethCommon.Address) bool {
   186  	return false
   187  }
   188  
   189  // SlotInAccessList checks if a slot is in the access list
   190  //
   191  // access list control is not a functionality of the base view
   192  // it always returns false
   193  func (v *BaseView) SlotInAccessList(types.SlotAddress) (addressOk bool, slotOk bool) {
   194  	return false, false
   195  }
   196  
   197  // CreateAccount creates a new account
   198  func (v *BaseView) CreateAccount(
   199  	addr gethCommon.Address,
   200  	balance *big.Int,
   201  	nonce uint64,
   202  	code []byte,
   203  	codeHash gethCommon.Hash,
   204  ) error {
   205  	var colID []byte
   206  	// if is an smart contract account
   207  	if len(code) > 0 {
   208  		err := v.updateAccountCode(addr, code, codeHash)
   209  		if err != nil {
   210  			return err
   211  		}
   212  	}
   213  
   214  	// create a new account and store it
   215  	acc := NewAccount(addr, balance, nonce, codeHash, colID)
   216  
   217  	// no need to update the cache , storeAccount would update the cache
   218  	return v.storeAccount(acc)
   219  }
   220  
   221  // UpdateAccount updates an account's meta data
   222  func (v *BaseView) UpdateAccount(
   223  	addr gethCommon.Address,
   224  	balance *big.Int,
   225  	nonce uint64,
   226  	code []byte,
   227  	codeHash gethCommon.Hash,
   228  ) error {
   229  	acc, err := v.getAccount(addr)
   230  	if err != nil {
   231  		return err
   232  	}
   233  	// if update is called on a non existing account
   234  	// we gracefully call the create account
   235  	// TODO: but we might need to revisit this action in the future
   236  	if acc == nil {
   237  		return v.CreateAccount(addr, balance, nonce, code, codeHash)
   238  	}
   239  
   240  	// update account code
   241  	err = v.updateAccountCode(addr, code, codeHash)
   242  	if err != nil {
   243  		return err
   244  	}
   245  	// TODO: maybe purge the state in the future as well
   246  	// currently the behaviour of stateDB doesn't purge the data
   247  	// We don't need to check if the code is empty and we purge the state
   248  	// this is not possible right now.
   249  
   250  	newAcc := NewAccount(addr, balance, nonce, codeHash, acc.CollectionID)
   251  	// no need to update the cache , storeAccount would update the cache
   252  	return v.storeAccount(newAcc)
   253  }
   254  
   255  // DeleteAccount deletes an account's meta data, code, and
   256  // storage slots associated with that address
   257  func (v *BaseView) DeleteAccount(addr gethCommon.Address) error {
   258  	// 1. check account exists
   259  	acc, err := v.getAccount(addr)
   260  	if err != nil {
   261  		return err
   262  	}
   263  	if acc == nil {
   264  		return fmt.Errorf("account doesn't exist to be deleted")
   265  	}
   266  
   267  	// 2. remove the code
   268  	if acc.HasCode() {
   269  		err = v.updateAccountCode(addr, nil, gethTypes.EmptyCodeHash)
   270  		if err != nil {
   271  			return err
   272  		}
   273  	}
   274  
   275  	// 3. update the cache
   276  	delete(v.cachedAccounts, addr)
   277  
   278  	// 4. collections
   279  	err = v.accounts.Remove(addr.Bytes())
   280  	if err != nil {
   281  		return err
   282  	}
   283  
   284  	// 5. remove storage slots
   285  	if len(acc.CollectionID) > 0 {
   286  		col, found := v.slots[addr]
   287  		if !found {
   288  			col, err = v.collectionProvider.CollectionByID(acc.CollectionID)
   289  			if err != nil {
   290  				return err
   291  			}
   292  		}
   293  		// delete all slots related to this account (eip-6780)
   294  		keys, err := col.Destroy()
   295  		if err != nil {
   296  			return err
   297  		}
   298  
   299  		delete(v.slots, addr)
   300  
   301  		for _, key := range keys {
   302  			delete(v.cachedSlots, types.SlotAddress{
   303  				Address: addr,
   304  				Key:     gethCommon.BytesToHash(key),
   305  			})
   306  		}
   307  	}
   308  	return nil
   309  }
   310  
   311  // Commit commits the changes to the underlying storage layers
   312  func (v *BaseView) Commit() error {
   313  	// commit collection changes
   314  	err := v.collectionProvider.Commit()
   315  	if err != nil {
   316  		return err
   317  	}
   318  
   319  	// if this is the first time we are setting up an
   320  	// account collection, store its collection id.
   321  	if v.accountSetupOnCommit {
   322  		err = v.ledger.SetValue(v.rootAddress[:], []byte(AccountsStorageIDKey), v.accounts.CollectionID())
   323  		if err != nil {
   324  			return err
   325  		}
   326  		v.accountSetupOnCommit = false
   327  
   328  	}
   329  
   330  	// if this is the first time we are setting up an
   331  	// code collection, store its collection id.
   332  	if v.codeSetupOnCommit {
   333  		err = v.ledger.SetValue(v.rootAddress[:], []byte(CodesStorageIDKey), v.codes.CollectionID())
   334  		if err != nil {
   335  			return err
   336  		}
   337  		v.codeSetupOnCommit = false
   338  	}
   339  	return nil
   340  }
   341  
   342  // NumberOfContracts returns the number of unique contracts
   343  func (v *BaseView) NumberOfContracts() uint64 {
   344  	return v.codes.Size()
   345  }
   346  
   347  // NumberOfContracts returns the number of accounts
   348  func (v *BaseView) NumberOfAccounts() uint64 {
   349  	return v.accounts.Size()
   350  }
   351  
   352  func (v *BaseView) fetchOrCreateCollection(path string) (collection *Collection, created bool, error error) {
   353  	collectionID, err := v.ledger.GetValue(v.rootAddress[:], []byte(path))
   354  	if err != nil {
   355  		return nil, false, err
   356  	}
   357  	if len(collectionID) == 0 {
   358  		collection, err = v.collectionProvider.NewCollection()
   359  		return collection, true, err
   360  	}
   361  	collection, err = v.collectionProvider.CollectionByID(collectionID)
   362  	return collection, false, err
   363  }
   364  
   365  func (v *BaseView) getAccount(addr gethCommon.Address) (*Account, error) {
   366  	// check cached accounts first
   367  	acc, found := v.cachedAccounts[addr]
   368  	if found {
   369  		return acc, nil
   370  	}
   371  
   372  	// then collect it from the account collection
   373  	data, err := v.accounts.Get(addr.Bytes())
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  	// decode it
   378  	acc, err = DecodeAccount(data)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  	// cache it
   383  	if acc != nil {
   384  		v.cachedAccounts[addr] = acc
   385  	}
   386  	return acc, nil
   387  }
   388  
   389  func (v *BaseView) storeAccount(acc *Account) error {
   390  	data, err := acc.Encode()
   391  	if err != nil {
   392  		return err
   393  	}
   394  	// update the cache
   395  	v.cachedAccounts[acc.Address] = acc
   396  	return v.accounts.Set(acc.Address.Bytes(), data)
   397  }
   398  
   399  func (v *BaseView) getCode(addr gethCommon.Address) ([]byte, error) {
   400  	// check the cache first
   401  	code, found := v.cachedCodes[addr]
   402  	if found {
   403  		return code, nil
   404  	}
   405  
   406  	// get account
   407  	acc, err := v.getAccount(addr)
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  
   412  	if acc == nil || !acc.HasCode() {
   413  		return nil, nil
   414  	}
   415  
   416  	// collect the container from the code collection by codeHash
   417  	encoded, err := v.codes.Get(acc.CodeHash.Bytes())
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  	if len(encoded) == 0 {
   422  		return nil, nil
   423  	}
   424  
   425  	codeCont, err := CodeContainerFromEncoded(encoded)
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  	code = codeCont.Code()
   430  	if len(code) > 0 {
   431  		v.cachedCodes[addr] = code
   432  	}
   433  	return code, nil
   434  }
   435  
   436  func (v *BaseView) updateAccountCode(addr gethCommon.Address, code []byte, codeHash gethCommon.Hash) error {
   437  	// get account
   438  	acc, err := v.getAccount(addr)
   439  	if err != nil {
   440  		return err
   441  	}
   442  	// if is a new account
   443  	if acc == nil {
   444  		if len(code) == 0 {
   445  			return nil
   446  		}
   447  		v.cachedCodes[addr] = code
   448  		return v.addCode(code, codeHash)
   449  	}
   450  
   451  	// skip if is the same code
   452  	if acc.CodeHash == codeHash {
   453  		return nil
   454  	}
   455  
   456  	// clean old code first if exist
   457  	if acc.HasCode() {
   458  		delete(v.cachedCodes, addr)
   459  		err = v.removeCode(acc.CodeHash)
   460  		if err != nil {
   461  			return err
   462  		}
   463  	}
   464  
   465  	// add new code
   466  	if len(code) == 0 {
   467  		return nil
   468  	}
   469  	v.cachedCodes[addr] = code
   470  	return v.addCode(code, codeHash)
   471  }
   472  
   473  func (v *BaseView) removeCode(codeHash gethCommon.Hash) error {
   474  	encoded, err := v.codes.Get(codeHash.Bytes())
   475  	if err != nil {
   476  		return err
   477  	}
   478  	if len(encoded) == 0 {
   479  		return nil
   480  	}
   481  
   482  	cc, err := CodeContainerFromEncoded(encoded)
   483  	if err != nil {
   484  		return err
   485  	}
   486  	if cc.DecRefCount() {
   487  		return v.codes.Remove(codeHash.Bytes())
   488  	}
   489  	return v.codes.Set(codeHash.Bytes(), cc.Encode())
   490  }
   491  
   492  func (v *BaseView) addCode(code []byte, codeHash gethCommon.Hash) error {
   493  	encoded, err := v.codes.Get(codeHash.Bytes())
   494  	if err != nil {
   495  		return err
   496  	}
   497  	// if is the first time the code is getting deployed
   498  	if len(encoded) == 0 {
   499  		return v.codes.Set(codeHash.Bytes(), NewCodeContainer(code).Encode())
   500  	}
   501  
   502  	// otherwise update the cc
   503  	cc, err := CodeContainerFromEncoded(encoded)
   504  	if err != nil {
   505  		return err
   506  	}
   507  	cc.IncRefCount()
   508  	return v.codes.Set(codeHash.Bytes(), cc.Encode())
   509  }
   510  
   511  func (v *BaseView) getSlot(sk types.SlotAddress) (gethCommon.Hash, error) {
   512  	value, found := v.cachedSlots[sk]
   513  	if found {
   514  		return value, nil
   515  	}
   516  
   517  	acc, err := v.getAccount(sk.Address)
   518  	if err != nil {
   519  		return gethCommon.Hash{}, err
   520  	}
   521  	if acc == nil || len(acc.CollectionID) == 0 {
   522  		return gethCommon.Hash{}, nil
   523  	}
   524  
   525  	col, err := v.getSlotCollection(acc)
   526  	if err != nil {
   527  		return gethCommon.Hash{}, err
   528  	}
   529  
   530  	val, err := col.Get(sk.Key.Bytes())
   531  	if err != nil {
   532  		return gethCommon.Hash{}, err
   533  	}
   534  	value = gethCommon.BytesToHash(val)
   535  	v.cachedSlots[sk] = value
   536  	return value, nil
   537  }
   538  
   539  func (v *BaseView) storeSlot(sk types.SlotAddress, data gethCommon.Hash) error {
   540  	acc, err := v.getAccount(sk.Address)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	if acc == nil {
   545  		return fmt.Errorf("slot belongs to a non-existing account")
   546  	}
   547  	if !acc.HasCode() {
   548  		return fmt.Errorf("slot belongs to a non-smart contract account")
   549  	}
   550  	col, err := v.getSlotCollection(acc)
   551  	if err != nil {
   552  		return err
   553  	}
   554  
   555  	emptyValue := gethCommon.Hash{}
   556  	if data == emptyValue {
   557  		delete(v.cachedSlots, sk)
   558  		return col.Remove(sk.Key.Bytes())
   559  	}
   560  	v.cachedSlots[sk] = data
   561  	return col.Set(sk.Key.Bytes(), data.Bytes())
   562  }
   563  
   564  func (v *BaseView) getSlotCollection(acc *Account) (*Collection, error) {
   565  	var err error
   566  
   567  	if len(acc.CollectionID) == 0 {
   568  		// create a new collection for slots
   569  		col, err := v.collectionProvider.NewCollection()
   570  		if err != nil {
   571  			return nil, err
   572  		}
   573  		// cache collection
   574  		v.slots[acc.Address] = col
   575  		// update account's collection ID
   576  		acc.CollectionID = col.CollectionID()
   577  		err = v.storeAccount(acc)
   578  		if err != nil {
   579  			return nil, err
   580  		}
   581  		return col, nil
   582  	}
   583  
   584  	col, found := v.slots[acc.Address]
   585  	if !found {
   586  		col, err = v.collectionProvider.CollectionByID(acc.CollectionID)
   587  		if err != nil {
   588  			return nil, err
   589  		}
   590  		v.slots[acc.Address] = col
   591  	}
   592  	return col, nil
   593  }