github.com/onflow/flow-go@v0.33.17/fvm/evm/emulator/state/delta.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  	gethCrypto "github.com/ethereum/go-ethereum/crypto"
    10  
    11  	"github.com/onflow/flow-go/fvm/evm/types"
    12  )
    13  
    14  // DeltaView captures the changes to the state during the execution
    15  //
    16  // for most of the read calls it checks its change logs and if no record is
    17  // found it would redirect the call to the parent view.
    18  type DeltaView struct {
    19  	parent types.ReadOnlyView
    20  
    21  	// dirtyAddresses keeps a set of addresses with changes
    22  	dirtyAddresses map[gethCommon.Address]struct{}
    23  	// created keeps a set of recently created addresses
    24  	created map[gethCommon.Address]struct{}
    25  	// toBeDestructed keeps a set of addresses flagged to be destructed at the
    26  	// end of transaction, it also keeps the balance of the addresses before destruction
    27  	toBeDestructed map[gethCommon.Address]*big.Int
    28  	// is a flag used to track accounts that has been flagged for
    29  	// destruction but recreated later
    30  	recreated map[gethCommon.Address]struct{}
    31  	// balances keeps the changes to the account balances
    32  	balances map[gethCommon.Address]*big.Int
    33  	// nonces keeps the changes to the account nonces
    34  	nonces map[gethCommon.Address]uint64
    35  	// codes keeps the changes to the account codes
    36  	codes map[gethCommon.Address][]byte
    37  	// codeHashes keeps the changes to account code hashes
    38  	codeHashes map[gethCommon.Address]gethCommon.Hash
    39  
    40  	// slots keeps a set of slots that has been changed in this view
    41  	slots map[types.SlotAddress]gethCommon.Hash
    42  
    43  	// transient storage
    44  	transient map[types.SlotAddress]gethCommon.Hash
    45  
    46  	// access lists
    47  	accessListAddresses map[gethCommon.Address]struct{}
    48  	accessListSlots     map[types.SlotAddress]struct{}
    49  
    50  	// logs
    51  	logs []*gethTypes.Log
    52  
    53  	// preimages
    54  	preimages map[gethCommon.Hash][]byte
    55  
    56  	// refund
    57  	refund uint64
    58  }
    59  
    60  var _ types.HotView = &DeltaView{}
    61  
    62  // NewDeltaView constructs a new delta view
    63  func NewDeltaView(parent types.ReadOnlyView) *DeltaView {
    64  	return &DeltaView{
    65  		parent: parent,
    66  
    67  		dirtyAddresses: make(map[gethCommon.Address]struct{}),
    68  		created:        make(map[gethCommon.Address]struct{}),
    69  		toBeDestructed: make(map[gethCommon.Address]*big.Int),
    70  		recreated:      make(map[gethCommon.Address]struct{}),
    71  		balances:       make(map[gethCommon.Address]*big.Int),
    72  		nonces:         make(map[gethCommon.Address]uint64),
    73  		codes:          make(map[gethCommon.Address][]byte),
    74  		codeHashes:     make(map[gethCommon.Address]gethCommon.Hash),
    75  
    76  		slots: make(map[types.SlotAddress]gethCommon.Hash),
    77  
    78  		// for refund we just copy the data
    79  		refund: parent.GetRefund(),
    80  	}
    81  }
    82  
    83  // NewChildView constructs a new delta view having the current view as parent
    84  func (d *DeltaView) NewChildView() *DeltaView {
    85  	return NewDeltaView(d)
    86  }
    87  
    88  // Exist returns true if address exists
    89  //
    90  // it also returns true for both newly created accounts or accounts that has been flagged for deletion
    91  func (d *DeltaView) Exist(addr gethCommon.Address) (bool, error) {
    92  	_, found := d.created[addr]
    93  	if found {
    94  		return true, nil
    95  	}
    96  	_, found = d.toBeDestructed[addr]
    97  	if found {
    98  		return true, nil
    99  	}
   100  	return d.parent.Exist(addr)
   101  }
   102  
   103  // CreateAccount creates a new account for the given address
   104  //
   105  // if address already extists (even if destructed), carry over the balance
   106  // and reset the data from the orginal account.
   107  func (d *DeltaView) CreateAccount(addr gethCommon.Address) error {
   108  	// if is already created return
   109  	if d.IsCreated(addr) {
   110  		return nil
   111  	}
   112  	exist, err := d.Exist(addr)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	if exist {
   117  		// check if already destructed
   118  		destructed, balance := d.HasSelfDestructed(addr)
   119  		if !destructed {
   120  			balance, err = d.GetBalance(addr)
   121  			if err != nil {
   122  				return err
   123  			}
   124  			err = d.SelfDestruct(addr)
   125  			if err != nil {
   126  				return err
   127  			}
   128  		}
   129  
   130  		d.nonces[addr] = 0
   131  		d.codes[addr] = nil
   132  		d.codeHashes[addr] = gethTypes.EmptyCodeHash
   133  		// carrying over the balance. (legacy behaviour of the Geth stateDB)
   134  		d.balances[addr] = balance
   135  
   136  		// flag addr as recreated, this flag helps with postponing deletion of slabs
   137  		// otherwise we have to iterate over all slabs of this account and set the to nil
   138  		d.recreated[addr] = struct{}{}
   139  
   140  		// remove slabs from cache related to this account
   141  		for k := range d.slots {
   142  			if k.Address == addr {
   143  				delete(d.slots, k)
   144  			}
   145  		}
   146  	}
   147  	d.dirtyAddresses[addr] = struct{}{}
   148  	d.created[addr] = struct{}{}
   149  	return nil
   150  }
   151  
   152  // IsCreated returns true if address has been created in this tx
   153  func (d *DeltaView) IsCreated(addr gethCommon.Address) bool {
   154  	_, found := d.created[addr]
   155  	if found {
   156  		return true
   157  	}
   158  	return d.parent.IsCreated(addr)
   159  }
   160  
   161  // HasSelfDestructed returns true if address has been flagged for destruction
   162  // it also returns the balance of the address before the destruction call
   163  func (d *DeltaView) HasSelfDestructed(addr gethCommon.Address) (bool, *big.Int) {
   164  	bal, found := d.toBeDestructed[addr]
   165  	if found {
   166  		return true, bal
   167  	}
   168  	return d.parent.HasSelfDestructed(addr)
   169  }
   170  
   171  // SelfDestruct sets a flag to destruct the account at the end of transaction
   172  //
   173  // if an account has been created in this transaction, it would return an error
   174  func (d *DeltaView) SelfDestruct(addr gethCommon.Address) error {
   175  	// if it has been recently created, calling self destruct is not a valid operation
   176  	if d.IsCreated(addr) {
   177  		return fmt.Errorf("invalid operation, can't selfdestruct an account that is just created")
   178  	}
   179  
   180  	// if it doesn't exist, return false
   181  	exists, err := d.Exist(addr)
   182  	if err != nil {
   183  		return err
   184  	}
   185  	if !exists {
   186  		return nil
   187  	}
   188  
   189  	// flag the account for destruction and capture the balance
   190  	// before destruction
   191  	d.toBeDestructed[addr], err = d.GetBalance(addr)
   192  	if err != nil {
   193  		return err
   194  	}
   195  	// flag the address as dirty
   196  	d.dirtyAddresses[addr] = struct{}{}
   197  
   198  	// set balance to zero
   199  	d.balances[addr] = new(big.Int)
   200  	return nil
   201  }
   202  
   203  // GetBalance returns the balance of the given address
   204  func (d *DeltaView) GetBalance(addr gethCommon.Address) (*big.Int, error) {
   205  	val, found := d.balances[addr]
   206  	if found {
   207  		return val, nil
   208  	}
   209  	// if newly created and no balance is set yet
   210  	_, newlyCreated := d.created[addr]
   211  	if newlyCreated {
   212  		return big.NewInt(0), nil
   213  	}
   214  	return d.parent.GetBalance(addr)
   215  }
   216  
   217  // AddBalance adds the amount to the current balance of the given address
   218  func (d *DeltaView) AddBalance(addr gethCommon.Address, amount *big.Int) error {
   219  	// if amount is 0 skip
   220  	if amount.Sign() == 0 {
   221  		return nil
   222  	}
   223  	// get the latest balance
   224  	orgBalance, err := d.GetBalance(addr)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	// update the balance
   229  	newBalance := new(big.Int).Add(orgBalance, amount)
   230  	d.balances[addr] = newBalance
   231  
   232  	// flag the address as dirty
   233  	d.dirtyAddresses[addr] = struct{}{}
   234  	return nil
   235  }
   236  
   237  // SubBalance subtracts the amount from the current balance of the given address
   238  func (d *DeltaView) SubBalance(addr gethCommon.Address, amount *big.Int) error {
   239  	// if amount is 0 skip
   240  	if amount.Sign() == 0 {
   241  		return nil
   242  	}
   243  
   244  	// get the latest balance
   245  	orgBalance, err := d.GetBalance(addr)
   246  	if err != nil {
   247  		return err
   248  	}
   249  
   250  	// update the new balance
   251  	newBalance := new(big.Int).Sub(orgBalance, amount)
   252  
   253  	// if new balance is negative error
   254  	if newBalance.Sign() < 0 {
   255  		return fmt.Errorf("account balance is negative %d", newBalance)
   256  	}
   257  
   258  	// update the balance
   259  	d.balances[addr] = newBalance
   260  
   261  	// flag the address as dirty
   262  	d.dirtyAddresses[addr] = struct{}{}
   263  	return nil
   264  }
   265  
   266  // GetNonce returns the nonce of the given address
   267  func (d *DeltaView) GetNonce(addr gethCommon.Address) (uint64, error) {
   268  	val, found := d.nonces[addr]
   269  	if found {
   270  		return val, nil
   271  	}
   272  	// if newly created
   273  	_, newlyCreated := d.created[addr]
   274  	if newlyCreated {
   275  		return 0, nil
   276  	}
   277  	return d.parent.GetNonce(addr)
   278  }
   279  
   280  // SetNonce sets the nonce for the given address
   281  func (d *DeltaView) SetNonce(addr gethCommon.Address, nonce uint64) error {
   282  	// update the nonce
   283  	d.nonces[addr] = nonce
   284  
   285  	// flag the address as dirty
   286  	d.dirtyAddresses[addr] = struct{}{}
   287  	return nil
   288  }
   289  
   290  // GetCode returns the code of the given address
   291  func (d *DeltaView) GetCode(addr gethCommon.Address) ([]byte, error) {
   292  	code, found := d.codes[addr]
   293  	if found {
   294  		return code, nil
   295  	}
   296  	// if newly created
   297  	_, newlyCreated := d.created[addr]
   298  	if newlyCreated {
   299  		return nil, nil
   300  	}
   301  	return d.parent.GetCode(addr)
   302  }
   303  
   304  // GetCodeSize returns the code size of the given address
   305  func (d *DeltaView) GetCodeSize(addr gethCommon.Address) (int, error) {
   306  	code, err := d.GetCode(addr)
   307  	return len(code), err
   308  }
   309  
   310  // GetCodeHash returns the code hash of the given address
   311  func (d *DeltaView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) {
   312  	codeHash, found := d.codeHashes[addr]
   313  	if found {
   314  		return codeHash, nil
   315  	}
   316  	// if newly created
   317  	_, newlyCreated := d.created[addr]
   318  	if newlyCreated {
   319  		return gethTypes.EmptyCodeHash, nil
   320  	}
   321  	return d.parent.GetCodeHash(addr)
   322  }
   323  
   324  // SetCode sets the code for the given address
   325  func (d *DeltaView) SetCode(addr gethCommon.Address, code []byte) error {
   326  	// update code
   327  	d.codes[addr] = code
   328  
   329  	// update code hash
   330  	codeHash := gethTypes.EmptyCodeHash
   331  	if len(code) > 0 {
   332  		codeHash = gethCrypto.Keccak256Hash(code)
   333  	}
   334  	d.codeHashes[addr] = codeHash
   335  
   336  	// flag the address as dirty
   337  	d.dirtyAddresses[addr] = struct{}{}
   338  	return nil
   339  }
   340  
   341  // GetState returns the value of the slot of the main state
   342  func (d *DeltaView) GetState(sk types.SlotAddress) (gethCommon.Hash, error) {
   343  	val, found := d.slots[sk]
   344  	if found {
   345  		return val, nil
   346  	}
   347  	// if address is deleted in the scope of this delta view,
   348  	// don't go backward. this has been done to skip the step to iterate
   349  	// over all the state slabs and delete them.
   350  	_, recreated := d.recreated[sk.Address]
   351  	if recreated {
   352  		return gethCommon.Hash{}, nil
   353  	}
   354  	return d.parent.GetState(sk)
   355  }
   356  
   357  // SetState adds sets a value for the given slot of the main storage
   358  func (d *DeltaView) SetState(sk types.SlotAddress, value gethCommon.Hash) error {
   359  	lastValue, err := d.GetState(sk)
   360  	if err != nil {
   361  		return err
   362  	}
   363  	// if the value hasn't changed, skip
   364  	if value == lastValue {
   365  		return nil
   366  	}
   367  	d.slots[sk] = value
   368  	return nil
   369  }
   370  
   371  // GetTransientState returns the value of the slot of the transient state
   372  func (d *DeltaView) GetTransientState(sk types.SlotAddress) gethCommon.Hash {
   373  	if d.transient != nil {
   374  		val, found := d.transient[sk]
   375  		if found {
   376  			return val
   377  		}
   378  	}
   379  	return d.parent.GetTransientState(sk)
   380  }
   381  
   382  // SetTransientState adds sets a value for the given slot of the transient storage
   383  func (d *DeltaView) SetTransientState(sk types.SlotAddress, value gethCommon.Hash) {
   384  	if d.transient == nil {
   385  		d.transient = make(map[types.SlotAddress]gethCommon.Hash)
   386  	}
   387  	d.transient[sk] = value
   388  }
   389  
   390  // GetRefund returns the total (gas) refund
   391  func (d *DeltaView) GetRefund() uint64 {
   392  	return d.refund
   393  }
   394  
   395  // AddRefund adds the amount to the total (gas) refund
   396  func (d *DeltaView) AddRefund(amount uint64) error {
   397  	d.refund += amount
   398  	return nil
   399  }
   400  
   401  // SubRefund subtracts the amount from the total (gas) refund
   402  func (d *DeltaView) SubRefund(amount uint64) error {
   403  	if amount > d.refund {
   404  		return fmt.Errorf("refund counter below zero (gas: %d > refund: %d)", amount, d.refund)
   405  	}
   406  	d.refund -= amount
   407  	return nil
   408  }
   409  
   410  // AddressInAccessList checks if the address is in the access list
   411  func (d *DeltaView) AddressInAccessList(addr gethCommon.Address) bool {
   412  	if d.accessListAddresses != nil {
   413  		_, addressFound := d.accessListAddresses[addr]
   414  		if addressFound {
   415  			return true
   416  		}
   417  	}
   418  	return d.parent.AddressInAccessList(addr)
   419  }
   420  
   421  // AddAddressToAccessList adds an address to the access list
   422  func (d *DeltaView) AddAddressToAccessList(addr gethCommon.Address) bool {
   423  	if d.accessListAddresses == nil {
   424  		d.accessListAddresses = make(map[gethCommon.Address]struct{})
   425  	}
   426  
   427  	addrPresent := d.AddressInAccessList(addr)
   428  	d.accessListAddresses[addr] = struct{}{}
   429  	return !addrPresent
   430  }
   431  
   432  // SlotInAccessList checks if the slot is in the access list
   433  func (d *DeltaView) SlotInAccessList(sk types.SlotAddress) (addressOk bool, slotOk bool) {
   434  	addressFound := d.AddressInAccessList(sk.Address)
   435  	if d.accessListSlots != nil {
   436  		_, slotFound := d.accessListSlots[sk]
   437  		if slotFound {
   438  			return addressFound, true
   439  		}
   440  	}
   441  	_, slotFound := d.parent.SlotInAccessList(sk)
   442  	return addressFound, slotFound
   443  }
   444  
   445  // AddSlotToAccessList adds a slot to the access list
   446  // it also adds the address to the address list
   447  func (d *DeltaView) AddSlotToAccessList(sk types.SlotAddress) (addrAdded bool, slotAdded bool) {
   448  	addrPresent, slotPresent := d.SlotInAccessList(sk)
   449  	if d.accessListAddresses == nil {
   450  		d.accessListAddresses = make(map[gethCommon.Address]struct{})
   451  	}
   452  	d.accessListAddresses[sk.Address] = struct{}{}
   453  	if d.accessListSlots == nil {
   454  		d.accessListSlots = make(map[types.SlotAddress]struct{})
   455  	}
   456  	d.accessListSlots[sk] = struct{}{}
   457  	return !addrPresent, !slotPresent
   458  }
   459  
   460  // AddLog appends a log to the log collection
   461  func (d *DeltaView) AddLog(log *gethTypes.Log) {
   462  	if d.logs == nil {
   463  		d.logs = make([]*gethTypes.Log, 0)
   464  	}
   465  	d.logs = append(d.logs, log)
   466  }
   467  
   468  // Logs returns the logs that has been captured in this view
   469  func (d *DeltaView) Logs() []*gethTypes.Log {
   470  	return d.logs
   471  }
   472  
   473  // AddPreimage adds a preimage
   474  func (d *DeltaView) AddPreimage(hash gethCommon.Hash, preimage []byte) {
   475  	if d.preimages == nil {
   476  		d.preimages = make(map[gethCommon.Hash][]byte)
   477  	}
   478  
   479  	// make a copy (legacy behaviour)
   480  	pi := make([]byte, len(preimage))
   481  	copy(pi, preimage)
   482  	d.preimages[hash] = pi
   483  }
   484  
   485  // Preimages returns a map of preimages
   486  func (d *DeltaView) Preimages() map[gethCommon.Hash][]byte {
   487  	return d.preimages
   488  }
   489  
   490  // DirtyAddresses returns a set of addresses that has been updated in this view
   491  func (d *DeltaView) DirtyAddresses() map[gethCommon.Address]struct{} {
   492  	return d.dirtyAddresses
   493  }
   494  
   495  // DirtySlots returns a set of slots that has been updated in this view
   496  func (d *DeltaView) DirtySlots() map[types.SlotAddress]struct{} {
   497  	dirtySlots := make(map[types.SlotAddress]struct{})
   498  	for sk := range d.slots {
   499  		dirtySlots[sk] = struct{}{}
   500  	}
   501  	return dirtySlots
   502  }