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 }