github.com/status-im/status-go@v1.1.0/services/wallet/saved_addresses_test.go (about) 1 package wallet 2 3 import ( 4 "strconv" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/require" 9 10 "github.com/ethereum/go-ethereum/common" 11 multiAccCommon "github.com/status-im/status-go/multiaccounts/common" 12 "github.com/status-im/status-go/t/helpers" 13 "github.com/status-im/status-go/walletdatabase" 14 ) 15 16 const ( 17 ensMember int = iota 18 isTestMember 19 addressMember 20 ) 21 22 func setupTestSavedAddressesDB(t *testing.T) (*SavedAddressesManager, func()) { 23 db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{}) 24 require.NoError(t, err) 25 26 return &SavedAddressesManager{db}, func() { 27 require.NoError(t, db.Close()) 28 } 29 } 30 31 func TestSavedAddressesAdd(t *testing.T) { 32 manager, stop := setupTestSavedAddressesDB(t) 33 defer stop() 34 35 rst, err := manager.GetRawSavedAddresses() 36 require.NoError(t, err) 37 require.Nil(t, rst) 38 39 sa := SavedAddress{ 40 Address: common.Address{1}, 41 Name: "Zilliqa", 42 ChainShortNames: "eth:arb1:", 43 ENSName: "test.stateofus.eth", 44 ColorID: multiAccCommon.CustomizationColorGreen, 45 IsTest: false, 46 } 47 48 err = manager.UpdateMetadataAndUpsertSavedAddress(sa) 49 require.NoError(t, err) 50 51 rst, err = manager.GetRawSavedAddresses() 52 require.NoError(t, err) 53 require.Equal(t, 1, len(rst)) 54 require.Equal(t, sa.Address, rst[0].Address) 55 require.Equal(t, sa.Name, rst[0].Name) 56 require.Equal(t, sa.ChainShortNames, rst[0].ChainShortNames) 57 require.Equal(t, sa.ENSName, rst[0].ENSName) 58 require.Equal(t, sa.ColorID, rst[0].ColorID) 59 require.Equal(t, sa.IsTest, rst[0].IsTest) 60 } 61 62 func contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool { 63 for _, e := range container { 64 if isEqual(e, element) { 65 return true 66 } 67 } 68 return false 69 } 70 71 func haveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool { 72 for _, v := range a { 73 if !contains(b, v, isEqual) { 74 return false 75 } 76 } 77 return true 78 } 79 80 func savedAddressDataIsEqual(a, b *SavedAddress) bool { 81 return a.Address == b.Address && a.Name == b.Name && a.ChainShortNames == b.ChainShortNames && 82 a.ENSName == b.ENSName && a.IsTest == b.IsTest && a.ColorID == b.ColorID 83 } 84 85 func TestSavedAddressesMetadata(t *testing.T) { 86 manager, stop := setupTestSavedAddressesDB(t) 87 defer stop() 88 89 savedAddresses, err := manager.GetRawSavedAddresses() 90 require.NoError(t, err) 91 require.Nil(t, savedAddresses) 92 93 // Add raw saved addresses 94 sa1 := SavedAddress{ 95 Address: common.Address{1}, 96 Name: "Raw", 97 savedAddressMeta: savedAddressMeta{ 98 UpdateClock: 234, 99 }, 100 ChainShortNames: "eth:arb1:", 101 ENSName: "test.stateofus.eth", 102 ColorID: multiAccCommon.CustomizationColorGreen, 103 IsTest: false, 104 } 105 106 err = manager.upsertSavedAddress(sa1, nil) 107 require.NoError(t, err) 108 109 dbSavedAddresses, err := manager.GetRawSavedAddresses() 110 require.NoError(t, err) 111 require.Equal(t, 1, len(dbSavedAddresses)) 112 require.Equal(t, sa1.Address, dbSavedAddresses[0].Address) 113 114 // Add simple saved address without sync metadata 115 sa2 := SavedAddress{ 116 Address: common.Address{2}, 117 Name: "Simple", 118 ColorID: multiAccCommon.CustomizationColorBlue, 119 IsTest: false, 120 savedAddressMeta: savedAddressMeta{ 121 UpdateClock: 42, 122 }, 123 } 124 125 err = manager.UpdateMetadataAndUpsertSavedAddress(sa2) 126 require.NoError(t, err) 127 128 dbSavedAddresses, err = manager.GetRawSavedAddresses() 129 require.NoError(t, err) 130 require.Equal(t, 2, len(dbSavedAddresses)) 131 // The order is not guaranteed check raw entry to decide 132 rawIndex := 0 133 simpleIndex := 1 134 if dbSavedAddresses[0].Address == sa1.Address { 135 rawIndex = 1 136 simpleIndex = 0 137 } 138 require.Equal(t, sa1.Address, dbSavedAddresses[simpleIndex].Address) 139 require.Equal(t, sa2.Address, dbSavedAddresses[rawIndex].Address) 140 require.Equal(t, sa2.Name, dbSavedAddresses[rawIndex].Name) 141 require.Equal(t, sa2.ColorID, dbSavedAddresses[rawIndex].ColorID) 142 require.Equal(t, sa2.IsTest, dbSavedAddresses[rawIndex].IsTest) 143 144 // Check the default values 145 require.False(t, dbSavedAddresses[rawIndex].Removed) 146 require.Equal(t, dbSavedAddresses[rawIndex].UpdateClock, sa2.UpdateClock) 147 require.Greater(t, dbSavedAddresses[rawIndex].UpdateClock, uint64(0)) 148 149 sa2Older := sa2 150 sa2Older.IsTest = false 151 sa2Older.UpdateClock = dbSavedAddresses[rawIndex].UpdateClock - 1 152 153 sa2Newer := sa2 154 sa2Newer.IsTest = false 155 sa2Newer.UpdateClock = dbSavedAddresses[rawIndex].UpdateClock + 1 156 157 // Try to add an older entry 158 updated := false 159 updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Older) 160 require.NoError(t, err) 161 require.False(t, updated) 162 163 dbSavedAddresses, err = manager.GetRawSavedAddresses() 164 require.NoError(t, err) 165 166 rawIndex = 0 167 simpleIndex = 1 168 if dbSavedAddresses[0].Address == sa1.Address { 169 rawIndex = 1 170 simpleIndex = 0 171 } 172 173 require.Equal(t, 2, len(dbSavedAddresses)) 174 require.True(t, haveSameElements([]*SavedAddress{&sa1, &sa2}, dbSavedAddresses, savedAddressDataIsEqual)) 175 require.Equal(t, sa1.savedAddressMeta, dbSavedAddresses[simpleIndex].savedAddressMeta) 176 177 // Try to update sa2 with a newer entry 178 updatedClock := dbSavedAddresses[rawIndex].UpdateClock + 1 179 updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Newer) 180 require.NoError(t, err) 181 require.True(t, updated) 182 183 dbSavedAddresses, err = manager.GetRawSavedAddresses() 184 require.NoError(t, err) 185 186 require.Equal(t, 2, len(dbSavedAddresses)) 187 require.True(t, haveSameElements([]*SavedAddress{&sa1, &sa2Newer}, dbSavedAddresses, savedAddressDataIsEqual)) 188 require.Equal(t, updatedClock, dbSavedAddresses[rawIndex].UpdateClock) 189 190 // Try to delete the sa2 newer entry 191 updatedDeleteClock := updatedClock + 1 192 updated, err = manager.DeleteSavedAddress(sa2Newer.Address, sa2Newer.IsTest, updatedDeleteClock) 193 require.NoError(t, err) 194 require.True(t, updated) 195 196 dbSavedAddresses, err = manager.GetRawSavedAddresses() 197 require.NoError(t, err) 198 199 require.Equal(t, 2, len(dbSavedAddresses)) 200 require.True(t, dbSavedAddresses[rawIndex].Removed) 201 202 // Check that deleted entry is not returned with the regular API (non-raw) 203 dbSavedAddresses, err = manager.GetSavedAddresses() 204 require.NoError(t, err) 205 require.Equal(t, 1, len(dbSavedAddresses)) 206 } 207 208 func TestSavedAddressesCleanSoftDeletes(t *testing.T) { 209 manager, stop := setupTestSavedAddressesDB(t) 210 defer stop() 211 212 firstTimestamp := 10 213 for i := 0; i < 5; i++ { 214 sa := SavedAddress{ 215 Address: common.Address{byte(i)}, 216 Name: "Test" + strconv.Itoa(i), 217 ColorID: multiAccCommon.CustomizationColorGreen, 218 Removed: true, 219 savedAddressMeta: savedAddressMeta{ 220 UpdateClock: uint64(firstTimestamp + i), 221 }, 222 } 223 224 err := manager.upsertSavedAddress(sa, nil) 225 require.NoError(t, err) 226 } 227 228 err := manager.DeleteSoftRemovedSavedAddresses(uint64(firstTimestamp + 3)) 229 require.NoError(t, err) 230 231 dbSavedAddresses, err := manager.GetRawSavedAddresses() 232 require.NoError(t, err) 233 require.Equal(t, 2, len(dbSavedAddresses)) 234 require.True(t, haveSameElements([]uint64{dbSavedAddresses[0].UpdateClock, 235 dbSavedAddresses[1].UpdateClock}, []uint64{uint64(firstTimestamp + 3), uint64(firstTimestamp + 4)}, 236 func(a, b uint64) bool { 237 return a == b 238 }, 239 )) 240 } 241 242 func TestSavedAddressesGet(t *testing.T) { 243 manager, stop := setupTestSavedAddressesDB(t) 244 defer stop() 245 246 sa := SavedAddress{ 247 Address: common.Address{1}, 248 ENSName: "test.ens.eth", 249 ColorID: multiAccCommon.CustomizationColorGreen, 250 IsTest: false, 251 Removed: true, 252 } 253 254 err := manager.upsertSavedAddress(sa, nil) 255 require.NoError(t, err) 256 257 dbSavedAddresses, err := manager.GetRawSavedAddresses() 258 require.NoError(t, err) 259 require.Equal(t, 1, len(dbSavedAddresses)) 260 261 require.True(t, savedAddressDataIsEqual(&sa, dbSavedAddresses[0])) 262 263 dbSavedAddresses, err = manager.GetSavedAddresses() 264 require.NoError(t, err) 265 require.Equal(t, 0, len(dbSavedAddresses)) 266 } 267 268 func TestSavedAddressesDelete(t *testing.T) { 269 manager, stop := setupTestSavedAddressesDB(t) 270 defer stop() 271 272 sa0 := SavedAddress{ 273 Address: common.Address{1}, 274 IsTest: false, 275 } 276 277 err := manager.upsertSavedAddress(sa0, nil) 278 require.NoError(t, err) 279 280 rst, err := manager.GetRawSavedAddresses() 281 require.NoError(t, err) 282 require.Equal(t, 1, len(rst)) 283 284 require.True(t, savedAddressDataIsEqual(&sa0, rst[0])) 285 286 // Modify IsTest flag, insert 287 sa1 := sa0 288 sa1.IsTest = !sa1.IsTest 289 290 err = manager.upsertSavedAddress(sa1, nil) 291 require.NoError(t, err) 292 293 // Delete s0, test that only s1 is left 294 updateClock := uint64(time.Now().Unix()) 295 _, err = manager.DeleteSavedAddress(sa0.Address, sa0.IsTest, updateClock) 296 require.NoError(t, err) 297 298 rst, err = manager.GetSavedAddresses() 299 require.NoError(t, err) 300 require.Equal(t, 1, len(rst)) 301 require.True(t, savedAddressDataIsEqual(&sa1, rst[0])) 302 303 // Test that we still have both addresses 304 rst, err = manager.GetRawSavedAddresses() 305 require.NoError(t, err) 306 require.Equal(t, 2, len(rst)) 307 308 // Delete s0 one more time with the same timestamp 309 deleted, err := manager.DeleteSavedAddress(sa0.Address, sa0.IsTest, updateClock) 310 require.NoError(t, err) 311 require.False(t, deleted) 312 } 313 314 func testInsertSameAddressWithOneChange(t *testing.T, member int) { 315 manager, stop := setupTestSavedAddressesDB(t) 316 defer stop() 317 318 // Insert one address 319 sa := SavedAddress{ 320 Address: common.Address{1}, 321 ENSName: "test.ens.eth", 322 IsTest: true, 323 } 324 325 err := manager.upsertSavedAddress(sa, nil) 326 require.NoError(t, err) 327 328 rst, err := manager.GetRawSavedAddresses() 329 require.NoError(t, err) 330 require.Equal(t, 1, len(rst)) 331 332 require.True(t, savedAddressDataIsEqual(&sa, rst[0])) 333 334 sa2 := sa 335 336 if member == isTestMember { 337 sa2.IsTest = !sa2.IsTest 338 } else if member == addressMember { 339 sa2.Address = common.Address{7} 340 } else if member == ensMember { 341 sa2.ENSName += "_" 342 } else { 343 t.Error("Unsupported member change. Please add it to the list") 344 } 345 346 err = manager.upsertSavedAddress(sa2, nil) 347 require.NoError(t, err) 348 349 rst, err = manager.GetRawSavedAddresses() 350 require.NoError(t, err) 351 require.Equal(t, 2, len(rst)) 352 353 // The order of records returned by GetRawSavedAddresses is not 354 // guaranteed to be the same as insertions, so swap indices if first record does not match 355 firstIndex := 0 356 secondIndex := 1 357 if rst[firstIndex].Address == sa.Address { 358 firstIndex = 1 359 secondIndex = 0 360 } 361 require.True(t, savedAddressDataIsEqual(&sa, rst[firstIndex])) 362 require.True(t, savedAddressDataIsEqual(&sa2, rst[secondIndex])) 363 } 364 365 func TestSavedAddressesAddDifferentIsTest(t *testing.T) { 366 testInsertSameAddressWithOneChange(t, isTestMember) 367 } 368 369 func TestSavedAddressesAddSame(t *testing.T) { 370 manager, stop := setupTestSavedAddressesDB(t) 371 defer stop() 372 373 // Insert one address 374 sa := SavedAddress{ 375 Address: common.Address{1}, 376 ENSName: "test.ens.eth", 377 IsTest: true, 378 } 379 380 err := manager.upsertSavedAddress(sa, nil) 381 require.NoError(t, err) 382 383 rst, err := manager.GetRawSavedAddresses() 384 require.NoError(t, err) 385 require.Equal(t, 1, len(rst)) 386 387 require.True(t, savedAddressDataIsEqual(&sa, rst[0])) 388 389 sa2 := sa 390 err = manager.upsertSavedAddress(sa2, nil) 391 require.NoError(t, err) 392 393 rst, err = manager.GetRawSavedAddresses() 394 require.NoError(t, err) 395 require.Equal(t, 1, len(rst)) 396 } 397 398 func TestSavedAddressesPerTestnetMode(t *testing.T) { 399 manager, stop := setupTestSavedAddressesDB(t) 400 defer stop() 401 402 addresses := []SavedAddress{ 403 SavedAddress{ 404 Address: common.Address{1}, 405 Name: "addr1", 406 IsTest: true, 407 }, 408 SavedAddress{ 409 Address: common.Address{2}, 410 Name: "addr2", 411 IsTest: false, 412 }, 413 SavedAddress{ 414 Address: common.Address{3}, 415 Name: "addr3", 416 IsTest: true, 417 }, 418 SavedAddress{ 419 Address: common.Address{4}, 420 Name: "addr4", 421 IsTest: false, 422 }, 423 SavedAddress{ 424 Address: common.Address{5}, 425 Name: "addr5", 426 IsTest: true, 427 Removed: true, 428 }, 429 SavedAddress{ 430 Address: common.Address{6}, 431 Name: "addr6", 432 IsTest: false, 433 Removed: true, 434 }, 435 SavedAddress{ 436 Address: common.Address{7}, 437 Name: "addr7", 438 IsTest: true, 439 }, 440 } 441 442 for _, sa := range addresses { 443 err := manager.upsertSavedAddress(sa, nil) 444 require.NoError(t, err) 445 } 446 447 res, err := manager.GetSavedAddresses() 448 require.NoError(t, err) 449 require.Equal(t, len(res), len(addresses)-2) 450 451 res, err = manager.GetSavedAddressesPerMode(true) 452 require.NoError(t, err) 453 require.Equal(t, len(res), 3) 454 455 res, err = manager.GetSavedAddressesPerMode(false) 456 require.NoError(t, err) 457 require.Equal(t, len(res), 2) 458 } 459 460 func TestSavedAddressesCapacity(t *testing.T) { 461 manager, stop := setupTestSavedAddressesDB(t) 462 defer stop() 463 464 addresses := []SavedAddress{ 465 SavedAddress{ 466 Address: common.Address{1}, 467 Name: "addr1", 468 IsTest: true, 469 }, 470 SavedAddress{ 471 Address: common.Address{2}, 472 Name: "addr2", 473 IsTest: false, 474 }, 475 SavedAddress{ 476 Address: common.Address{3}, 477 Name: "addr3", 478 IsTest: true, 479 }, 480 SavedAddress{ 481 Address: common.Address{4}, 482 Name: "addr4", 483 IsTest: false, 484 }, 485 SavedAddress{ 486 Address: common.Address{5}, 487 Name: "addr5", 488 IsTest: true, 489 Removed: true, 490 }, 491 SavedAddress{ 492 Address: common.Address{6}, 493 Name: "addr6", 494 IsTest: false, 495 Removed: true, 496 }, 497 SavedAddress{ 498 Address: common.Address{7}, 499 Name: "addr7", 500 IsTest: true, 501 }, 502 } 503 504 for _, sa := range addresses { 505 err := manager.upsertSavedAddress(sa, nil) 506 require.NoError(t, err) 507 } 508 509 capacity, err := manager.RemainingCapacityForSavedAddresses(true) 510 require.NoError(t, err) 511 require.Equal(t, 17, capacity) 512 513 capacity, err = manager.RemainingCapacityForSavedAddresses(false) 514 require.NoError(t, err) 515 require.Equal(t, 18, capacity) 516 517 // add 17 more for testnet and 18 more for mainnet mode 518 for i := 1; i < 36; i++ { 519 sa := SavedAddress{ 520 Address: common.Address{byte(i + 8)}, 521 Name: "addr" + strconv.Itoa(i+8), 522 IsTest: i%2 == 0, 523 } 524 525 err := manager.upsertSavedAddress(sa, nil) 526 require.NoError(t, err) 527 } 528 529 capacity, err = manager.RemainingCapacityForSavedAddresses(true) 530 require.Error(t, err) 531 require.Equal(t, "no more save addresses can be added", err.Error()) 532 require.Equal(t, 0, capacity) 533 534 capacity, err = manager.RemainingCapacityForSavedAddresses(false) 535 require.Error(t, err) 536 require.Equal(t, "no more save addresses can be added", err.Error()) 537 require.Equal(t, 0, capacity) 538 }