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  }