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

     1  package state_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"testing"
     7  
     8  	gethCommon "github.com/onflow/go-ethereum/common"
     9  	gethTypes "github.com/onflow/go-ethereum/core/types"
    10  	gethCrypto "github.com/onflow/go-ethereum/crypto"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/onflow/flow-go/fvm/evm/emulator/state"
    14  	"github.com/onflow/flow-go/fvm/evm/testutils"
    15  	"github.com/onflow/flow-go/fvm/evm/types"
    16  )
    17  
    18  var emptyRefund = func() uint64 {
    19  	return 0
    20  }
    21  
    22  func TestDeltaView(t *testing.T) {
    23  	t.Parallel()
    24  
    25  	t.Run("test account exist/creation/self-destruct functionality", func(t *testing.T) {
    26  		addr1 := testutils.RandomCommonAddress(t)
    27  		addr2 := testutils.RandomCommonAddress(t)
    28  		addr3 := testutils.RandomCommonAddress(t)
    29  
    30  		view := state.NewDeltaView(
    31  			&MockedReadOnlyView{
    32  				// we need get refund for parent
    33  				GetRefundFunc: emptyRefund,
    34  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
    35  					switch addr {
    36  					case addr1:
    37  						return true, nil
    38  					case addr2:
    39  						return false, nil
    40  					default:
    41  						return false, fmt.Errorf("some error")
    42  					}
    43  				},
    44  				IsCreatedFunc: func(a gethCommon.Address) bool {
    45  					return false
    46  				},
    47  				GetBalanceFunc: func(gethCommon.Address) (*big.Int, error) {
    48  					return new(big.Int), nil
    49  				},
    50  				HasSelfDestructedFunc: func(gethCommon.Address) (bool, *big.Int) {
    51  					return false, new(big.Int)
    52  				},
    53  			})
    54  
    55  		// check existing account on the parent
    56  		found, err := view.Exist(addr1)
    57  		require.NoError(t, err)
    58  		require.True(t, found)
    59  
    60  		// account doesn't exist on parent
    61  		found, err = view.Exist(addr2)
    62  		require.NoError(t, err)
    63  		require.False(t, found)
    64  
    65  		// handling error on the parent
    66  		_, err = view.Exist(addr3)
    67  		require.Error(t, err)
    68  
    69  		// create a account at address 2
    70  		err = view.CreateAccount(addr2)
    71  		require.NoError(t, err)
    72  		require.True(t, view.IsCreated(addr2))
    73  
    74  		// now it should be found
    75  		found, err = view.Exist(addr2)
    76  		require.NoError(t, err)
    77  		require.True(t, found)
    78  
    79  		// test HasSelfDestructed first
    80  		success, _ := view.HasSelfDestructed(addr1)
    81  		require.False(t, success)
    82  
    83  		// set addr1 for deletion
    84  		err = view.SelfDestruct(addr1)
    85  		require.NoError(t, err)
    86  
    87  		// check HasSelfDestructed now
    88  		success, _ = view.HasSelfDestructed(addr1)
    89  		require.True(t, success)
    90  
    91  		// addr1 should still exist after self destruct call
    92  		found, err = view.Exist(addr1)
    93  		require.NoError(t, err)
    94  		require.True(t, found)
    95  	})
    96  
    97  	t.Run("test account balance functionality", func(t *testing.T) {
    98  		addr1 := testutils.RandomCommonAddress(t)
    99  		addr1InitBal := big.NewInt(10)
   100  		addr2 := testutils.RandomCommonAddress(t)
   101  		addr2InitBal := big.NewInt(5)
   102  		addr3 := testutils.RandomCommonAddress(t)
   103  
   104  		view := state.NewDeltaView(
   105  			&MockedReadOnlyView{
   106  				// we need get refund for parent
   107  				GetRefundFunc: emptyRefund,
   108  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
   109  					switch addr {
   110  					case addr1, addr2:
   111  						return true, nil
   112  					default:
   113  						return false, nil
   114  					}
   115  				},
   116  				HasSelfDestructedFunc: func(a gethCommon.Address) (bool, *big.Int) {
   117  					return false, new(big.Int)
   118  				},
   119  				IsCreatedFunc: func(a gethCommon.Address) bool {
   120  					return false
   121  				},
   122  				GetBalanceFunc: func(addr gethCommon.Address) (*big.Int, error) {
   123  					switch addr {
   124  					case addr1:
   125  						return addr1InitBal, nil
   126  					case addr2:
   127  						return addr2InitBal, nil
   128  					default:
   129  						return nil, fmt.Errorf("some error")
   130  					}
   131  				},
   132  			})
   133  
   134  		// get balance through parent
   135  		bal, err := view.GetBalance(addr1)
   136  		require.NoError(t, err)
   137  		require.Equal(t, addr1InitBal, bal)
   138  
   139  		// call self destruct on addr
   140  		err = view.SelfDestruct(addr1)
   141  		require.NoError(t, err)
   142  
   143  		// now it should return balance of zero
   144  		bal, err = view.GetBalance(addr1)
   145  		require.NoError(t, err)
   146  		require.Equal(t, big.NewInt(0), bal)
   147  
   148  		// add balance to addr2
   149  		amount := big.NewInt(7)
   150  		expected := new(big.Int).Add(addr2InitBal, amount)
   151  		err = view.AddBalance(addr2, amount)
   152  		require.NoError(t, err)
   153  		newBal, err := view.GetBalance(addr2)
   154  		require.NoError(t, err)
   155  		require.Equal(t, expected, newBal)
   156  
   157  		// sub balance from addr2
   158  		amount = big.NewInt(9)
   159  		expected = new(big.Int).Sub(newBal, amount)
   160  		err = view.SubBalance(addr2, amount)
   161  		require.NoError(t, err)
   162  		bal, err = view.GetBalance(addr2)
   163  		require.NoError(t, err)
   164  		require.Equal(t, expected, bal)
   165  
   166  		// negative balance error
   167  		err = view.SubBalance(addr2, big.NewInt(100))
   168  		require.Error(t, err)
   169  
   170  		// handling error on the parent
   171  		_, err = view.GetBalance(addr3)
   172  		require.Error(t, err)
   173  	})
   174  
   175  	t.Run("test nonce functionality", func(t *testing.T) {
   176  		addr1 := testutils.RandomCommonAddress(t)
   177  		addr1InitNonce := uint64(1)
   178  		addr2 := testutils.RandomCommonAddress(t)
   179  
   180  		view := state.NewDeltaView(
   181  			&MockedReadOnlyView{
   182  				// we need get refund for parent
   183  				GetRefundFunc: emptyRefund,
   184  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
   185  					switch addr {
   186  					case addr1:
   187  						return true, nil
   188  					default:
   189  						return false, nil
   190  					}
   191  				},
   192  				HasSelfDestructedFunc: func(a gethCommon.Address) (bool, *big.Int) {
   193  					return false, new(big.Int)
   194  				},
   195  				IsCreatedFunc: func(a gethCommon.Address) bool {
   196  					return false
   197  				},
   198  				GetBalanceFunc: func(a gethCommon.Address) (*big.Int, error) {
   199  					return new(big.Int), nil
   200  				},
   201  				GetNonceFunc: func(addr gethCommon.Address) (uint64, error) {
   202  					switch addr {
   203  					case addr1:
   204  						return addr1InitNonce, nil
   205  					default:
   206  						return 0, fmt.Errorf("some error")
   207  					}
   208  				},
   209  			})
   210  
   211  		// get nonce through parent
   212  		nonce, err := view.GetNonce(addr1)
   213  		require.NoError(t, err)
   214  		require.Equal(t, addr1InitNonce, nonce)
   215  
   216  		// set nonce
   217  		new := uint64(100)
   218  		err = view.SetNonce(addr1, new)
   219  		require.NoError(t, err)
   220  		nonce, err = view.GetNonce(addr1)
   221  		require.NoError(t, err)
   222  		require.Equal(t, new, nonce)
   223  
   224  		// handling error on the parent
   225  		_, err = view.GetNonce(addr2)
   226  		require.Error(t, err)
   227  
   228  		// create a new account at addr2
   229  		err = view.CreateAccount(addr2)
   230  		require.NoError(t, err)
   231  
   232  		// now the nonce should return 0
   233  		nonce, err = view.GetNonce(addr2)
   234  		require.NoError(t, err)
   235  		require.Equal(t, uint64(0), nonce)
   236  	})
   237  
   238  	t.Run("test code functionality", func(t *testing.T) {
   239  		addr1 := testutils.RandomCommonAddress(t)
   240  		addr1InitCode := []byte("code1")
   241  		addr1IntiCodeHash := gethCommon.BytesToHash([]byte{1, 2})
   242  		addr2 := testutils.RandomCommonAddress(t)
   243  
   244  		view := state.NewDeltaView(
   245  			&MockedReadOnlyView{
   246  				// we need get refund for parent
   247  				GetRefundFunc: emptyRefund,
   248  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
   249  					switch addr {
   250  					case addr1:
   251  						return true, nil
   252  					default:
   253  						return false, nil
   254  					}
   255  				},
   256  				HasSelfDestructedFunc: func(a gethCommon.Address) (bool, *big.Int) {
   257  					return false, new(big.Int)
   258  				},
   259  				IsCreatedFunc: func(a gethCommon.Address) bool {
   260  					return false
   261  				},
   262  				GetBalanceFunc: func(a gethCommon.Address) (*big.Int, error) {
   263  					return new(big.Int), nil
   264  				},
   265  				GetCodeFunc: func(addr gethCommon.Address) ([]byte, error) {
   266  					switch addr {
   267  					case addr1:
   268  						return addr1InitCode, nil
   269  					default:
   270  						return nil, fmt.Errorf("some error")
   271  					}
   272  				},
   273  				GetCodeSizeFunc: func(addr gethCommon.Address) (int, error) {
   274  					switch addr {
   275  					case addr1:
   276  						return len(addr1InitCode), nil
   277  					default:
   278  						return 0, fmt.Errorf("some error")
   279  					}
   280  				},
   281  				GetCodeHashFunc: func(addr gethCommon.Address) (gethCommon.Hash, error) {
   282  					switch addr {
   283  					case addr1:
   284  						return addr1IntiCodeHash, nil
   285  					default:
   286  						return gethCommon.Hash{}, fmt.Errorf("some error")
   287  					}
   288  				},
   289  			})
   290  
   291  		// get code through parent
   292  		code, err := view.GetCode(addr1)
   293  		require.NoError(t, err)
   294  		require.Equal(t, addr1InitCode, code)
   295  
   296  		// get code size through parent
   297  		codeSize, err := view.GetCodeSize(addr1)
   298  		require.NoError(t, err)
   299  		require.Equal(t, len(addr1InitCode), codeSize)
   300  
   301  		// get code hash through parent
   302  		codeHash, err := view.GetCodeHash(addr1)
   303  		require.NoError(t, err)
   304  		require.Equal(t, addr1IntiCodeHash, codeHash)
   305  
   306  		// set code for addr1
   307  		newCode := []byte("new code")
   308  		err = view.SetCode(addr1, newCode)
   309  		require.NoError(t, err)
   310  
   311  		code, err = view.GetCode(addr1)
   312  		require.NoError(t, err)
   313  		require.Equal(t, newCode, code)
   314  
   315  		codeSize, err = view.GetCodeSize(addr1)
   316  		require.NoError(t, err)
   317  		require.Equal(t, len(newCode), codeSize)
   318  
   319  		codeHash, err = view.GetCodeHash(addr1)
   320  		require.NoError(t, err)
   321  		require.Equal(t, gethCrypto.Keccak256Hash(code), codeHash)
   322  
   323  		// handling error on the parent
   324  		_, err = view.GetCode(addr2)
   325  		require.Error(t, err)
   326  
   327  		// create a new account at addr2
   328  		err = view.CreateAccount(addr2)
   329  		require.NoError(t, err)
   330  
   331  		// now the code should return empty code
   332  		code, err = view.GetCode(addr2)
   333  		require.NoError(t, err)
   334  		require.Len(t, code, 0)
   335  
   336  		codeHash, err = view.GetCodeHash(addr2)
   337  		require.NoError(t, err)
   338  		require.Equal(t, gethTypes.EmptyCodeHash, codeHash)
   339  	})
   340  
   341  	t.Run("test state access functionality", func(t *testing.T) {
   342  		slot1 := types.SlotAddress{
   343  			Address: testutils.RandomCommonAddress(t),
   344  			Key:     gethCommon.BytesToHash([]byte{1, 2}),
   345  		}
   346  
   347  		slot1InitValue := gethCommon.BytesToHash([]byte{3, 4})
   348  
   349  		slot2 := types.SlotAddress{
   350  			Address: testutils.RandomCommonAddress(t),
   351  			Key:     gethCommon.BytesToHash([]byte{5, 6}),
   352  		}
   353  
   354  		view := state.NewDeltaView(
   355  			&MockedReadOnlyView{
   356  				// we need get refund for parent
   357  				GetRefundFunc: emptyRefund,
   358  
   359  				GetStateFunc: func(slot types.SlotAddress) (gethCommon.Hash, error) {
   360  					switch slot {
   361  					case slot1:
   362  						return slot1InitValue, nil
   363  					default:
   364  						return gethCommon.Hash{}, fmt.Errorf("some error")
   365  					}
   366  				},
   367  			})
   368  
   369  		// get state through parent
   370  		value, err := view.GetState(slot1)
   371  		require.NoError(t, err)
   372  		require.Equal(t, slot1InitValue, value)
   373  
   374  		// handle error from parent
   375  		_, err = view.GetState(slot2)
   376  		require.Error(t, err)
   377  
   378  		// check dirty slots
   379  		dirtySlots := view.DirtySlots()
   380  		require.Empty(t, dirtySlots)
   381  
   382  		// set slot1 with some new value
   383  		newValue := gethCommon.BytesToHash([]byte{9, 8})
   384  		err = view.SetState(slot1, newValue)
   385  		require.NoError(t, err)
   386  
   387  		value, err = view.GetState(slot1)
   388  		require.NoError(t, err)
   389  		require.Equal(t, newValue, value)
   390  
   391  		// check dirty slots
   392  		dirtySlots = view.DirtySlots()
   393  		require.Len(t, dirtySlots, 1)
   394  
   395  		_, found := dirtySlots[slot1]
   396  		require.True(t, found)
   397  	})
   398  
   399  	t.Run("test transient state access functionality", func(t *testing.T) {
   400  		slot1 := types.SlotAddress{
   401  			Address: testutils.RandomCommonAddress(t),
   402  			Key:     gethCommon.BytesToHash([]byte{1, 2}),
   403  		}
   404  
   405  		slot1InitValue := gethCommon.BytesToHash([]byte{3, 4})
   406  
   407  		view := state.NewDeltaView(
   408  			&MockedReadOnlyView{
   409  				// we need get refund for parent
   410  				GetRefundFunc: emptyRefund,
   411  				GetTransientStateFunc: func(slot types.SlotAddress) gethCommon.Hash {
   412  					switch slot {
   413  					case slot1:
   414  						return slot1InitValue
   415  					default:
   416  						return gethCommon.Hash{}
   417  					}
   418  				},
   419  			})
   420  
   421  		// get state through parent
   422  		value := view.GetTransientState(slot1)
   423  		require.Equal(t, slot1InitValue, value)
   424  
   425  		// set slot1 with some new value
   426  		newValue := gethCommon.BytesToHash([]byte{9, 8})
   427  		view.SetTransientState(slot1, newValue)
   428  
   429  		value = view.GetTransientState(slot1)
   430  		require.Equal(t, newValue, value)
   431  	})
   432  
   433  	t.Run("test refund functionality", func(t *testing.T) {
   434  		initRefund := uint64(10)
   435  		view := state.NewDeltaView(
   436  			&MockedReadOnlyView{
   437  				GetRefundFunc: func() uint64 {
   438  					return initRefund
   439  				},
   440  			})
   441  
   442  		// get refund through parent
   443  		value := view.GetRefund()
   444  		require.Equal(t, initRefund, value)
   445  
   446  		// add refund
   447  		addition := uint64(7)
   448  		err := view.AddRefund(addition)
   449  		require.NoError(t, err)
   450  		require.Equal(t, initRefund+addition, view.GetRefund())
   451  
   452  		// sub refund
   453  		subtract := uint64(2)
   454  		err = view.SubRefund(subtract)
   455  		require.NoError(t, err)
   456  		require.Equal(t, initRefund+addition-subtract, view.GetRefund())
   457  
   458  		// refund goes negative
   459  		err = view.SubRefund(1000)
   460  		require.Error(t, err)
   461  	})
   462  
   463  	t.Run("test access list functionality", func(t *testing.T) {
   464  		addr1 := testutils.RandomCommonAddress(t)
   465  		addr2 := testutils.RandomCommonAddress(t)
   466  		slot1 := types.SlotAddress{
   467  			Address: testutils.RandomCommonAddress(t),
   468  			Key:     gethCommon.BytesToHash([]byte{1, 2}),
   469  		}
   470  
   471  		slot2 := types.SlotAddress{
   472  			Address: testutils.RandomCommonAddress(t),
   473  			Key:     gethCommon.BytesToHash([]byte{3, 4}),
   474  		}
   475  
   476  		view := state.NewDeltaView(
   477  			&MockedReadOnlyView{
   478  				GetRefundFunc: emptyRefund,
   479  				AddressInAccessListFunc: func(addr gethCommon.Address) bool {
   480  					switch addr {
   481  					case addr1:
   482  						return true
   483  					default:
   484  						return false
   485  					}
   486  				},
   487  				SlotInAccessListFunc: func(slot types.SlotAddress) (addressOk bool, slotOk bool) {
   488  					switch slot {
   489  					case slot1:
   490  						return false, true
   491  					default:
   492  						return false, false
   493  					}
   494  				},
   495  			})
   496  
   497  		// check address through parent
   498  		require.True(t, view.AddressInAccessList(addr1))
   499  
   500  		// add addr 2 to the list
   501  		require.False(t, view.AddressInAccessList(addr2))
   502  		added := view.AddAddressToAccessList(addr2)
   503  		require.True(t, added)
   504  		require.True(t, view.AddressInAccessList(addr2))
   505  
   506  		// adding again
   507  		added = view.AddAddressToAccessList(addr2)
   508  		require.False(t, added)
   509  
   510  		// check slot through parent
   511  		addrFound, slotFound := view.SlotInAccessList(slot1)
   512  		require.False(t, addrFound)
   513  		require.True(t, slotFound)
   514  
   515  		// add slot 2 to the list
   516  		addrFound, slotFound = view.SlotInAccessList(slot2)
   517  		require.False(t, addrFound)
   518  		require.False(t, slotFound)
   519  
   520  		addressAdded, slotAdded := view.AddSlotToAccessList(slot2)
   521  		require.True(t, addressAdded)
   522  		require.True(t, slotAdded)
   523  
   524  		addrFound, slotFound = view.SlotInAccessList(slot2)
   525  		require.True(t, addrFound)
   526  		require.True(t, slotFound)
   527  
   528  		// adding again
   529  		addressAdded, slotAdded = view.AddSlotToAccessList(slot2)
   530  		require.False(t, addressAdded)
   531  		require.False(t, slotAdded)
   532  	})
   533  
   534  	t.Run("test log functionality", func(t *testing.T) {
   535  		view := state.NewDeltaView(
   536  			&MockedReadOnlyView{
   537  				GetRefundFunc: emptyRefund,
   538  			})
   539  
   540  		logs := view.Logs()
   541  		require.Empty(t, logs)
   542  
   543  		log1 := &gethTypes.Log{
   544  			Address: testutils.RandomCommonAddress(t),
   545  		}
   546  		view.AddLog(log1)
   547  
   548  		log2 := &gethTypes.Log{
   549  			Address: testutils.RandomCommonAddress(t),
   550  		}
   551  		view.AddLog(log2)
   552  
   553  		logs = view.Logs()
   554  		require.Equal(t, []*gethTypes.Log{log1, log2}, logs)
   555  	})
   556  
   557  	t.Run("test preimage functionality", func(t *testing.T) {
   558  		view := state.NewDeltaView(
   559  			&MockedReadOnlyView{
   560  				GetRefundFunc: emptyRefund,
   561  			})
   562  
   563  		preimages := view.Preimages()
   564  		require.Empty(t, preimages)
   565  
   566  		preimage1 := []byte{1, 2}
   567  		hash1 := gethCommon.BytesToHash([]byte{2, 3})
   568  		view.AddPreimage(hash1, preimage1)
   569  
   570  		preimage2 := []byte{4, 5}
   571  		hash2 := gethCommon.BytesToHash([]byte{6, 7})
   572  		view.AddPreimage(hash2, preimage2)
   573  
   574  		expected := make(map[gethCommon.Hash][]byte)
   575  		expected[hash1] = preimage1
   576  		expected[hash2] = preimage2
   577  
   578  		preimages = view.Preimages()
   579  		require.Equal(t, expected, preimages)
   580  	})
   581  
   582  	t.Run("test dirty addresses functionality", func(t *testing.T) {
   583  		addrCount := 6
   584  		addresses := make([]gethCommon.Address, addrCount)
   585  		for i := 0; i < addrCount; i++ {
   586  			addresses[i] = testutils.RandomCommonAddress(t)
   587  		}
   588  
   589  		view := state.NewDeltaView(
   590  			&MockedReadOnlyView{
   591  				// we need get refund for parent
   592  				GetRefundFunc: emptyRefund,
   593  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
   594  					return true, nil
   595  				},
   596  				GetBalanceFunc: func(addr gethCommon.Address) (*big.Int, error) {
   597  					return big.NewInt(10), nil
   598  				},
   599  				GetNonceFunc: func(addr gethCommon.Address) (uint64, error) {
   600  					return 0, nil
   601  				},
   602  				IsCreatedFunc: func(a gethCommon.Address) bool {
   603  					return false
   604  				},
   605  				HasSelfDestructedFunc: func(gethCommon.Address) (bool, *big.Int) {
   606  					return false, new(big.Int)
   607  				},
   608  			})
   609  
   610  		// check dirty addresses
   611  		dirtyAddresses := view.DirtyAddresses()
   612  		require.Empty(t, dirtyAddresses)
   613  
   614  		// create a account at address 1
   615  		err := view.CreateAccount(addresses[0])
   616  		require.NoError(t, err)
   617  
   618  		// self destruct address 2
   619  		err = view.SelfDestruct(addresses[1])
   620  		require.NoError(t, err)
   621  
   622  		// add balance for address 3
   623  		err = view.AddBalance(addresses[2], big.NewInt(5))
   624  		require.NoError(t, err)
   625  
   626  		// sub balance for address 4
   627  		err = view.AddBalance(addresses[3], big.NewInt(5))
   628  		require.NoError(t, err)
   629  
   630  		// set nonce for address 5
   631  		err = view.SetNonce(addresses[4], 5)
   632  		require.NoError(t, err)
   633  
   634  		// set code for address 6
   635  		err = view.SetCode(addresses[5], []byte{1, 2})
   636  		require.NoError(t, err)
   637  
   638  		// now check dirty addresses
   639  		dirtyAddresses = view.DirtyAddresses()
   640  		require.Len(t, dirtyAddresses, addrCount)
   641  		for _, addr := range addresses {
   642  			_, found := dirtyAddresses[addr]
   643  			require.True(t, found)
   644  		}
   645  	})
   646  
   647  	t.Run("test account creation after selfdestruct call", func(t *testing.T) {
   648  		addr1 := testutils.RandomCommonAddress(t)
   649  
   650  		view := state.NewDeltaView(
   651  			&MockedReadOnlyView{
   652  				// we need get refund for parent
   653  				GetRefundFunc: emptyRefund,
   654  				ExistFunc: func(addr gethCommon.Address) (bool, error) {
   655  					return true, nil
   656  				},
   657  				HasSelfDestructedFunc: func(gethCommon.Address) (bool, *big.Int) {
   658  					return true, big.NewInt(2)
   659  				},
   660  				IsCreatedFunc: func(a gethCommon.Address) bool {
   661  					return false
   662  				},
   663  				GetBalanceFunc: func(addr gethCommon.Address) (*big.Int, error) {
   664  					return new(big.Int), nil
   665  				},
   666  				GetStateFunc: func(sa types.SlotAddress) (gethCommon.Hash, error) {
   667  					return gethCommon.Hash{}, nil
   668  				},
   669  			})
   670  
   671  		found, err := view.Exist(addr1)
   672  		require.NoError(t, err)
   673  		require.True(t, found)
   674  
   675  		// set balance
   676  		initBalance := big.NewInt(10)
   677  		err = view.AddBalance(addr1, initBalance)
   678  		require.NoError(t, err)
   679  
   680  		bal, err := view.GetBalance(addr1)
   681  		require.NoError(t, err)
   682  		require.Equal(t, initBalance, bal)
   683  
   684  		// set code
   685  		code := []byte{1, 2, 3}
   686  		err = view.SetCode(addr1, code)
   687  		require.NoError(t, err)
   688  
   689  		ret, err := view.GetCode(addr1)
   690  		require.NoError(t, err)
   691  		require.Equal(t, code, ret)
   692  
   693  		// set key values
   694  		key := testutils.RandomCommonHash(t)
   695  		value := testutils.RandomCommonHash(t)
   696  		sk := types.SlotAddress{Address: addr1, Key: key}
   697  		err = view.SetState(sk, value)
   698  		require.NoError(t, err)
   699  
   700  		vret, err := view.GetState(sk)
   701  		require.NoError(t, err)
   702  		require.Equal(t, value, vret)
   703  
   704  		err = view.SelfDestruct(addr1)
   705  		require.NoError(t, err)
   706  
   707  		// balance should be returned zero
   708  		bal, err = view.GetBalance(addr1)
   709  		require.NoError(t, err)
   710  		require.Equal(t, new(big.Int), bal)
   711  
   712  		// get code should still work
   713  		ret, err = view.GetCode(addr1)
   714  		require.NoError(t, err)
   715  		require.Equal(t, code, ret)
   716  
   717  		// get state should also still work
   718  		vret, err = view.GetState(sk)
   719  		require.NoError(t, err)
   720  		require.Equal(t, value, vret)
   721  
   722  		// now re-create account
   723  		err = view.CreateAccount(addr1)
   724  		require.NoError(t, err)
   725  
   726  		// it should carry over the balance
   727  		bal, err = view.GetBalance(addr1)
   728  		require.NoError(t, err)
   729  		require.Equal(t, initBalance, bal)
   730  
   731  		ret, err = view.GetCode(addr1)
   732  		require.NoError(t, err)
   733  		require.Len(t, ret, 0)
   734  
   735  		vret, err = view.GetState(sk)
   736  		require.NoError(t, err)
   737  		emptyValue := gethCommon.Hash{}
   738  		require.Equal(t, emptyValue, vret)
   739  	})
   740  }
   741  
   742  type MockedReadOnlyView struct {
   743  	ExistFunc               func(gethCommon.Address) (bool, error)
   744  	HasSelfDestructedFunc   func(gethCommon.Address) (bool, *big.Int)
   745  	IsCreatedFunc           func(gethCommon.Address) bool
   746  	GetBalanceFunc          func(gethCommon.Address) (*big.Int, error)
   747  	GetNonceFunc            func(gethCommon.Address) (uint64, error)
   748  	GetCodeFunc             func(gethCommon.Address) ([]byte, error)
   749  	GetCodeHashFunc         func(gethCommon.Address) (gethCommon.Hash, error)
   750  	GetCodeSizeFunc         func(gethCommon.Address) (int, error)
   751  	GetStateFunc            func(types.SlotAddress) (gethCommon.Hash, error)
   752  	GetTransientStateFunc   func(types.SlotAddress) gethCommon.Hash
   753  	GetRefundFunc           func() uint64
   754  	AddressInAccessListFunc func(gethCommon.Address) bool
   755  	SlotInAccessListFunc    func(types.SlotAddress) (addressOk bool, slotOk bool)
   756  }
   757  
   758  var _ types.ReadOnlyView = &MockedReadOnlyView{}
   759  
   760  func (v *MockedReadOnlyView) Exist(addr gethCommon.Address) (bool, error) {
   761  	if v.ExistFunc == nil {
   762  		panic("Exist is not set in this mocked view")
   763  	}
   764  	return v.ExistFunc(addr)
   765  }
   766  
   767  func (v *MockedReadOnlyView) IsCreated(addr gethCommon.Address) bool {
   768  	if v.IsCreatedFunc == nil {
   769  		panic("IsCreated is not set in this mocked view")
   770  	}
   771  	return v.IsCreatedFunc(addr)
   772  }
   773  
   774  func (v *MockedReadOnlyView) HasSelfDestructed(addr gethCommon.Address) (bool, *big.Int) {
   775  	if v.HasSelfDestructedFunc == nil {
   776  		panic("HasSelfDestructed is not set in this mocked view")
   777  	}
   778  	return v.HasSelfDestructedFunc(addr)
   779  }
   780  
   781  func (v *MockedReadOnlyView) GetBalance(addr gethCommon.Address) (*big.Int, error) {
   782  	if v.GetBalanceFunc == nil {
   783  		panic("GetBalance is not set in this mocked view")
   784  	}
   785  	return v.GetBalanceFunc(addr)
   786  }
   787  
   788  func (v *MockedReadOnlyView) GetNonce(addr gethCommon.Address) (uint64, error) {
   789  	if v.GetNonceFunc == nil {
   790  		panic("GetNonce is not set in this mocked view")
   791  	}
   792  	return v.GetNonceFunc(addr)
   793  }
   794  
   795  func (v *MockedReadOnlyView) GetCode(addr gethCommon.Address) ([]byte, error) {
   796  	if v.GetCodeFunc == nil {
   797  		panic("GetCode is not set in this mocked view")
   798  	}
   799  	return v.GetCodeFunc(addr)
   800  }
   801  
   802  func (v *MockedReadOnlyView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) {
   803  	if v.GetCodeHashFunc == nil {
   804  		panic("GetCodeHash is not set in this mocked view")
   805  	}
   806  	return v.GetCodeHashFunc(addr)
   807  }
   808  
   809  func (v *MockedReadOnlyView) GetCodeSize(addr gethCommon.Address) (int, error) {
   810  	if v.GetCodeSizeFunc == nil {
   811  		panic("GetCodeSize is not set in this mocked view")
   812  	}
   813  	return v.GetCodeSizeFunc(addr)
   814  }
   815  
   816  func (v *MockedReadOnlyView) GetState(slot types.SlotAddress) (gethCommon.Hash, error) {
   817  	if v.GetStateFunc == nil {
   818  		panic("GetState is not set in this mocked view")
   819  	}
   820  	return v.GetStateFunc(slot)
   821  }
   822  
   823  func (v *MockedReadOnlyView) GetTransientState(slot types.SlotAddress) gethCommon.Hash {
   824  	if v.GetTransientStateFunc == nil {
   825  		panic("GetTransientState is not set in this mocked view")
   826  	}
   827  	return v.GetTransientStateFunc(slot)
   828  }
   829  
   830  func (v *MockedReadOnlyView) GetRefund() uint64 {
   831  	if v.GetRefundFunc == nil {
   832  		panic("GetRefund is not set in this mocked view")
   833  	}
   834  	return v.GetRefundFunc()
   835  }
   836  
   837  func (v *MockedReadOnlyView) AddressInAccessList(addr gethCommon.Address) bool {
   838  	if v.AddressInAccessListFunc == nil {
   839  		panic("AddressInAccessList is not set in this mocked view")
   840  	}
   841  	return v.AddressInAccessListFunc(addr)
   842  }
   843  
   844  func (v *MockedReadOnlyView) SlotInAccessList(slot types.SlotAddress) (addressOk bool, slotOk bool) {
   845  	if v.SlotInAccessListFunc == nil {
   846  		panic("SlotInAccessList is not set in this mocked view")
   847  	}
   848  	return v.SlotInAccessListFunc(slot)
   849  }