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

     1  package state_test
     2  
     3  import (
     4  	"math/big"
     5  	"testing"
     6  
     7  	gethCommon "github.com/ethereum/go-ethereum/common"
     8  	gethTypes "github.com/ethereum/go-ethereum/core/types"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/onflow/flow-go/fvm/evm/emulator/state"
    12  	"github.com/onflow/flow-go/fvm/evm/testutils"
    13  	"github.com/onflow/flow-go/fvm/evm/types"
    14  	"github.com/onflow/flow-go/model/flow"
    15  )
    16  
    17  func TestBaseView(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	t.Run("test account functionalities", func(t *testing.T) {
    21  		ledger := testutils.GetSimpleValueStore()
    22  		rootAddr := flow.Address{1, 2, 3, 4, 5, 6, 7, 8}
    23  		view, err := state.NewBaseView(ledger, rootAddr)
    24  		require.NoError(t, err)
    25  
    26  		addr1 := testutils.RandomCommonAddress(t)
    27  
    28  		// data calls for a non-existent account
    29  		checkAccount(t,
    30  			view,
    31  			addr1,
    32  			false,
    33  			big.NewInt(0),
    34  			uint64(0),
    35  			nil,
    36  			gethTypes.EmptyCodeHash,
    37  		)
    38  
    39  		// create an account with code
    40  		newBal := big.NewInt(10)
    41  		newNonce := uint64(5)
    42  		newCode := []byte("some code")
    43  		newCodeHash := gethCommon.Hash{1, 2}
    44  
    45  		err = view.CreateAccount(addr1, newBal, newNonce, newCode, newCodeHash)
    46  		require.NoError(t, err)
    47  
    48  		// check data from cache
    49  		checkAccount(t,
    50  			view,
    51  			addr1,
    52  			true,
    53  			newBal,
    54  			newNonce,
    55  			newCode,
    56  			newCodeHash,
    57  		)
    58  
    59  		// commit the changes and create a new baseview
    60  		err = view.Commit()
    61  		require.NoError(t, err)
    62  
    63  		view, err = state.NewBaseView(ledger, rootAddr)
    64  		require.NoError(t, err)
    65  
    66  		checkAccount(t,
    67  			view,
    68  			addr1,
    69  			true,
    70  			newBal,
    71  			newNonce,
    72  			newCode,
    73  			newCodeHash,
    74  		)
    75  
    76  		// test update account
    77  
    78  		newBal = big.NewInt(12)
    79  		newNonce = uint64(6)
    80  		newCode = []byte("some new code")
    81  		newCodeHash = gethCommon.Hash{2, 3}
    82  		err = view.UpdateAccount(addr1, newBal, newNonce, newCode, newCodeHash)
    83  		require.NoError(t, err)
    84  
    85  		// check data from cache
    86  		checkAccount(t,
    87  			view,
    88  			addr1,
    89  			true,
    90  			newBal,
    91  			newNonce,
    92  			newCode,
    93  			newCodeHash,
    94  		)
    95  
    96  		// commit the changes and create a new baseview
    97  		err = view.Commit()
    98  		require.NoError(t, err)
    99  
   100  		view, err = state.NewBaseView(ledger, rootAddr)
   101  		require.NoError(t, err)
   102  
   103  		checkAccount(t,
   104  			view,
   105  			addr1,
   106  			true,
   107  			newBal,
   108  			newNonce,
   109  			newCode,
   110  			newCodeHash,
   111  		)
   112  
   113  		// test delete account
   114  
   115  		err = view.DeleteAccount(addr1)
   116  		require.NoError(t, err)
   117  
   118  		// check from cache
   119  		checkAccount(t,
   120  			view,
   121  			addr1,
   122  			false,
   123  			big.NewInt(0),
   124  			uint64(0),
   125  			nil,
   126  			gethTypes.EmptyCodeHash,
   127  		)
   128  
   129  		// commit the changes and create a new baseview
   130  		err = view.Commit()
   131  		require.NoError(t, err)
   132  
   133  		view, err = state.NewBaseView(ledger, rootAddr)
   134  		require.NoError(t, err)
   135  
   136  		checkAccount(t,
   137  			view,
   138  			addr1,
   139  			false,
   140  			big.NewInt(0),
   141  			uint64(0),
   142  			nil,
   143  			gethTypes.EmptyCodeHash,
   144  		)
   145  	})
   146  
   147  	t.Run("test slot storage", func(t *testing.T) {
   148  		ledger := testutils.GetSimpleValueStore()
   149  		rootAddr := flow.Address{1, 2, 3, 4, 5, 6, 7, 8}
   150  		view, err := state.NewBaseView(ledger, rootAddr)
   151  		require.NoError(t, err)
   152  
   153  		addr1 := testutils.RandomCommonAddress(t)
   154  		key1 := testutils.RandomCommonHash(t)
   155  		slot1 := types.SlotAddress{
   156  			Address: addr1,
   157  			Key:     key1,
   158  		}
   159  
   160  		// non-existent account
   161  		value, err := view.GetState(slot1)
   162  		require.NoError(t, err)
   163  		require.Equal(t, value, gethCommon.Hash{})
   164  
   165  		// store a new value
   166  		newValue := testutils.RandomCommonHash(t)
   167  
   168  		// updating slot for non-existent account should fail
   169  		err = view.UpdateSlot(slot1, newValue)
   170  		require.Error(t, err)
   171  
   172  		// account should have code to have slots
   173  		err = view.CreateAccount(addr1, big.NewInt(10), 0, []byte("ABC"), gethCommon.Hash{1, 2, 3})
   174  		require.NoError(t, err)
   175  
   176  		err = view.UpdateSlot(slot1, newValue)
   177  		require.NoError(t, err)
   178  
   179  		// return result from the cache
   180  		value, err = view.GetState(slot1)
   181  		require.NoError(t, err)
   182  		require.Equal(t, newValue, value)
   183  
   184  		// commit changes
   185  		err = view.Commit()
   186  		require.NoError(t, err)
   187  
   188  		view2, err := state.NewBaseView(ledger, rootAddr)
   189  		require.NoError(t, err)
   190  
   191  		// return state from ledger
   192  		value, err = view2.GetState(slot1)
   193  		require.NoError(t, err)
   194  		require.Equal(t, newValue, value)
   195  	})
   196  
   197  	t.Run("default values method calls", func(t *testing.T) {
   198  		// calls to these method that has always same value
   199  		view, err := state.NewBaseView(testutils.GetSimpleValueStore(), flow.Address{1, 2, 3, 4})
   200  		require.NoError(t, err)
   201  
   202  		dest, bal := view.HasSelfDestructed(gethCommon.Address{})
   203  		require.Equal(t, false, dest)
   204  		require.Equal(t, new(big.Int), bal)
   205  		require.Equal(t, false, view.IsCreated(gethCommon.Address{}))
   206  		require.Equal(t, uint64(0), view.GetRefund())
   207  		require.Equal(t, gethCommon.Hash{}, view.GetTransientState(types.SlotAddress{}))
   208  		require.Equal(t, false, view.AddressInAccessList(gethCommon.Address{}))
   209  		addrFound, slotFound := view.SlotInAccessList(types.SlotAddress{})
   210  		require.Equal(t, false, addrFound)
   211  		require.Equal(t, false, slotFound)
   212  	})
   213  }
   214  
   215  func checkAccount(t *testing.T,
   216  	view *state.BaseView,
   217  	addr gethCommon.Address,
   218  	exists bool,
   219  	balance *big.Int,
   220  	nonce uint64,
   221  	code []byte,
   222  	codeHash gethCommon.Hash,
   223  ) {
   224  	ex, err := view.Exist(addr)
   225  	require.NoError(t, err)
   226  	require.Equal(t, exists, ex)
   227  
   228  	bal, err := view.GetBalance(addr)
   229  	require.NoError(t, err)
   230  	require.Equal(t, balance, bal)
   231  
   232  	no, err := view.GetNonce(addr)
   233  	require.NoError(t, err)
   234  	require.Equal(t, nonce, no)
   235  
   236  	cd, err := view.GetCode(addr)
   237  	require.NoError(t, err)
   238  	require.Equal(t, code, cd)
   239  
   240  	cs, err := view.GetCodeSize(addr)
   241  	require.NoError(t, err)
   242  	require.Equal(t, len(code), cs)
   243  
   244  	ch, err := view.GetCodeHash(addr)
   245  	require.NoError(t, err)
   246  	require.Equal(t, codeHash, ch)
   247  }