github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/storage/state/execution_state_test.go (about) 1 package state_test 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/onflow/flow-go/fvm/meter" 9 "github.com/onflow/flow-go/fvm/storage/state" 10 "github.com/onflow/flow-go/model/flow" 11 "github.com/onflow/flow-go/utils/unittest" 12 ) 13 14 func createByteArray(size int) []byte { 15 bytes := make([]byte, size) 16 for i := range bytes { 17 bytes[i] = 255 18 } 19 return bytes 20 } 21 22 func TestExecutionState_Finalize(t *testing.T) { 23 parent := state.NewExecutionState(nil, state.DefaultParameters()) 24 25 child := parent.NewChild() 26 27 readId := flow.NewRegisterID(unittest.RandomAddressFixture(), "x") 28 29 _, err := child.Get(readId) 30 require.NoError(t, err) 31 32 writeId := flow.NewRegisterID(unittest.RandomAddressFixture(), "y") 33 writeValue := flow.RegisterValue("a") 34 35 err = child.Set(writeId, writeValue) 36 require.NoError(t, err) 37 38 childSnapshot := child.Finalize() 39 40 require.Equal( 41 t, 42 map[flow.RegisterID]struct{}{ 43 readId: {}, 44 }, 45 childSnapshot.ReadSet) 46 47 require.Equal( 48 t, 49 map[flow.RegisterID]flow.RegisterValue{ 50 writeId: writeValue, 51 }, 52 childSnapshot.WriteSet) 53 54 require.NotNil(t, childSnapshot.SpockSecret) 55 require.NotNil(t, childSnapshot.Meter) 56 57 parentSnapshot := parent.Finalize() 58 // empty read / write set since child was not merged. 59 require.Empty(t, parentSnapshot.ReadSet) 60 require.Empty(t, parentSnapshot.WriteSet) 61 require.NotNil(t, parentSnapshot.SpockSecret) 62 require.NotNil(t, parentSnapshot.Meter) 63 64 } 65 66 func TestExecutionState_ChildMergeFunctionality(t *testing.T) { 67 st := state.NewExecutionState(nil, state.DefaultParameters()) 68 69 owner := unittest.RandomAddressFixture() 70 71 t.Run("test read from parent state (backoff)", func(t *testing.T) { 72 key := flow.NewRegisterID(owner, "key1") 73 value := createByteArray(1) 74 // set key1 on parent 75 err := st.Set(key, value) 76 require.NoError(t, err) 77 78 // read key1 on child 79 stChild := st.NewChild() 80 v, err := stChild.Get(key) 81 require.NoError(t, err) 82 require.Equal(t, v, value) 83 }) 84 85 t.Run("test write to child (no merge)", func(t *testing.T) { 86 key := flow.NewRegisterID(owner, "key2") 87 value := createByteArray(2) 88 stChild := st.NewChild() 89 90 // set key2 on child 91 err := stChild.Set(key, value) 92 require.NoError(t, err) 93 94 // read key2 on parent 95 v, err := st.Get(key) 96 require.NoError(t, err) 97 require.Equal(t, len(v), 0) 98 }) 99 100 t.Run("test write to child and merge", func(t *testing.T) { 101 key := flow.NewRegisterID(owner, "key3") 102 value := createByteArray(3) 103 stChild := st.NewChild() 104 105 // set key3 on child 106 err := stChild.Set(key, value) 107 require.NoError(t, err) 108 109 // read before merge 110 v, err := st.Get(key) 111 require.NoError(t, err) 112 require.Equal(t, len(v), 0) 113 114 // merge to parent 115 err = st.Merge(stChild.Finalize()) 116 require.NoError(t, err) 117 118 // read key3 on parent 119 v, err = st.Get(key) 120 require.NoError(t, err) 121 require.Equal(t, v, value) 122 }) 123 124 t.Run("test write to ledger", func(t *testing.T) { 125 key := flow.NewRegisterID(owner, "key4") 126 value := createByteArray(4) 127 // set key4 on parent 128 err := st.Set(key, value) 129 require.NoError(t, err) 130 131 // now should be part of the ledger 132 v, err := st.Get(key) 133 require.NoError(t, err) 134 require.Equal(t, v, value) 135 }) 136 137 } 138 139 func TestExecutionState_MaxValueSize(t *testing.T) { 140 st := state.NewExecutionState( 141 nil, 142 state.DefaultParameters().WithMaxValueSizeAllowed(6)) 143 144 key := flow.NewRegisterID(unittest.RandomAddressFixture(), "key") 145 146 // update should pass 147 value := createByteArray(5) 148 err := st.Set(key, value) 149 require.NoError(t, err) 150 151 // update shouldn't pass 152 value = createByteArray(7) 153 err = st.Set(key, value) 154 require.Error(t, err) 155 } 156 157 func TestExecutionState_MaxKeySize(t *testing.T) { 158 st := state.NewExecutionState( 159 nil, 160 // Note: owners are always 8 bytes 161 state.DefaultParameters().WithMaxKeySizeAllowed(8+2)) 162 163 key1 := flow.NewRegisterID(unittest.RandomAddressFixture(), "23") 164 key2 := flow.NewRegisterID(unittest.RandomAddressFixture(), "234") 165 166 // read 167 _, err := st.Get(key1) 168 require.NoError(t, err) 169 170 // read 171 _, err = st.Get(key2) 172 require.Error(t, err) 173 174 // update 175 err = st.Set(key1, []byte{}) 176 require.NoError(t, err) 177 178 // read 179 err = st.Set(key2, []byte{}) 180 require.Error(t, err) 181 182 } 183 184 func TestExecutionState_MaxInteraction(t *testing.T) { 185 key1 := flow.NewRegisterID(unittest.RandomAddressFixture(), "2") 186 key1Size := uint64(8 + 1) 187 188 value1 := []byte("A") 189 value1Size := uint64(1) 190 191 key2 := flow.NewRegisterID(unittest.RandomAddressFixture(), "23") 192 key2Size := uint64(8 + 2) 193 194 key3 := flow.NewRegisterID(unittest.RandomAddressFixture(), "345") 195 key3Size := uint64(8 + 3) 196 197 key4 := flow.NewRegisterID(unittest.RandomAddressFixture(), "4567") 198 key4Size := uint64(8 + 4) 199 200 st := state.NewExecutionState( 201 nil, 202 state.DefaultParameters(). 203 WithMeterParameters( 204 meter.DefaultParameters().WithStorageInteractionLimit( 205 key1Size+key2Size+key3Size-1))) 206 207 // read - interaction 2 208 _, err := st.Get(key1) 209 require.Equal(t, st.InteractionUsed(), key1Size) 210 require.NoError(t, err) 211 212 // read - interaction 8 213 _, err = st.Get(key2) 214 require.NoError(t, err) 215 require.Equal(t, st.InteractionUsed(), key1Size+key2Size) 216 217 // read - interaction 14 218 _, err = st.Get(key3) 219 require.Error(t, err) 220 require.Equal(t, st.InteractionUsed(), key1Size+key2Size+key3Size) 221 222 st = state.NewExecutionState( 223 nil, 224 state.DefaultParameters(). 225 WithMeterParameters( 226 meter.DefaultParameters().WithStorageInteractionLimit( 227 key1Size+value1Size+key2Size))) 228 stChild := st.NewChild() 229 230 // update - 0 231 err = stChild.Set(key1, value1) 232 require.NoError(t, err) 233 require.Equal(t, st.InteractionUsed(), uint64(0)) 234 235 // commit 236 err = st.Merge(stChild.Finalize()) 237 require.NoError(t, err) 238 require.Equal(t, st.InteractionUsed(), key1Size+value1Size) 239 240 // read - interaction 3 (already in read cache) 241 _, err = st.Get(key1) 242 require.NoError(t, err) 243 require.Equal(t, st.InteractionUsed(), key1Size+value1Size) 244 245 // read - interaction 5 246 _, err = st.Get(key2) 247 require.NoError(t, err) 248 require.Equal(t, st.InteractionUsed(), key1Size+value1Size+key2Size) 249 250 // read - interaction 7 251 _, err = st.Get(key4) 252 require.Error(t, err) 253 require.Equal( 254 t, 255 st.InteractionUsed(), 256 key1Size+value1Size+key2Size+key4Size) 257 }