2019-08-20 15:38:40 +00:00
|
|
|
package accounts
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2023-07-16 11:11:48 +00:00
|
|
|
"encoding/json"
|
2024-03-27 13:58:51 +00:00
|
|
|
"fmt"
|
2019-08-20 15:38:40 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2019-07-25 05:35:09 +00:00
|
|
|
"github.com/status-im/status-go/appdatabase"
|
2019-12-11 13:59:37 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2023-06-02 15:06:51 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts/common"
|
2023-07-16 11:11:48 +00:00
|
|
|
"github.com/status-im/status-go/multiaccounts/settings"
|
|
|
|
"github.com/status-im/status-go/params"
|
2023-08-11 11:28:45 +00:00
|
|
|
"github.com/status-im/status-go/t/helpers"
|
2019-12-27 09:58:25 +00:00
|
|
|
)
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
func setupTestDB(t *testing.T) (*Database, func()) {
|
2023-08-11 11:28:45 +00:00
|
|
|
db, stop, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "settings-tests-")
|
2019-08-20 15:38:40 +00:00
|
|
|
require.NoError(t, err)
|
2022-03-23 18:47:00 +00:00
|
|
|
d, err := NewDB(db)
|
2019-12-27 09:58:25 +00:00
|
|
|
require.NoError(t, err)
|
2023-08-11 11:28:45 +00:00
|
|
|
return d, func() { require.NoError(t, stop()) }
|
2019-08-08 07:31:24 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
func TestGetAddresses(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2022-05-18 10:42:51 +00:00
|
|
|
accounts := []*Account{
|
2019-12-11 13:59:37 +00:00
|
|
|
{Address: types.Address{0x01}, Chat: true, Wallet: true},
|
|
|
|
{Address: types.Address{0x02}},
|
2019-08-20 15:38:40 +00:00
|
|
|
}
|
2023-06-28 19:45:36 +00:00
|
|
|
require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
|
2019-08-20 15:38:40 +00:00
|
|
|
addresses, err := db.GetAddresses()
|
|
|
|
require.NoError(t, err)
|
2019-12-11 13:59:37 +00:00
|
|
|
require.Equal(t, []types.Address{{0x01}, {0x02}}, addresses)
|
2019-08-20 15:38:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-16 11:11:48 +00:00
|
|
|
func TestMoveWalletAccount(t *testing.T) {
|
2023-06-20 11:35:22 +00:00
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2023-07-16 11:11:48 +00:00
|
|
|
|
|
|
|
networks := json.RawMessage("{}")
|
|
|
|
setting := settings.Settings{
|
|
|
|
Networks: &networks,
|
|
|
|
}
|
|
|
|
config := params.NodeConfig{}
|
|
|
|
err := db.CreateSettings(setting, config)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-06-20 11:35:22 +00:00
|
|
|
accounts := []*Account{
|
2023-07-16 11:11:48 +00:00
|
|
|
{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 0},
|
|
|
|
{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 1},
|
|
|
|
{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 2},
|
|
|
|
{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 3},
|
|
|
|
{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 4},
|
|
|
|
{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 5},
|
2023-06-20 11:35:22 +00:00
|
|
|
}
|
2023-06-28 19:45:36 +00:00
|
|
|
require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err := db.GetActiveAccounts()
|
2023-07-16 11:11:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, dbAccounts, len(accounts))
|
|
|
|
for i := 0; i < len(accounts); i++ {
|
|
|
|
require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
|
|
|
|
}
|
|
|
|
|
|
|
|
clock := uint64(1000)
|
|
|
|
err = db.MoveWalletAccount(-1, 4, clock)
|
|
|
|
require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
|
|
|
|
err = db.MoveWalletAccount(4, -1, clock)
|
|
|
|
require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
|
|
|
|
err = db.MoveWalletAccount(4, 4, clock)
|
|
|
|
require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
|
|
|
|
|
|
|
|
// Move down account from position 1 to position 4
|
|
|
|
err = db.MoveWalletAccount(1, 4, clock)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Expected after moving down
|
|
|
|
accounts = []*Account{
|
|
|
|
{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 0},
|
|
|
|
{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 1},
|
|
|
|
{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 2},
|
|
|
|
{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 3},
|
|
|
|
{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 4}, // acc with addr 0x02 is at position 4 (moved from position 1)
|
|
|
|
{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 5},
|
|
|
|
}
|
|
|
|
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-07-16 11:11:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < len(accounts); i++ {
|
|
|
|
require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check clock
|
|
|
|
dbClock, err := db.GetClockOfLastAccountsPositionChange()
|
2023-06-20 11:35:22 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-16 11:11:48 +00:00
|
|
|
require.Equal(t, clock, dbClock)
|
2023-06-20 11:35:22 +00:00
|
|
|
|
2023-07-16 11:11:48 +00:00
|
|
|
// Move up account from position 5 to position 0
|
|
|
|
clock = 2000
|
|
|
|
err = db.MoveWalletAccount(5, 0, clock)
|
2023-06-20 11:35:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-07-16 11:11:48 +00:00
|
|
|
// Expected after moving up
|
|
|
|
accounts = []*Account{
|
|
|
|
{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 0}, // acc with addr 0x06 is at position 0 (moved from position 5)
|
|
|
|
{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 1},
|
|
|
|
{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 2},
|
|
|
|
{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 3},
|
|
|
|
{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 4},
|
|
|
|
{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 5},
|
|
|
|
}
|
|
|
|
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-07-16 11:11:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < len(accounts); i++ {
|
|
|
|
require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check clock
|
|
|
|
dbClock, err = db.GetClockOfLastAccountsPositionChange()
|
2023-06-20 11:35:22 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-16 11:11:48 +00:00
|
|
|
require.Equal(t, clock, dbClock)
|
2023-06-20 11:35:22 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
func TestGetWalletAddress(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2019-12-11 13:59:37 +00:00
|
|
|
address := types.Address{0x01}
|
2019-08-20 15:38:40 +00:00
|
|
|
_, err := db.GetWalletAddress()
|
|
|
|
require.Equal(t, err, sql.ErrNoRows)
|
2023-06-28 19:45:36 +00:00
|
|
|
require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Wallet: true}}, false))
|
2019-08-20 15:38:40 +00:00
|
|
|
wallet, err := db.GetWalletAddress()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, address, wallet)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetChatAddress(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2019-12-11 13:59:37 +00:00
|
|
|
address := types.Address{0x01}
|
2019-08-20 15:38:40 +00:00
|
|
|
_, err := db.GetChatAddress()
|
|
|
|
require.Equal(t, err, sql.ErrNoRows)
|
2023-06-28 19:45:36 +00:00
|
|
|
require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Chat: true}}, false))
|
2019-08-20 15:38:40 +00:00
|
|
|
chat, err := db.GetChatAddress()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, address, chat)
|
|
|
|
}
|
|
|
|
|
2019-08-29 08:06:22 +00:00
|
|
|
func TestAddressExists(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
|
|
|
|
2022-05-18 10:42:51 +00:00
|
|
|
accounts := []*Account{
|
2019-12-11 13:59:37 +00:00
|
|
|
{Address: types.Address{0x01}, Chat: true, Wallet: true},
|
2019-08-29 08:06:22 +00:00
|
|
|
}
|
2023-06-28 19:45:36 +00:00
|
|
|
require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
|
2019-08-29 08:06:22 +00:00
|
|
|
|
|
|
|
exists, err := db.AddressExists(accounts[0].Address)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, exists)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAddressDoesntExist(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2019-12-11 13:59:37 +00:00
|
|
|
exists, err := db.AddressExists(types.Address{1, 1, 1})
|
2019-08-29 08:06:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, exists)
|
|
|
|
}
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
func TestWatchOnlyAccounts(t *testing.T) {
|
2023-03-20 07:33:08 +00:00
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// check the db
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err := db.GetActiveAccounts()
|
2023-03-20 07:33:08 +00:00
|
|
|
require.NoError(t, err)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.Equal(t, 0, len(dbAccounts))
|
|
|
|
|
|
|
|
woAccounts := GetWatchOnlyAccountsForTest()
|
|
|
|
|
|
|
|
// try to save keypair with watch only accounts
|
|
|
|
kp := &Keypair{}
|
|
|
|
kp.Accounts = append(kp.Accounts, woAccounts...)
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// check the db after that trying to save keypair with watch only accounts
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-03-20 07:33:08 +00:00
|
|
|
require.NoError(t, err)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.Equal(t, 0, len(dbAccounts))
|
|
|
|
|
|
|
|
// save watch only accounts
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts(woAccounts, false)
|
2023-03-20 07:33:08 +00:00
|
|
|
require.NoError(t, err)
|
2023-05-16 10:50:04 +00:00
|
|
|
_, err = db.GetKeypairByKeyUID(woAccounts[0].KeyUID)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(woAccounts), len(dbAccounts))
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, woAccounts[0].Address, dbAccounts[0].Address)
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// try to save the same watch only account again
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts(woAccounts[:1], false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(woAccounts), len(dbAccounts))
|
|
|
|
dbAcc, err := db.GetAccountByAddress(woAccounts[:1][0].Address)
|
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, woAccounts[:1][0].Address, dbAcc.Address)
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// try to save new watch only account
|
|
|
|
wo4 := &Account{
|
|
|
|
Address: types.Address{0x14},
|
|
|
|
Type: AccountTypeWatch,
|
|
|
|
Name: "WatchOnlyAcc4",
|
2023-06-02 15:06:51 +00:00
|
|
|
ColorID: common.CustomizationColorPrimary,
|
2023-05-16 10:50:04 +00:00
|
|
|
Emoji: "emoji-1",
|
2023-03-20 07:33:08 +00:00
|
|
|
}
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{wo4}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(woAccounts)+1, len(dbAccounts))
|
|
|
|
dbAcc, err = db.GetAccountByAddress(wo4.Address)
|
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, wo4.Address, dbAcc.Address)
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// updated watch onl to save the same account after it's saved
|
2024-01-18 18:54:54 +00:00
|
|
|
wo4.Name = wo4.Name + "updated"
|
2023-06-02 15:06:51 +00:00
|
|
|
wo4.ColorID = common.CustomizationColorCamel
|
2024-01-18 18:54:54 +00:00
|
|
|
wo4.Emoji = wo4.Emoji + "updated"
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{wo4}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(woAccounts)+1, len(dbAccounts))
|
|
|
|
dbAcc, err = db.GetAccountByAddress(wo4.Address)
|
2023-03-20 07:33:08 +00:00
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, wo4.Address, dbAcc.Address)
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// try to delete keypair for watch only account
|
2023-07-20 15:00:39 +00:00
|
|
|
err = db.RemoveKeypair(wo4.KeyUID, 0)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
|
|
|
|
|
|
|
// try to delete watch only account
|
2023-07-20 15:00:39 +00:00
|
|
|
err = db.RemoveAccount(wo4.Address, 0)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-03-20 07:33:08 +00:00
|
|
|
require.NoError(t, err)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.Equal(t, len(woAccounts), len(dbAccounts))
|
|
|
|
_, err = db.GetAccountByAddress(wo4.Address)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbAccountNotFound)
|
|
|
|
}
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-24 14:42:31 +00:00
|
|
|
func TestUpdateKeypairName(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
|
|
|
|
|
|
|
kp := GetProfileKeypairForTest(true, false, false)
|
|
|
|
|
|
|
|
// check the db
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err := db.GetActiveAccounts()
|
2023-05-24 14:42:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dbAccounts))
|
|
|
|
|
|
|
|
// save keypair
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbKeypairs, err := db.GetActiveKeypairs()
|
2023-05-24 14:42:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dbKeypairs))
|
|
|
|
require.True(t, SameKeypairs(kp, dbKeypairs[0]))
|
|
|
|
|
|
|
|
// update keypair name
|
2024-01-18 18:54:54 +00:00
|
|
|
kp.Name = kp.Name + "updated"
|
2023-06-28 19:45:36 +00:00
|
|
|
kp.Accounts[0].Name = kp.Name
|
|
|
|
err = db.UpdateKeypairName(kp.KeyUID, kp.Name, kp.Clock, true)
|
2023-05-24 14:42:31 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// check keypair
|
|
|
|
dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
|
|
|
|
require.True(t, SameKeypairs(kp, dbKp))
|
|
|
|
}
|
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
func TestKeypairs(t *testing.T) {
|
|
|
|
keypairs := []*Keypair{
|
2023-05-24 14:40:40 +00:00
|
|
|
GetProfileKeypairForTest(true, true, true),
|
2023-05-16 10:50:04 +00:00
|
|
|
GetSeedImportedKeypair1ForTest(),
|
|
|
|
GetPrivKeyImportedKeypairForTest(), // in this context (when testing db functions) there is not limitations for private key imported keypair
|
2023-03-20 07:33:08 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
for _, kp := range keypairs {
|
|
|
|
t.Run("test keypair "+kp.Name, func(t *testing.T) {
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
2023-03-20 07:33:08 +00:00
|
|
|
|
2023-05-16 10:50:04 +00:00
|
|
|
// check the db
|
2023-07-25 15:17:17 +00:00
|
|
|
dbKeypairs, err := db.GetActiveKeypairs()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dbKeypairs))
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err := db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(dbAccounts))
|
|
|
|
|
|
|
|
expectedLastUsedDerivationIndex := uint64(len(kp.Accounts) - 1)
|
|
|
|
if kp.Type == KeypairTypeProfile {
|
|
|
|
expectedLastUsedDerivationIndex-- // subtract one more in case of profile keypair because of chat account
|
|
|
|
}
|
|
|
|
|
|
|
|
// save keypair
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbKeypairs, err = db.GetActiveKeypairs()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dbKeypairs))
|
|
|
|
dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
|
|
|
|
kp.LastUsedDerivationIndex = expectedLastUsedDerivationIndex
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, kp.KeyUID, dbKp.KeyUID)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbAccounts))
|
|
|
|
|
|
|
|
// delete keypair
|
2023-07-20 15:00:39 +00:00
|
|
|
err = db.RemoveKeypair(kp.KeyUID, 0)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
_, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
|
|
|
|
|
|
|
// save keypair again to test the flow below
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbKeypairs, err = db.GetActiveKeypairs()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dbKeypairs))
|
|
|
|
|
|
|
|
ind := len(kp.Accounts) - 1
|
|
|
|
accToUpdate := kp.Accounts[ind]
|
|
|
|
|
|
|
|
// try to save the same account again
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, kp.KeyUID, dbKp.KeyUID)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbAccounts))
|
|
|
|
|
|
|
|
// update an existing account
|
2024-01-18 18:54:54 +00:00
|
|
|
accToUpdate.Name = accToUpdate.Name + "updated"
|
2023-06-02 15:06:51 +00:00
|
|
|
accToUpdate.ColorID = common.CustomizationColorBrown
|
2024-01-18 18:54:54 +00:00
|
|
|
accToUpdate.Emoji = accToUpdate.Emoji + "updated"
|
2023-05-16 10:50:04 +00:00
|
|
|
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbAccounts))
|
|
|
|
dbAcc, err := db.GetAccountByAddress(accToUpdate.Address)
|
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, accToUpdate.Address, dbAcc.Address)
|
2023-05-16 10:50:04 +00:00
|
|
|
|
|
|
|
// update keypair name
|
|
|
|
kpToUpdate := kp
|
|
|
|
kpToUpdate.Name = kpToUpdate.Name + "updated"
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbKeypairs, err = db.GetActiveKeypairs()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(dbKeypairs))
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, kpToUpdate.KeyUID, dbKp.KeyUID)
|
2023-05-16 10:50:04 +00:00
|
|
|
|
|
|
|
// save new account to an existing keypair which is out of the default Status' derivation root path
|
|
|
|
accToAdd := kp.Accounts[ind]
|
|
|
|
accToAdd.Address = types.Address{0x08}
|
|
|
|
accToAdd.Path = "m/44'/60'/0'/0/10"
|
|
|
|
accToAdd.PublicKey = types.Hex2Bytes("0x000000008")
|
|
|
|
accToAdd.Name = "Generated Acc 8"
|
|
|
|
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{accToAdd}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts)+1, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, kp.LastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts)+1, len(dbAccounts))
|
|
|
|
dbAcc, err = db.GetAccountByAddress(accToUpdate.Address)
|
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, accToAdd.Address, dbAcc.Address)
|
2023-05-16 10:50:04 +00:00
|
|
|
|
|
|
|
// save new account to an existing keypair which follows Status' default derivation root path
|
|
|
|
accToAdd = kp.Accounts[ind]
|
|
|
|
accToAdd.Address = types.Address{0x09}
|
|
|
|
accToAdd.Path = "m/44'/60'/0'/0/3"
|
|
|
|
accToAdd.PublicKey = types.Hex2Bytes("0x000000009")
|
|
|
|
accToAdd.Name = "Generated Acc 9"
|
|
|
|
|
|
|
|
expectedLastUsedDerivationIndex = 3
|
|
|
|
if kp.Type == KeypairTypeSeed {
|
|
|
|
accToAdd.Path = "m/44'/60'/0'/0/2"
|
|
|
|
expectedLastUsedDerivationIndex = 2
|
|
|
|
} else if kp.Type == KeypairTypeKey {
|
|
|
|
accToAdd.Path = "m/44'/60'/0'/0/1"
|
|
|
|
expectedLastUsedDerivationIndex = 1
|
|
|
|
}
|
|
|
|
|
2023-06-28 19:45:36 +00:00
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{accToAdd}, false)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts)+2, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts)+2, len(dbAccounts))
|
|
|
|
dbAcc, err = db.GetAccountByAddress(accToUpdate.Address)
|
|
|
|
require.NoError(t, err)
|
2023-06-02 07:38:06 +00:00
|
|
|
require.Equal(t, accToAdd.Address, dbAcc.Address)
|
2023-05-16 10:50:04 +00:00
|
|
|
|
|
|
|
// delete account
|
2023-07-20 15:00:39 +00:00
|
|
|
err = db.RemoveAccount(accToAdd.Address, 0)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
2023-07-25 15:17:17 +00:00
|
|
|
dbAccounts, err = db.GetActiveAccounts()
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(kp.Accounts)+1, len(dbAccounts))
|
|
|
|
_, err = db.GetAccountByAddress(accToAdd.Address)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbAccountNotFound)
|
|
|
|
|
|
|
|
for _, acc := range dbAccounts {
|
2023-07-20 15:00:39 +00:00
|
|
|
err = db.RemoveAccount(acc.Address, 0)
|
2023-05-16 10:50:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
|
|
|
})
|
|
|
|
}
|
2023-03-20 07:33:08 +00:00
|
|
|
}
|
2024-03-27 13:58:51 +00:00
|
|
|
|
|
|
|
func TestResolvingSuggestedDerivationPath(t *testing.T) {
|
|
|
|
kp := GetProfileKeypairForTest(true, true, true)
|
|
|
|
totalNumOfAccounts := len(kp.Accounts)
|
|
|
|
|
|
|
|
db, stop := setupTestDB(t)
|
|
|
|
defer stop()
|
|
|
|
|
|
|
|
// check the db
|
|
|
|
dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
|
|
|
require.Nil(t, dbKp)
|
|
|
|
|
|
|
|
expectedLastUsedDerivationIndex := uint64(2)
|
|
|
|
|
|
|
|
// save keypair
|
|
|
|
err = db.SaveOrUpdateKeypair(kp)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
// check number of addresses to generate
|
|
|
|
numOfAddresses, err := db.GetNumOfAddressesToGenerateForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, maxNumOfGeneratedAddresses, numOfAddresses)
|
|
|
|
|
|
|
|
// check suggested path
|
|
|
|
suggestedPath, err := db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
|
|
|
|
|
|
|
|
// prepare new account with the next suggested path
|
|
|
|
generatedWalletAccountThatWillBeRemovedLater := &Account{
|
|
|
|
Address: types.Address{0x05},
|
|
|
|
KeyUID: kp.KeyUID,
|
|
|
|
Wallet: false,
|
|
|
|
Chat: false,
|
|
|
|
Type: AccountTypeGenerated,
|
|
|
|
Path: suggestedPath,
|
|
|
|
PublicKey: types.Hex2Bytes("0x000000005"),
|
|
|
|
Name: "Generated Acc 4",
|
|
|
|
Emoji: "emoji-4",
|
|
|
|
ColorID: common.CustomizationColorPrimary,
|
|
|
|
Hidden: false,
|
|
|
|
Clock: 0,
|
|
|
|
Removed: false,
|
|
|
|
Operable: AccountFullyOperable,
|
|
|
|
ProdPreferredChainIDs: "1",
|
|
|
|
TestPreferredChainIDs: "5",
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new account with the next suggested path
|
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccountThatWillBeRemovedLater}, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
totalNumOfAccounts++
|
|
|
|
expectedLastUsedDerivationIndex++
|
|
|
|
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
// check suggested path
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
|
|
|
|
|
|
|
|
customSuggestedPath := fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1+1)
|
|
|
|
|
|
|
|
// prepare new account with the custom suggested path
|
|
|
|
generatedWalletAccount := &Account{
|
|
|
|
Address: types.Address{0x07},
|
|
|
|
KeyUID: kp.KeyUID,
|
|
|
|
Wallet: false,
|
|
|
|
Chat: false,
|
|
|
|
Type: AccountTypeGenerated,
|
|
|
|
Path: customSuggestedPath,
|
|
|
|
PublicKey: types.Hex2Bytes("0x000000007"),
|
|
|
|
Name: "Generated Acc 6",
|
|
|
|
Emoji: "emoji-6",
|
|
|
|
ColorID: common.CustomizationColorPrimary,
|
|
|
|
Hidden: false,
|
|
|
|
Clock: 0,
|
|
|
|
Removed: false,
|
|
|
|
Operable: AccountFullyOperable,
|
|
|
|
ProdPreferredChainIDs: "1",
|
|
|
|
TestPreferredChainIDs: "5",
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new account with the next suggested path
|
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
totalNumOfAccounts++
|
|
|
|
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
// check suggested path
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
|
|
|
|
|
|
|
|
// prepare new account with the next suggested path
|
|
|
|
generatedWalletAccount = &Account{
|
|
|
|
Address: types.Address{0x06},
|
|
|
|
KeyUID: kp.KeyUID,
|
|
|
|
Wallet: false,
|
|
|
|
Chat: false,
|
|
|
|
Type: AccountTypeGenerated,
|
|
|
|
Path: suggestedPath,
|
|
|
|
PublicKey: types.Hex2Bytes("0x000000006"),
|
|
|
|
Name: "Generated Acc 5",
|
|
|
|
Emoji: "emoji-5",
|
|
|
|
ColorID: common.CustomizationColorPrimary,
|
|
|
|
Hidden: false,
|
|
|
|
Clock: 0,
|
|
|
|
Removed: false,
|
|
|
|
Operable: AccountFullyOperable,
|
|
|
|
ProdPreferredChainIDs: "1",
|
|
|
|
TestPreferredChainIDs: "5",
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new account with the next suggested path
|
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
totalNumOfAccounts++
|
|
|
|
expectedLastUsedDerivationIndex++
|
|
|
|
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
// check suggested path
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+2), suggestedPath)
|
|
|
|
|
|
|
|
// prepare new account with the next suggested path
|
|
|
|
generatedWalletAccount = &Account{
|
|
|
|
Address: types.Address{0x08},
|
|
|
|
KeyUID: kp.KeyUID,
|
|
|
|
Wallet: false,
|
|
|
|
Chat: false,
|
|
|
|
Type: AccountTypeGenerated,
|
|
|
|
Path: suggestedPath,
|
|
|
|
PublicKey: types.Hex2Bytes("0x000000008"),
|
|
|
|
Name: "Generated Acc 7",
|
|
|
|
Emoji: "emoji-7",
|
|
|
|
ColorID: common.CustomizationColorPrimary,
|
|
|
|
Hidden: false,
|
|
|
|
Clock: 0,
|
|
|
|
Removed: false,
|
|
|
|
Operable: AccountFullyOperable,
|
|
|
|
ProdPreferredChainIDs: "1",
|
|
|
|
TestPreferredChainIDs: "5",
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new account with the next suggested path
|
|
|
|
err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
totalNumOfAccounts++
|
|
|
|
expectedLastUsedDerivationIndex += 2
|
|
|
|
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
// check suggested path
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
|
|
|
|
|
|
|
|
// remove account
|
|
|
|
err = db.RemoveAccount(generatedWalletAccountThatWillBeRemovedLater.Address, 0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
totalNumOfAccounts--
|
|
|
|
|
|
|
|
dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
|
|
|
|
require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
|
|
|
|
|
|
|
|
_, err = db.GetAccountByAddress(generatedWalletAccountThatWillBeRemovedLater.Address)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbAccountNotFound)
|
|
|
|
|
|
|
|
// check suggested path after removing account
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
|
2024-10-02 13:49:45 +00:00
|
|
|
|
|
|
|
// remove kaypair
|
|
|
|
err = db.RemoveKeypair(kp.KeyUID, 0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
_, err = db.GetKeypairByKeyUID(kp.KeyUID)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.True(t, err == ErrDbKeypairNotFound)
|
|
|
|
|
|
|
|
// check suggested path after removing keypair when adding the same keypair again
|
|
|
|
suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, 0), suggestedPath)
|
2024-03-27 13:58:51 +00:00
|
|
|
}
|