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

     1  package state
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  
     8  	"github.com/onflow/flow-go/fvm/storage/snapshot"
     9  	"github.com/onflow/flow-go/model/flow"
    10  	"github.com/onflow/flow-go/utils/unittest"
    11  )
    12  
    13  func TestStorageStateSet(t *testing.T) {
    14  	fooOwner := unittest.RandomAddressFixture()
    15  
    16  	registerId1 := flow.NewRegisterID(fooOwner, "1")
    17  	value1 := flow.RegisterValue([]byte("value1"))
    18  
    19  	registerId2 := flow.NewRegisterID(fooOwner, "2")
    20  	value2 := flow.RegisterValue([]byte("value2"))
    21  
    22  	state := newStorageState(nil)
    23  
    24  	err := state.Set(registerId1, []byte("old value"))
    25  	require.NoError(t, err)
    26  
    27  	err = state.Set(registerId2, value2)
    28  	require.NoError(t, err)
    29  
    30  	err = state.Set(registerId1, value1)
    31  	require.NoError(t, err)
    32  
    33  	snapshot := state.Finalize()
    34  	require.Empty(t, snapshot.ReadSet)
    35  	require.Equal(
    36  		t,
    37  		snapshot.WriteSet,
    38  		map[flow.RegisterID]flow.RegisterValue{
    39  			registerId1: value1,
    40  			registerId2: value2,
    41  		})
    42  }
    43  
    44  func TestStorageStateGetFromNilBase(t *testing.T) {
    45  	state := newStorageState(nil)
    46  	value, err := state.Get(flow.NewRegisterID(unittest.RandomAddressFixture(), "bar"))
    47  	require.NoError(t, err)
    48  	require.Nil(t, value)
    49  }
    50  
    51  func TestStorageStateGetFromBase(t *testing.T) {
    52  	registerId := flow.NewRegisterID(flow.EmptyAddress, "base")
    53  	baseValue := flow.RegisterValue([]byte("base"))
    54  
    55  	state := newStorageState(
    56  		snapshot.MapStorageSnapshot{
    57  			registerId: baseValue,
    58  		})
    59  
    60  	value, err := state.Get(registerId)
    61  	require.NoError(t, err)
    62  	require.Equal(t, value, baseValue)
    63  
    64  	// Finalize to ensure read set is updated.
    65  	snapshot := state.Finalize()
    66  	require.Equal(
    67  		t,
    68  		snapshot.ReadSet,
    69  		map[flow.RegisterID]struct{}{
    70  			registerId: struct{}{},
    71  		})
    72  	require.Empty(t, snapshot.WriteSet)
    73  
    74  	// Override a previous read value won't change the read set.
    75  	updatedValue := flow.RegisterValue([]byte("value"))
    76  	err = state.Set(registerId, updatedValue)
    77  	require.NoError(t, err)
    78  
    79  	snapshot = state.Finalize()
    80  	require.Equal(
    81  		t,
    82  		snapshot.ReadSet,
    83  		map[flow.RegisterID]struct{}{
    84  			registerId: struct{}{},
    85  		})
    86  	require.Equal(
    87  		t,
    88  		snapshot.WriteSet,
    89  		map[flow.RegisterID]flow.RegisterValue{
    90  			registerId: updatedValue,
    91  		})
    92  }
    93  
    94  func TestStorageStateGetFromWriteSet(t *testing.T) {
    95  	registerId := flow.NewRegisterID(flow.EmptyAddress, "base")
    96  	expectedValue := flow.RegisterValue([]byte("base"))
    97  
    98  	state := newStorageState(nil)
    99  
   100  	err := state.Set(registerId, expectedValue)
   101  	require.NoError(t, err)
   102  
   103  	value, err := state.Get(registerId)
   104  	require.NoError(t, err)
   105  	require.Equal(t, value, expectedValue)
   106  
   107  	snapshot := state.Finalize()
   108  	require.Empty(t, snapshot.ReadSet)
   109  	require.Equal(
   110  		t,
   111  		snapshot.WriteSet,
   112  		map[flow.RegisterID]flow.RegisterValue{
   113  			registerId: expectedValue,
   114  		})
   115  }
   116  
   117  func TestStorageStateMerge(t *testing.T) {
   118  	parentOwner := unittest.RandomAddressFixture()
   119  	childOwner := unittest.RandomAddressFixture()
   120  
   121  	baseRegisterId := flow.NewRegisterID(flow.EmptyAddress, "base")
   122  	baseValue := flow.RegisterValue([]byte("base"))
   123  
   124  	parentRegisterId1 := flow.NewRegisterID(parentOwner, "1")
   125  	parentValue := flow.RegisterValue([]byte("parent"))
   126  
   127  	parentRegisterId2 := flow.NewRegisterID(parentOwner, "2")
   128  
   129  	parentRegisterId3 := flow.NewRegisterID(parentOwner, "3")
   130  	originalParentValue3 := flow.RegisterValue([]byte("parent value"))
   131  	updatedParentValue3 := flow.RegisterValue([]byte("child value"))
   132  
   133  	childRegisterId1 := flow.NewRegisterID(childOwner, "1")
   134  	childValue1 := flow.RegisterValue([]byte("child"))
   135  
   136  	childRegisterId2 := flow.NewRegisterID(childOwner, "2")
   137  
   138  	parent := newStorageState(
   139  		snapshot.MapStorageSnapshot{
   140  			baseRegisterId: baseValue,
   141  		})
   142  
   143  	err := parent.Set(parentRegisterId1, parentValue)
   144  	require.NoError(t, err)
   145  
   146  	value, err := parent.Get(parentRegisterId2)
   147  	require.NoError(t, err)
   148  	require.Nil(t, value)
   149  
   150  	err = parent.Set(parentRegisterId3, originalParentValue3)
   151  	require.NoError(t, err)
   152  
   153  	child := parent.NewChild()
   154  
   155  	err = child.Set(parentRegisterId3, updatedParentValue3)
   156  	require.NoError(t, err)
   157  
   158  	value, err = child.Get(baseRegisterId)
   159  	require.NoError(t, err)
   160  	require.Equal(t, value, baseValue)
   161  
   162  	value, err = child.Get(parentRegisterId1)
   163  	require.NoError(t, err)
   164  	require.Equal(t, value, parentValue)
   165  
   166  	value, err = child.Get(childRegisterId2)
   167  	require.NoError(t, err)
   168  	require.Nil(t, value)
   169  
   170  	err = child.Set(childRegisterId1, childValue1)
   171  	require.NoError(t, err)
   172  
   173  	childSnapshot := child.Finalize()
   174  	require.Equal(
   175  		t,
   176  		childSnapshot.ReadSet,
   177  		map[flow.RegisterID]struct{}{
   178  			baseRegisterId:    struct{}{},
   179  			parentRegisterId1: struct{}{},
   180  			childRegisterId2:  struct{}{},
   181  		})
   182  
   183  	require.Equal(
   184  		t,
   185  		childSnapshot.WriteSet,
   186  		map[flow.RegisterID]flow.RegisterValue{
   187  			childRegisterId1:  childValue1,
   188  			parentRegisterId3: updatedParentValue3,
   189  		})
   190  
   191  	// Finalize parent without merging child to see if they are independent.
   192  	parentSnapshot := parent.Finalize()
   193  	require.Equal(
   194  		t,
   195  		parentSnapshot.ReadSet,
   196  		map[flow.RegisterID]struct{}{
   197  			parentRegisterId2: struct{}{},
   198  		})
   199  
   200  	require.Equal(
   201  		t,
   202  		parentSnapshot.WriteSet,
   203  		map[flow.RegisterID]flow.RegisterValue{
   204  			parentRegisterId1: parentValue,
   205  			parentRegisterId3: originalParentValue3,
   206  		})
   207  
   208  	// Merge the child snapshot and check again
   209  	err = parent.Merge(childSnapshot)
   210  	require.NoError(t, err)
   211  
   212  	parentSnapshot = parent.Finalize()
   213  	require.Equal(
   214  		t,
   215  		parentSnapshot.ReadSet,
   216  		map[flow.RegisterID]struct{}{
   217  			// from parent's state
   218  			parentRegisterId2: struct{}{},
   219  
   220  			// from child's state (parentRegisterId1 is not included since
   221  			// that value is read from the write set)
   222  			baseRegisterId:   struct{}{},
   223  			childRegisterId2: struct{}{},
   224  		})
   225  
   226  	require.Equal(
   227  		t,
   228  		parentSnapshot.WriteSet,
   229  		map[flow.RegisterID]flow.RegisterValue{
   230  			// from parent's state (parentRegisterId3 is overwritten by child)
   231  			parentRegisterId1: parentValue,
   232  
   233  			// from parent's state
   234  			childRegisterId1:  childValue1,
   235  			parentRegisterId3: updatedParentValue3,
   236  		})
   237  }