github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/accounts_test.go (about)

     1  package environment_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/onflow/atree"
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/onflow/flow-go/fvm/environment"
    10  	"github.com/onflow/flow-go/fvm/errors"
    11  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    12  	"github.com/onflow/flow-go/fvm/storage/testutils"
    13  	"github.com/onflow/flow-go/model/flow"
    14  )
    15  
    16  func TestAccounts_Create(t *testing.T) {
    17  	t.Run("Sets registers", func(t *testing.T) {
    18  		txnState := testutils.NewSimpleTransaction(nil)
    19  		accounts := environment.NewAccounts(txnState)
    20  
    21  		address := flow.HexToAddress("01")
    22  
    23  		err := accounts.Create(nil, address)
    24  		require.NoError(t, err)
    25  
    26  		snapshot, err := txnState.FinalizeMainTransaction()
    27  		require.NoError(t, err)
    28  
    29  		// account status
    30  		require.Equal(t, len(snapshot.AllRegisterIDs()), 1)
    31  	})
    32  
    33  	t.Run("Fails if account exists", func(t *testing.T) {
    34  		txnState := testutils.NewSimpleTransaction(nil)
    35  		accounts := environment.NewAccounts(txnState)
    36  		address := flow.HexToAddress("01")
    37  
    38  		err := accounts.Create(nil, address)
    39  		require.NoError(t, err)
    40  
    41  		err = accounts.Create(nil, address)
    42  
    43  		require.Error(t, err)
    44  	})
    45  }
    46  
    47  func TestAccounts_GetWithNoKeys(t *testing.T) {
    48  	txnState := testutils.NewSimpleTransaction(nil)
    49  	accounts := environment.NewAccounts(txnState)
    50  	address := flow.HexToAddress("01")
    51  
    52  	err := accounts.Create(nil, address)
    53  	require.NoError(t, err)
    54  
    55  	require.NotPanics(t, func() {
    56  		_, _ = accounts.Get(address)
    57  	})
    58  }
    59  
    60  func TestAccounts_GetPublicKey(t *testing.T) {
    61  
    62  	t.Run("non-existent key index", func(t *testing.T) {
    63  
    64  		address := flow.HexToAddress("01")
    65  		registerId := flow.NewRegisterID(
    66  			address,
    67  			"public_key_0")
    68  
    69  		for _, value := range [][]byte{{}, nil} {
    70  			txnState := testutils.NewSimpleTransaction(
    71  				snapshot.MapStorageSnapshot{
    72  					registerId: value,
    73  				})
    74  			accounts := environment.NewAccounts(txnState)
    75  
    76  			err := accounts.Create(nil, address)
    77  			require.NoError(t, err)
    78  
    79  			_, err = accounts.GetPublicKey(address, 0)
    80  			require.True(t, errors.IsAccountPublicKeyNotFoundError(err))
    81  		}
    82  	})
    83  }
    84  
    85  func TestAccounts_GetPublicKeyCount(t *testing.T) {
    86  
    87  	t.Run("non-existent key count", func(t *testing.T) {
    88  
    89  		address := flow.HexToAddress("01")
    90  		registerId := flow.NewRegisterID(
    91  			address,
    92  			"public_key_count")
    93  
    94  		for _, value := range [][]byte{{}, nil} {
    95  			txnState := testutils.NewSimpleTransaction(
    96  				snapshot.MapStorageSnapshot{
    97  					registerId: value,
    98  				})
    99  			accounts := environment.NewAccounts(txnState)
   100  
   101  			err := accounts.Create(nil, address)
   102  			require.NoError(t, err)
   103  
   104  			count, err := accounts.GetPublicKeyCount(address)
   105  			require.NoError(t, err)
   106  			require.Equal(t, uint64(0), count)
   107  		}
   108  	})
   109  }
   110  
   111  func TestAccounts_GetPublicKeys(t *testing.T) {
   112  
   113  	t.Run("non-existent key count", func(t *testing.T) {
   114  
   115  		address := flow.HexToAddress("01")
   116  		registerId := flow.NewRegisterID(
   117  			address,
   118  			"public_key_count")
   119  
   120  		for _, value := range [][]byte{{}, nil} {
   121  			txnState := testutils.NewSimpleTransaction(
   122  				snapshot.MapStorageSnapshot{
   123  					registerId: value,
   124  				})
   125  
   126  			accounts := environment.NewAccounts(txnState)
   127  
   128  			err := accounts.Create(nil, address)
   129  			require.NoError(t, err)
   130  
   131  			keys, err := accounts.GetPublicKeys(address)
   132  			require.NoError(t, err)
   133  			require.Empty(t, keys)
   134  		}
   135  	})
   136  }
   137  
   138  func TestAccounts_SetContracts(t *testing.T) {
   139  
   140  	address := flow.HexToAddress("0x01")
   141  
   142  	t.Run("Setting a contract puts it in Contracts", func(t *testing.T) {
   143  		txnState := testutils.NewSimpleTransaction(nil)
   144  		a := environment.NewAccounts(txnState)
   145  		err := a.Create(nil, address)
   146  		require.NoError(t, err)
   147  
   148  		err = a.SetContract("Dummy", address, []byte("non empty string"))
   149  		require.NoError(t, err)
   150  
   151  		contractNames, err := a.GetContractNames(address)
   152  		require.NoError(t, err)
   153  
   154  		require.Len(t, contractNames, 1, "There should only be one contract")
   155  		require.Equal(t, contractNames[0], "Dummy")
   156  	})
   157  	t.Run("Setting a contract again, does not add it to contracts", func(t *testing.T) {
   158  		txnState := testutils.NewSimpleTransaction(nil)
   159  		a := environment.NewAccounts(txnState)
   160  		err := a.Create(nil, address)
   161  		require.NoError(t, err)
   162  
   163  		err = a.SetContract("Dummy", address, []byte("non empty string"))
   164  		require.NoError(t, err)
   165  
   166  		err = a.SetContract("Dummy", address, []byte("non empty string"))
   167  		require.NoError(t, err)
   168  
   169  		contractNames, err := a.GetContractNames(address)
   170  		require.NoError(t, err)
   171  
   172  		require.Len(t, contractNames, 1, "There should only be one contract")
   173  		require.Equal(t, contractNames[0], "Dummy")
   174  	})
   175  	t.Run("Setting more contracts always keeps them sorted", func(t *testing.T) {
   176  		txnState := testutils.NewSimpleTransaction(nil)
   177  		a := environment.NewAccounts(txnState)
   178  		err := a.Create(nil, address)
   179  		require.NoError(t, err)
   180  
   181  		err = a.SetContract("Dummy", address, []byte("non empty string"))
   182  		require.NoError(t, err)
   183  
   184  		err = a.SetContract("ZedDummy", address, []byte("non empty string"))
   185  		require.NoError(t, err)
   186  
   187  		err = a.SetContract("ADummy", address, []byte("non empty string"))
   188  		require.NoError(t, err)
   189  
   190  		contractNames, err := a.GetContractNames(address)
   191  		require.NoError(t, err)
   192  
   193  		require.Len(t, contractNames, 3)
   194  		require.Equal(t, contractNames[0], "ADummy")
   195  		require.Equal(t, contractNames[1], "Dummy")
   196  		require.Equal(t, contractNames[2], "ZedDummy")
   197  	})
   198  	t.Run("Removing a contract does not fail if there is none", func(t *testing.T) {
   199  		txnState := testutils.NewSimpleTransaction(nil)
   200  		a := environment.NewAccounts(txnState)
   201  		err := a.Create(nil, address)
   202  		require.NoError(t, err)
   203  
   204  		err = a.DeleteContract("Dummy", address)
   205  		require.NoError(t, err)
   206  	})
   207  	t.Run("Removing a contract removes it", func(t *testing.T) {
   208  		txnState := testutils.NewSimpleTransaction(nil)
   209  		a := environment.NewAccounts(txnState)
   210  		err := a.Create(nil, address)
   211  		require.NoError(t, err)
   212  
   213  		err = a.SetContract("Dummy", address, []byte("non empty string"))
   214  		require.NoError(t, err)
   215  
   216  		err = a.DeleteContract("Dummy", address)
   217  		require.NoError(t, err)
   218  
   219  		contractNames, err := a.GetContractNames(address)
   220  		require.NoError(t, err)
   221  
   222  		require.Len(t, contractNames, 0, "There should be no contract")
   223  	})
   224  }
   225  
   226  func TestAccount_StorageUsed(t *testing.T) {
   227  	emptyAccountSize := uint64(48)
   228  
   229  	t.Run("Storage used on account creation is deterministic", func(t *testing.T) {
   230  		txnState := testutils.NewSimpleTransaction(nil)
   231  		accounts := environment.NewAccounts(txnState)
   232  		address := flow.HexToAddress("01")
   233  
   234  		err := accounts.Create(nil, address)
   235  		require.NoError(t, err)
   236  
   237  		storageUsed, err := accounts.GetStorageUsed(address)
   238  		require.NoError(t, err)
   239  		require.Equal(t, emptyAccountSize, storageUsed)
   240  	})
   241  
   242  	t.Run("Storage used on register set increases", func(t *testing.T) {
   243  		txnState := testutils.NewSimpleTransaction(nil)
   244  		accounts := environment.NewAccounts(txnState)
   245  		address := flow.HexToAddress("01")
   246  		key := flow.NewRegisterID(address, "some_key")
   247  
   248  		err := accounts.Create(nil, address)
   249  		require.NoError(t, err)
   250  
   251  		err = accounts.SetValue(key, createByteArray(12))
   252  		require.NoError(t, err)
   253  
   254  		storageUsed, err := accounts.GetStorageUsed(address)
   255  		require.NoError(t, err)
   256  		require.Equal(t, emptyAccountSize+uint64(32), storageUsed)
   257  	})
   258  
   259  	t.Run("Storage used, set twice on same register to same value, stays the same", func(t *testing.T) {
   260  		txnState := testutils.NewSimpleTransaction(nil)
   261  		accounts := environment.NewAccounts(txnState)
   262  		address := flow.HexToAddress("01")
   263  		key := flow.NewRegisterID(address, "some_key")
   264  
   265  		err := accounts.Create(nil, address)
   266  		require.NoError(t, err)
   267  
   268  		err = accounts.SetValue(key, createByteArray(12))
   269  		require.NoError(t, err)
   270  		err = accounts.SetValue(key, createByteArray(12))
   271  		require.NoError(t, err)
   272  
   273  		storageUsed, err := accounts.GetStorageUsed(address)
   274  		require.NoError(t, err)
   275  		require.Equal(t, emptyAccountSize+uint64(32), storageUsed)
   276  	})
   277  
   278  	t.Run("Storage used, set twice on same register to larger value, increases", func(t *testing.T) {
   279  		txnState := testutils.NewSimpleTransaction(nil)
   280  		accounts := environment.NewAccounts(txnState)
   281  		address := flow.HexToAddress("01")
   282  		key := flow.NewRegisterID(address, "some_key")
   283  
   284  		err := accounts.Create(nil, address)
   285  		require.NoError(t, err)
   286  
   287  		err = accounts.SetValue(key, createByteArray(12))
   288  		require.NoError(t, err)
   289  		err = accounts.SetValue(key, createByteArray(13))
   290  		require.NoError(t, err)
   291  
   292  		storageUsed, err := accounts.GetStorageUsed(address)
   293  		require.NoError(t, err)
   294  		require.Equal(t, emptyAccountSize+uint64(33), storageUsed)
   295  	})
   296  
   297  	t.Run("Storage used, set twice on same register to smaller value, decreases", func(t *testing.T) {
   298  		txnState := testutils.NewSimpleTransaction(nil)
   299  		accounts := environment.NewAccounts(txnState)
   300  		address := flow.HexToAddress("01")
   301  		key := flow.NewRegisterID(address, "some_key")
   302  
   303  		err := accounts.Create(nil, address)
   304  		require.NoError(t, err)
   305  
   306  		err = accounts.SetValue(key, createByteArray(12))
   307  		require.NoError(t, err)
   308  		err = accounts.SetValue(key, createByteArray(11))
   309  		require.NoError(t, err)
   310  
   311  		storageUsed, err := accounts.GetStorageUsed(address)
   312  		require.NoError(t, err)
   313  		require.Equal(t, emptyAccountSize+uint64(31), storageUsed)
   314  	})
   315  
   316  	t.Run("Storage used, after register deleted, decreases", func(t *testing.T) {
   317  		txnState := testutils.NewSimpleTransaction(nil)
   318  		accounts := environment.NewAccounts(txnState)
   319  		address := flow.HexToAddress("01")
   320  		key := flow.NewRegisterID(address, "some_key")
   321  
   322  		err := accounts.Create(nil, address)
   323  		require.NoError(t, err)
   324  
   325  		err = accounts.SetValue(key, createByteArray(12))
   326  		require.NoError(t, err)
   327  		err = accounts.SetValue(key, nil)
   328  		require.NoError(t, err)
   329  
   330  		storageUsed, err := accounts.GetStorageUsed(address)
   331  		require.NoError(t, err)
   332  		require.Equal(t, emptyAccountSize+uint64(0), storageUsed)
   333  	})
   334  
   335  	t.Run("Storage used on a complex scenario has correct value", func(t *testing.T) {
   336  		txnState := testutils.NewSimpleTransaction(nil)
   337  		accounts := environment.NewAccounts(txnState)
   338  		address := flow.HexToAddress("01")
   339  
   340  		err := accounts.Create(nil, address)
   341  		require.NoError(t, err)
   342  
   343  		key1 := flow.NewRegisterID(address, "some_key")
   344  		err = accounts.SetValue(key1, createByteArray(12))
   345  		require.NoError(t, err)
   346  		err = accounts.SetValue(key1, createByteArray(11))
   347  		require.NoError(t, err)
   348  
   349  		key2 := flow.NewRegisterID(address, "some_key2")
   350  		err = accounts.SetValue(key2, createByteArray(22))
   351  		require.NoError(t, err)
   352  		err = accounts.SetValue(key2, createByteArray(23))
   353  		require.NoError(t, err)
   354  
   355  		key3 := flow.NewRegisterID(address, "some_key3")
   356  		err = accounts.SetValue(key3, createByteArray(22))
   357  		require.NoError(t, err)
   358  		err = accounts.SetValue(key3, createByteArray(0))
   359  		require.NoError(t, err)
   360  
   361  		storageUsed, err := accounts.GetStorageUsed(address)
   362  		require.NoError(t, err)
   363  		require.Equal(t, emptyAccountSize+uint64(33+42), storageUsed)
   364  	})
   365  }
   366  
   367  func TestStatefulAccounts_GenerateAccountLocalID(t *testing.T) {
   368  
   369  	// Create 3 accounts
   370  	addressA := flow.HexToAddress("0x01")
   371  	addressB := flow.HexToAddress("0x02")
   372  	addressC := flow.HexToAddress("0x03")
   373  	txnState := testutils.NewSimpleTransaction(nil)
   374  	a := environment.NewAccounts(txnState)
   375  	err := a.Create(nil, addressA)
   376  	require.NoError(t, err)
   377  	err = a.Create(nil, addressB)
   378  	require.NoError(t, err)
   379  	err = a.Create(nil, addressC)
   380  	require.NoError(t, err)
   381  
   382  	// setup some state
   383  	_, err = a.GenerateAccountLocalID(addressA)
   384  	require.NoError(t, err)
   385  	_, err = a.GenerateAccountLocalID(addressA)
   386  	require.NoError(t, err)
   387  	_, err = a.GenerateAccountLocalID(addressB)
   388  	require.NoError(t, err)
   389  
   390  	// assert
   391  
   392  	// addressA
   393  	id, err := a.GenerateAccountLocalID(addressA)
   394  	require.NoError(t, err)
   395  	require.Equal(t, uint64(3), id)
   396  
   397  	// addressB
   398  	id, err = a.GenerateAccountLocalID(addressB)
   399  	require.NoError(t, err)
   400  	require.Equal(t, uint64(2), id)
   401  
   402  	// addressC
   403  	id, err = a.GenerateAccountLocalID(addressC)
   404  	require.NoError(t, err)
   405  	require.Equal(t, uint64(1), id)
   406  }
   407  
   408  func createByteArray(size int) []byte {
   409  	bytes := make([]byte, size)
   410  	for i := range bytes {
   411  		bytes[i] = 255
   412  	}
   413  	return bytes
   414  }
   415  
   416  func TestAccounts_AllocateStorageIndex(t *testing.T) {
   417  	txnState := testutils.NewSimpleTransaction(nil)
   418  	accounts := environment.NewAccounts(txnState)
   419  	address := flow.HexToAddress("01")
   420  
   421  	err := accounts.Create(nil, address)
   422  	require.NoError(t, err)
   423  
   424  	// no register set case
   425  	i, err := accounts.AllocateSlabIndex(address)
   426  	require.NoError(t, err)
   427  	require.Equal(t, i, atree.SlabIndex([8]byte{0, 0, 0, 0, 0, 0, 0, 1}))
   428  
   429  	// register already set case
   430  	i, err = accounts.AllocateSlabIndex(address)
   431  	require.NoError(t, err)
   432  	require.Equal(t, i, atree.SlabIndex([8]byte{0, 0, 0, 0, 0, 0, 0, 2}))
   433  
   434  	// register update successful
   435  	i, err = accounts.AllocateSlabIndex(address)
   436  	require.NoError(t, err)
   437  	require.Equal(t, i, atree.SlabIndex([8]byte{0, 0, 0, 0, 0, 0, 0, 3}))
   438  }