mirror of
https://github.com/status-im/status-go.git
synced 2025-01-10 06:36:32 +00:00
2d964bfe9f
The main goal of this change is to remove async operations from node manager. Additionally all of the signals from node manager are moved to status backend. All of the async operation now will have the following behaviour: - If node in the correct state exit immediatly without error - If node not in the correct state exit immediatly with error - In all other cases spawn a goroutine with wanted operation - All the progress regarding that operation will be reported by using signals - Signals should be handled in once place, which is StatusBackend There are 2 potentially breaking changes: - Empty event field will be ommited when Envelope is sent to a client - All errors will be delivered to a client as an Envelope, previously some errors (NodeExists, NoRunningNode) were delivered synchronously Signed-off-by: Dmitry Shulyak <yashulyak@gmail.com>
298 lines
13 KiB
Go
298 lines
13 KiB
Go
package accounts
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/status-im/status-go/geth/account"
|
|
"github.com/status-im/status-go/geth/common"
|
|
e2e "github.com/status-im/status-go/t/e2e"
|
|
. "github.com/status-im/status-go/t/utils"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
func TestAccountsTestSuite(t *testing.T) {
|
|
suite.Run(t, new(AccountsTestSuite))
|
|
}
|
|
|
|
type AccountsTestSuite struct {
|
|
e2e.BackendTestSuite
|
|
}
|
|
|
|
func (s *AccountsTestSuite) TestAccountsList() {
|
|
s.StartTestBackend()
|
|
defer s.StopTestBackend()
|
|
|
|
accounts, err := s.Backend.AccountManager().Accounts()
|
|
s.NoError(err)
|
|
|
|
// make sure that we start with empty accounts list (nobody has logged in yet)
|
|
s.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)")
|
|
|
|
// create an account
|
|
address, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
|
|
// ensure that there is still no accounts returned
|
|
accounts, err = s.Backend.AccountManager().Accounts()
|
|
s.NoError(err)
|
|
s.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)")
|
|
|
|
// select account (sub-accounts will be created for this key)
|
|
err = s.Backend.AccountManager().SelectAccount(address, TestConfig.Account1.Password)
|
|
s.NoError(err, "account selection failed")
|
|
|
|
// at this point main account should show up
|
|
accounts, err = s.Backend.AccountManager().Accounts()
|
|
s.NoError(err)
|
|
s.Equal(1, len(accounts), "exactly single account is expected (main account)")
|
|
s.Equal(string(accounts[0].Hex()), address,
|
|
fmt.Sprintf("main account is not retured as the first key: got %s, expected %s", accounts[0].Hex(), "0x"+address))
|
|
|
|
// create sub-account 1
|
|
subAccount1, subPubKey1, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
|
|
s.NoError(err, "cannot create sub-account")
|
|
|
|
// now we expect to see both main account and sub-account 1
|
|
accounts, err = s.Backend.AccountManager().Accounts()
|
|
s.NoError(err)
|
|
s.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)")
|
|
s.Equal(string(accounts[0].Hex()), address, "main account is not retured as the first key")
|
|
s.Equal(string(accounts[1].Hex()), subAccount1, "subAcount1 not returned")
|
|
|
|
// create sub-account 2, index automatically progresses
|
|
subAccount2, subPubKey2, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
|
|
s.NoError(err, "cannot create sub-account")
|
|
s.False(subAccount1 == subAccount2 || subPubKey1 == subPubKey2, "sub-account index auto-increament failed")
|
|
|
|
// finally, all 3 accounts should show up (main account, sub-accounts 1 and 2)
|
|
accounts, err = s.Backend.AccountManager().Accounts()
|
|
s.NoError(err)
|
|
s.Equal(3, len(accounts), "unexpected number of accounts")
|
|
s.Equal(string(accounts[0].Hex()), address, "main account is not retured as the first key")
|
|
|
|
subAccount1MatchesKey1 := string(accounts[1].Hex()) != "0x"+subAccount1
|
|
subAccount1MatchesKey2 := string(accounts[2].Hex()) != "0x"+subAccount1
|
|
s.False(!subAccount1MatchesKey1 && !subAccount1MatchesKey2, "subAcount1 not returned")
|
|
|
|
subAccount2MatchesKey1 := string(accounts[1].Hex()) != "0x"+subAccount2
|
|
subAccount2MatchesKey2 := string(accounts[2].Hex()) != "0x"+subAccount2
|
|
s.False(!subAccount2MatchesKey1 && !subAccount2MatchesKey2, "subAcount2 not returned")
|
|
}
|
|
|
|
func (s *AccountsTestSuite) TestCreateChildAccount() {
|
|
s.StartTestBackend()
|
|
defer s.StopTestBackend()
|
|
|
|
keyStore, err := s.Backend.NodeManager().AccountKeyStore()
|
|
s.NoError(err)
|
|
s.NotNil(keyStore)
|
|
|
|
// create an account
|
|
address, pubKey, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.T().Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
|
|
|
acct, err := common.ParseAccountString(address)
|
|
s.NoError(err, "can not get account from address")
|
|
|
|
// obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
|
|
_, key, err := keyStore.AccountDecryptedKey(acct, TestConfig.Account1.Password)
|
|
s.NoError(err, "can not obtain decrypted account key")
|
|
s.NotNil(key.ExtendedKey, "CKD#2 has not been generated for new account")
|
|
|
|
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
|
|
_, _, err = s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
|
|
s.EqualError(account.ErrNoAccountSelected, err.Error(), "expected error is not returned (tried to create sub-account w/o login)")
|
|
|
|
err = s.Backend.AccountManager().SelectAccount(address, TestConfig.Account1.Password)
|
|
s.NoError(err, "cannot select account")
|
|
|
|
// try to create sub-account with wrong password
|
|
_, _, err = s.Backend.AccountManager().CreateChildAccount("", "wrong password")
|
|
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase")
|
|
s.EqualError(expectedErr, err.Error(), "create sub-account with wrong password")
|
|
|
|
// create sub-account (from implicit parent)
|
|
subAccount1, subPubKey1, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
|
|
s.NoError(err, "cannot create sub-account")
|
|
|
|
// make sure that sub-account index automatically progresses
|
|
subAccount2, subPubKey2, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.False(subAccount1 == subAccount2 || subPubKey1 == subPubKey2, "sub-account index auto-increament failed")
|
|
|
|
// create sub-account (from explicit parent)
|
|
subAccount3, subPubKey3, err := s.Backend.AccountManager().CreateChildAccount(subAccount2, TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.False(subAccount1 == subAccount3 || subPubKey1 == subPubKey3 || subAccount2 == subAccount3 || subPubKey2 == subPubKey3)
|
|
}
|
|
|
|
func (s *AccountsTestSuite) TestRecoverAccount() {
|
|
s.StartTestBackend()
|
|
defer s.StopTestBackend()
|
|
|
|
keyStore, err := s.Backend.NodeManager().AccountKeyStore()
|
|
s.NoError(err)
|
|
|
|
// create an acc
|
|
address, pubKey, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.T().Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
|
|
|
|
// try recovering using password + mnemonic
|
|
addressCheck, pubKeyCheck, err := s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
|
|
s.NoError(err, "recover acc failed")
|
|
s.False(address != addressCheck || pubKey != pubKeyCheck, "incorrect accound details recovered")
|
|
|
|
// now test recovering, but make sure that acc/key file is removed i.e. simulate recovering on a new device
|
|
acc, err := common.ParseAccountString(address)
|
|
s.NoError(err, "can not get acc from address")
|
|
|
|
acc, key, err := keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password)
|
|
s.NoError(err, "can not obtain decrypted acc key")
|
|
extChild2String := key.ExtendedKey.String()
|
|
|
|
s.NoError(keyStore.Delete(acc, TestConfig.Account1.Password), "cannot remove acc")
|
|
|
|
addressCheck, pubKeyCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
|
|
s.NoError(err, "recover acc failed (for non-cached acc)")
|
|
s.False(address != addressCheck || pubKey != pubKeyCheck,
|
|
"incorrect acc details recovered (for non-cached acc)")
|
|
|
|
// make sure that extended key exists and is imported ok too
|
|
_, key, err = keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.Equal(extChild2String, key.ExtendedKey.String(), "CKD#2 key mismatch")
|
|
|
|
// make sure that calling import several times, just returns from cache (no error is expected)
|
|
addressCheck, pubKeyCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
|
|
s.NoError(err, "recover acc failed (for non-cached acc)")
|
|
s.False(address != addressCheck || pubKey != pubKeyCheck,
|
|
"incorrect acc details recovered (for non-cached acc)")
|
|
|
|
// time to login with recovered data
|
|
whisperService := s.WhisperService()
|
|
|
|
// make sure that identity is not (yet injected)
|
|
s.False(whisperService.HasKeyPair(pubKeyCheck), "identity already present in whisper")
|
|
s.NoError(s.Backend.AccountManager().SelectAccount(addressCheck, TestConfig.Account1.Password))
|
|
s.True(whisperService.HasKeyPair(pubKeyCheck), "identity not injected into whisper")
|
|
}
|
|
|
|
func (s *AccountsTestSuite) TestSelectAccount() {
|
|
s.StartTestBackend()
|
|
defer s.StopTestBackend()
|
|
|
|
// test to see if the account was injected in whisper
|
|
whisperService := s.WhisperService()
|
|
|
|
// create an account
|
|
address1, pubKey1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.T().Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
|
|
|
|
address2, pubKey2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.T().Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
|
|
|
|
// make sure that identity is not (yet injected)
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity already present in whisper")
|
|
|
|
// try selecting with wrong password
|
|
err = s.Backend.AccountManager().SelectAccount(address1, "wrongPassword")
|
|
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase")
|
|
s.EqualError(expectedErr, err.Error(), "select account is expected to throw error: wrong password used")
|
|
|
|
err = s.Backend.AccountManager().SelectAccount(address1, TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
s.True(whisperService.HasKeyPair(pubKey1), "identity not injected into whisper")
|
|
|
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
|
s.False(whisperService.HasKeyPair(pubKey2), "identity already present in whisper")
|
|
s.NoError(s.Backend.AccountManager().SelectAccount(address2, TestConfig.Account1.Password))
|
|
s.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity should be removed, but it is still present in whisper")
|
|
}
|
|
|
|
func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
|
|
s.StartTestBackend()
|
|
|
|
// we need to make sure that selected account is injected as identity into Whisper
|
|
whisperService := s.WhisperService()
|
|
|
|
// create test accounts
|
|
address1, pubKey1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
address2, pubKey2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
|
s.NoError(err)
|
|
|
|
// make sure that identity is not (yet injected)
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity already present in whisper")
|
|
|
|
// make sure that no account is selected by default
|
|
selectedAccount, err := s.Backend.AccountManager().SelectedAccount()
|
|
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
|
|
s.Nil(selectedAccount)
|
|
|
|
// select account
|
|
err = s.Backend.AccountManager().SelectAccount(address1, "wrongPassword")
|
|
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase")
|
|
s.EqualError(expectedErr, err.Error())
|
|
|
|
s.NoError(s.Backend.AccountManager().SelectAccount(address1, TestConfig.Account1.Password))
|
|
s.True(whisperService.HasKeyPair(pubKey1), "identity not injected into whisper")
|
|
|
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
|
s.False(whisperService.HasKeyPair(pubKey2), "identity already present in whisper")
|
|
s.NoError(s.Backend.AccountManager().SelectAccount(address2, TestConfig.Account1.Password))
|
|
s.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity should be removed, but it is still present in whisper")
|
|
|
|
// stop node (and all of its sub-protocols)
|
|
nodeConfig, err := s.Backend.NodeManager().NodeConfig()
|
|
s.NoError(err)
|
|
preservedNodeConfig := *nodeConfig
|
|
s.NoError(s.Backend.StopNode())
|
|
|
|
// make sure that account is still selected
|
|
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
|
s.NoError(err)
|
|
s.NotNil(selectedAccount)
|
|
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected")
|
|
|
|
// resume node
|
|
s.NoError(s.Backend.StartNode(&preservedNodeConfig))
|
|
|
|
// re-check selected account (account2 MUST be selected)
|
|
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
|
s.NoError(err)
|
|
s.NotNil(selectedAccount)
|
|
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected")
|
|
|
|
// make sure that Whisper gets identity re-injected
|
|
whisperService = s.WhisperService()
|
|
s.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity should not be present, but it is still present in whisper")
|
|
|
|
// now restart node using RestartNode() method, and make sure that account is still available
|
|
s.RestartTestNode()
|
|
defer s.StopTestBackend()
|
|
|
|
whisperService = s.WhisperService()
|
|
s.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity should not be present, but it is still present in whisper")
|
|
|
|
// now logout, and make sure that on restart no account is selected (i.e. logout works properly)
|
|
s.NoError(s.Backend.AccountManager().Logout())
|
|
s.RestartTestNode()
|
|
whisperService = s.WhisperService()
|
|
s.False(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
|
|
s.False(whisperService.HasKeyPair(pubKey1), "identity should not be present, but it is still present in whisper")
|
|
|
|
selectedAccount, err = s.Backend.AccountManager().SelectedAccount()
|
|
s.EqualError(account.ErrNoAccountSelected, err.Error())
|
|
s.Nil(selectedAccount)
|
|
}
|