539 lines
14 KiB
Go
539 lines
14 KiB
Go
package wallet
|
|
|
|
import (
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
multiAccCommon "github.com/status-im/status-go/multiaccounts/common"
|
|
"github.com/status-im/status-go/t/helpers"
|
|
"github.com/status-im/status-go/walletdatabase"
|
|
)
|
|
|
|
const (
|
|
ensMember int = iota
|
|
isTestMember
|
|
addressMember
|
|
)
|
|
|
|
func setupTestSavedAddressesDB(t *testing.T) (*SavedAddressesManager, func()) {
|
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
|
require.NoError(t, err)
|
|
|
|
return &SavedAddressesManager{db}, func() {
|
|
require.NoError(t, db.Close())
|
|
}
|
|
}
|
|
|
|
func TestSavedAddressesAdd(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
rst, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Nil(t, rst)
|
|
|
|
sa := SavedAddress{
|
|
Address: common.Address{1},
|
|
Name: "Zilliqa",
|
|
ChainShortNames: "eth:arb1:",
|
|
ENSName: "test.stateofus.eth",
|
|
ColorID: multiAccCommon.CustomizationColorGreen,
|
|
IsTest: false,
|
|
}
|
|
|
|
err = manager.UpdateMetadataAndUpsertSavedAddress(sa)
|
|
require.NoError(t, err)
|
|
|
|
rst, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
require.Equal(t, sa.Address, rst[0].Address)
|
|
require.Equal(t, sa.Name, rst[0].Name)
|
|
require.Equal(t, sa.ChainShortNames, rst[0].ChainShortNames)
|
|
require.Equal(t, sa.ENSName, rst[0].ENSName)
|
|
require.Equal(t, sa.ColorID, rst[0].ColorID)
|
|
require.Equal(t, sa.IsTest, rst[0].IsTest)
|
|
}
|
|
|
|
func contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool {
|
|
for _, e := range container {
|
|
if isEqual(e, element) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func haveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool {
|
|
for _, v := range a {
|
|
if !contains(b, v, isEqual) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func savedAddressDataIsEqual(a, b *SavedAddress) bool {
|
|
return a.Address == b.Address && a.Name == b.Name && a.ChainShortNames == b.ChainShortNames &&
|
|
a.ENSName == b.ENSName && a.IsTest == b.IsTest && a.ColorID == b.ColorID
|
|
}
|
|
|
|
func TestSavedAddressesMetadata(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
savedAddresses, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Nil(t, savedAddresses)
|
|
|
|
// Add raw saved addresses
|
|
sa1 := SavedAddress{
|
|
Address: common.Address{1},
|
|
Name: "Raw",
|
|
savedAddressMeta: savedAddressMeta{
|
|
UpdateClock: 234,
|
|
},
|
|
ChainShortNames: "eth:arb1:",
|
|
ENSName: "test.stateofus.eth",
|
|
ColorID: multiAccCommon.CustomizationColorGreen,
|
|
IsTest: false,
|
|
}
|
|
|
|
err = manager.upsertSavedAddress(sa1, nil)
|
|
require.NoError(t, err)
|
|
|
|
dbSavedAddresses, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(dbSavedAddresses))
|
|
require.Equal(t, sa1.Address, dbSavedAddresses[0].Address)
|
|
|
|
// Add simple saved address without sync metadata
|
|
sa2 := SavedAddress{
|
|
Address: common.Address{2},
|
|
Name: "Simple",
|
|
ColorID: multiAccCommon.CustomizationColorBlue,
|
|
IsTest: false,
|
|
savedAddressMeta: savedAddressMeta{
|
|
UpdateClock: 42,
|
|
},
|
|
}
|
|
|
|
err = manager.UpdateMetadataAndUpsertSavedAddress(sa2)
|
|
require.NoError(t, err)
|
|
|
|
dbSavedAddresses, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(dbSavedAddresses))
|
|
// The order is not guaranteed check raw entry to decide
|
|
rawIndex := 0
|
|
simpleIndex := 1
|
|
if dbSavedAddresses[0].Address == sa1.Address {
|
|
rawIndex = 1
|
|
simpleIndex = 0
|
|
}
|
|
require.Equal(t, sa1.Address, dbSavedAddresses[simpleIndex].Address)
|
|
require.Equal(t, sa2.Address, dbSavedAddresses[rawIndex].Address)
|
|
require.Equal(t, sa2.Name, dbSavedAddresses[rawIndex].Name)
|
|
require.Equal(t, sa2.ColorID, dbSavedAddresses[rawIndex].ColorID)
|
|
require.Equal(t, sa2.IsTest, dbSavedAddresses[rawIndex].IsTest)
|
|
|
|
// Check the default values
|
|
require.False(t, dbSavedAddresses[rawIndex].Removed)
|
|
require.Equal(t, dbSavedAddresses[rawIndex].UpdateClock, sa2.UpdateClock)
|
|
require.Greater(t, dbSavedAddresses[rawIndex].UpdateClock, uint64(0))
|
|
|
|
sa2Older := sa2
|
|
sa2Older.IsTest = false
|
|
sa2Older.UpdateClock = dbSavedAddresses[rawIndex].UpdateClock - 1
|
|
|
|
sa2Newer := sa2
|
|
sa2Newer.IsTest = false
|
|
sa2Newer.UpdateClock = dbSavedAddresses[rawIndex].UpdateClock + 1
|
|
|
|
// Try to add an older entry
|
|
updated := false
|
|
updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Older)
|
|
require.NoError(t, err)
|
|
require.False(t, updated)
|
|
|
|
dbSavedAddresses, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
|
|
rawIndex = 0
|
|
simpleIndex = 1
|
|
if dbSavedAddresses[0].Address == sa1.Address {
|
|
rawIndex = 1
|
|
simpleIndex = 0
|
|
}
|
|
|
|
require.Equal(t, 2, len(dbSavedAddresses))
|
|
require.True(t, haveSameElements([]*SavedAddress{&sa1, &sa2}, dbSavedAddresses, savedAddressDataIsEqual))
|
|
require.Equal(t, sa1.savedAddressMeta, dbSavedAddresses[simpleIndex].savedAddressMeta)
|
|
|
|
// Try to update sa2 with a newer entry
|
|
updatedClock := dbSavedAddresses[rawIndex].UpdateClock + 1
|
|
updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Newer)
|
|
require.NoError(t, err)
|
|
require.True(t, updated)
|
|
|
|
dbSavedAddresses, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dbSavedAddresses))
|
|
require.True(t, haveSameElements([]*SavedAddress{&sa1, &sa2Newer}, dbSavedAddresses, savedAddressDataIsEqual))
|
|
require.Equal(t, updatedClock, dbSavedAddresses[rawIndex].UpdateClock)
|
|
|
|
// Try to delete the sa2 newer entry
|
|
updatedDeleteClock := updatedClock + 1
|
|
updated, err = manager.DeleteSavedAddress(sa2Newer.Address, sa2Newer.IsTest, updatedDeleteClock)
|
|
require.NoError(t, err)
|
|
require.True(t, updated)
|
|
|
|
dbSavedAddresses, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(dbSavedAddresses))
|
|
require.True(t, dbSavedAddresses[rawIndex].Removed)
|
|
|
|
// Check that deleted entry is not returned with the regular API (non-raw)
|
|
dbSavedAddresses, err = manager.GetSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(dbSavedAddresses))
|
|
}
|
|
|
|
func TestSavedAddressesCleanSoftDeletes(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
firstTimestamp := 10
|
|
for i := 0; i < 5; i++ {
|
|
sa := SavedAddress{
|
|
Address: common.Address{byte(i)},
|
|
Name: "Test" + strconv.Itoa(i),
|
|
ColorID: multiAccCommon.CustomizationColorGreen,
|
|
Removed: true,
|
|
savedAddressMeta: savedAddressMeta{
|
|
UpdateClock: uint64(firstTimestamp + i),
|
|
},
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err := manager.DeleteSoftRemovedSavedAddresses(uint64(firstTimestamp + 3))
|
|
require.NoError(t, err)
|
|
|
|
dbSavedAddresses, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(dbSavedAddresses))
|
|
require.True(t, haveSameElements([]uint64{dbSavedAddresses[0].UpdateClock,
|
|
dbSavedAddresses[1].UpdateClock}, []uint64{uint64(firstTimestamp + 3), uint64(firstTimestamp + 4)},
|
|
func(a, b uint64) bool {
|
|
return a == b
|
|
},
|
|
))
|
|
}
|
|
|
|
func TestSavedAddressesGet(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
sa := SavedAddress{
|
|
Address: common.Address{1},
|
|
ENSName: "test.ens.eth",
|
|
ColorID: multiAccCommon.CustomizationColorGreen,
|
|
IsTest: false,
|
|
Removed: true,
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
|
|
dbSavedAddresses, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(dbSavedAddresses))
|
|
|
|
require.True(t, savedAddressDataIsEqual(&sa, dbSavedAddresses[0]))
|
|
|
|
dbSavedAddresses, err = manager.GetSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(dbSavedAddresses))
|
|
}
|
|
|
|
func TestSavedAddressesDelete(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
sa0 := SavedAddress{
|
|
Address: common.Address{1},
|
|
IsTest: false,
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa0, nil)
|
|
require.NoError(t, err)
|
|
|
|
rst, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
|
|
require.True(t, savedAddressDataIsEqual(&sa0, rst[0]))
|
|
|
|
// Modify IsTest flag, insert
|
|
sa1 := sa0
|
|
sa1.IsTest = !sa1.IsTest
|
|
|
|
err = manager.upsertSavedAddress(sa1, nil)
|
|
require.NoError(t, err)
|
|
|
|
// Delete s0, test that only s1 is left
|
|
updateClock := uint64(time.Now().Unix())
|
|
_, err = manager.DeleteSavedAddress(sa0.Address, sa0.IsTest, updateClock)
|
|
require.NoError(t, err)
|
|
|
|
rst, err = manager.GetSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
require.True(t, savedAddressDataIsEqual(&sa1, rst[0]))
|
|
|
|
// Test that we still have both addresses
|
|
rst, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(rst))
|
|
|
|
// Delete s0 one more time with the same timestamp
|
|
deleted, err := manager.DeleteSavedAddress(sa0.Address, sa0.IsTest, updateClock)
|
|
require.NoError(t, err)
|
|
require.False(t, deleted)
|
|
}
|
|
|
|
func testInsertSameAddressWithOneChange(t *testing.T, member int) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
// Insert one address
|
|
sa := SavedAddress{
|
|
Address: common.Address{1},
|
|
ENSName: "test.ens.eth",
|
|
IsTest: true,
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
|
|
rst, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
|
|
require.True(t, savedAddressDataIsEqual(&sa, rst[0]))
|
|
|
|
sa2 := sa
|
|
|
|
if member == isTestMember {
|
|
sa2.IsTest = !sa2.IsTest
|
|
} else if member == addressMember {
|
|
sa2.Address = common.Address{7}
|
|
} else if member == ensMember {
|
|
sa2.ENSName += "_"
|
|
} else {
|
|
t.Error("Unsupported member change. Please add it to the list")
|
|
}
|
|
|
|
err = manager.upsertSavedAddress(sa2, nil)
|
|
require.NoError(t, err)
|
|
|
|
rst, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(rst))
|
|
|
|
// The order of records returned by GetRawSavedAddresses is not
|
|
// guaranteed to be the same as insertions, so swap indices if first record does not match
|
|
firstIndex := 0
|
|
secondIndex := 1
|
|
if rst[firstIndex].Address == sa.Address {
|
|
firstIndex = 1
|
|
secondIndex = 0
|
|
}
|
|
require.True(t, savedAddressDataIsEqual(&sa, rst[firstIndex]))
|
|
require.True(t, savedAddressDataIsEqual(&sa2, rst[secondIndex]))
|
|
}
|
|
|
|
func TestSavedAddressesAddDifferentIsTest(t *testing.T) {
|
|
testInsertSameAddressWithOneChange(t, isTestMember)
|
|
}
|
|
|
|
func TestSavedAddressesAddSame(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
// Insert one address
|
|
sa := SavedAddress{
|
|
Address: common.Address{1},
|
|
ENSName: "test.ens.eth",
|
|
IsTest: true,
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
|
|
rst, err := manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
|
|
require.True(t, savedAddressDataIsEqual(&sa, rst[0]))
|
|
|
|
sa2 := sa
|
|
err = manager.upsertSavedAddress(sa2, nil)
|
|
require.NoError(t, err)
|
|
|
|
rst, err = manager.GetRawSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(rst))
|
|
}
|
|
|
|
func TestSavedAddressesPerTestnetMode(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
addresses := []SavedAddress{
|
|
SavedAddress{
|
|
Address: common.Address{1},
|
|
Name: "addr1",
|
|
IsTest: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{2},
|
|
Name: "addr2",
|
|
IsTest: false,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{3},
|
|
Name: "addr3",
|
|
IsTest: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{4},
|
|
Name: "addr4",
|
|
IsTest: false,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{5},
|
|
Name: "addr5",
|
|
IsTest: true,
|
|
Removed: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{6},
|
|
Name: "addr6",
|
|
IsTest: false,
|
|
Removed: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{7},
|
|
Name: "addr7",
|
|
IsTest: true,
|
|
},
|
|
}
|
|
|
|
for _, sa := range addresses {
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
res, err := manager.GetSavedAddresses()
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(res), len(addresses)-2)
|
|
|
|
res, err = manager.GetSavedAddressesPerMode(true)
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(res), 3)
|
|
|
|
res, err = manager.GetSavedAddressesPerMode(false)
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(res), 2)
|
|
}
|
|
|
|
func TestSavedAddressesCapacity(t *testing.T) {
|
|
manager, stop := setupTestSavedAddressesDB(t)
|
|
defer stop()
|
|
|
|
addresses := []SavedAddress{
|
|
SavedAddress{
|
|
Address: common.Address{1},
|
|
Name: "addr1",
|
|
IsTest: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{2},
|
|
Name: "addr2",
|
|
IsTest: false,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{3},
|
|
Name: "addr3",
|
|
IsTest: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{4},
|
|
Name: "addr4",
|
|
IsTest: false,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{5},
|
|
Name: "addr5",
|
|
IsTest: true,
|
|
Removed: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{6},
|
|
Name: "addr6",
|
|
IsTest: false,
|
|
Removed: true,
|
|
},
|
|
SavedAddress{
|
|
Address: common.Address{7},
|
|
Name: "addr7",
|
|
IsTest: true,
|
|
},
|
|
}
|
|
|
|
for _, sa := range addresses {
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
capacity, err := manager.RemainingCapacityForSavedAddresses(true)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 17, capacity)
|
|
|
|
capacity, err = manager.RemainingCapacityForSavedAddresses(false)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 18, capacity)
|
|
|
|
// add 17 more for testnet and 18 more for mainnet mode
|
|
for i := 1; i < 36; i++ {
|
|
sa := SavedAddress{
|
|
Address: common.Address{byte(i + 8)},
|
|
Name: "addr" + strconv.Itoa(i+8),
|
|
IsTest: i%2 == 0,
|
|
}
|
|
|
|
err := manager.upsertSavedAddress(sa, nil)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
capacity, err = manager.RemainingCapacityForSavedAddresses(true)
|
|
require.Error(t, err)
|
|
require.Equal(t, "no more save addresses can be added", err.Error())
|
|
require.Equal(t, 0, capacity)
|
|
|
|
capacity, err = manager.RemainingCapacityForSavedAddresses(false)
|
|
require.Error(t, err)
|
|
require.Equal(t, "no more save addresses can be added", err.Error())
|
|
require.Equal(t, 0, capacity)
|
|
}
|