status-go/geth/api/backend_accounts_test.go

382 lines
17 KiB
Go

package api_test
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/les"
"github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params"
. "github.com/status-im/status-go/geth/testing"
)
func (s *BackendTestSuite) TestAccountsList() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
defer s.StopTestBackend()
runningNode, err := s.backend.NodeManager().Node()
require.NoError(err)
require.NotNil(runningNode)
var lesService *les.LightEthereum
require.NoError(runningNode.Service(&lesService))
require.NotNil(lesService)
accounts := lesService.StatusBackend.AccountManager().Accounts()
for _, acc := range accounts {
fmt.Println(acc.Hex())
}
// make sure that we start with empty accounts list (nobody has logged in yet)
require.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)
require.NoError(err)
// ensure that there is still no accounts returned
accounts = lesService.StatusBackend.AccountManager().Accounts()
require.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)
require.NoError(err, "account selection failed")
// at this point main account should show up
accounts = lesService.StatusBackend.AccountManager().Accounts()
require.Equal(1, len(accounts), "exactly single account is expected (main account)")
require.Equal(string(accounts[0].Hex()), "0x"+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)
require.NoError(err, "cannot create sub-account")
// now we expect to see both main account and sub-account 1
accounts = lesService.StatusBackend.AccountManager().Accounts()
require.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)")
require.Equal(string(accounts[0].Hex()), "0x"+address, "main account is not retured as the first key")
require.Equal(string(accounts[1].Hex()), "0x"+subAccount1, "subAcount1 not returned")
// create sub-account 2, index automatically progresses
subAccount2, subPubKey2, err := s.backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
require.NoError(err, "cannot create sub-account")
require.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 = lesService.StatusBackend.AccountManager().Accounts()
require.Equal(3, len(accounts), "unexpected number of accounts")
require.Equal(string(accounts[0].Hex()), "0x"+address, "main account is not retured as the first key")
subAccount1MatchesKey1 := string(accounts[1].Hex()) != "0x"+subAccount1
subAccount1MatchesKey2 := string(accounts[2].Hex()) != "0x"+subAccount1
require.False(!subAccount1MatchesKey1 && !subAccount1MatchesKey2, "subAcount1 not returned")
subAccount2MatchesKey1 := string(accounts[1].Hex()) != "0x"+subAccount2
subAccount2MatchesKey2 := string(accounts[2].Hex()) != "0x"+subAccount2
require.False(!subAccount2MatchesKey1 && !subAccount2MatchesKey2, "subAcount2 not returned")
}
func (s *BackendTestSuite) TestCreateChildAccount() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
defer s.StopTestBackend()
keyStore, err := s.backend.NodeManager().AccountKeyStore()
require.NoError(err)
require.NotNil(keyStore)
// create an account
address, pubKey, mnemonic, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
account, err := common.ParseAccountString(address)
require.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(account, TestConfig.Account1.Password)
require.NoError(err, "can not obtain decrypted account key")
require.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)
require.EqualError(node.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)
require.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")
require.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)
require.NoError(err, "cannot create sub-account")
// make sure that sub-account index automatically progresses
subAccount2, subPubKey2, err := s.backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
require.NoError(err)
require.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)
require.NoError(err)
require.False(subAccount1 == subAccount3 || subPubKey1 == subPubKey3 || subAccount2 == subAccount3 || subPubKey2 == subPubKey3)
}
func (s *BackendTestSuite) TestRecoverAccount() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
defer s.StopTestBackend()
keyStore, err := s.backend.NodeManager().AccountKeyStore()
require.NoError(err)
require.NotNil(keyStore)
// create an account
address, pubKey, mnemonic, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.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)
require.NoError(err, "recover account failed")
require.False(address != addressCheck || pubKey != pubKeyCheck, "incorrect accound details recovered")
// now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device
account, err := common.ParseAccountString(address)
require.NoError(err, "can not get account from address")
account, key, err := keyStore.AccountDecryptedKey(account, TestConfig.Account1.Password)
require.NoError(err, "can not obtain decrypted account key")
extChild2String := key.ExtendedKey.String()
require.NoError(keyStore.Delete(account, TestConfig.Account1.Password), "cannot remove account")
addressCheck, pubKeyCheck, err = s.backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
require.NoError(err, "recover account failed (for non-cached account)")
require.False(address != addressCheck || pubKey != pubKeyCheck,
"incorrect account details recovered (for non-cached account)")
// make sure that extended key exists and is imported ok too
_, key, err = keyStore.AccountDecryptedKey(account, TestConfig.Account1.Password)
require.NoError(err)
require.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)
require.NoError(err, "recover account failed (for non-cached account)")
require.False(address != addressCheck || pubKey != pubKeyCheck,
"incorrect account details recovered (for non-cached account)")
// time to login with recovered data
whisperService := s.WhisperService()
// make sure that identity is not (yet injected)
require.False(whisperService.HasKeyPair(pubKeyCheck), "identity already present in whisper")
require.NoError(s.backend.AccountManager().SelectAccount(addressCheck, TestConfig.Account1.Password))
require.True(whisperService.HasKeyPair(pubKeyCheck), "identity not injected into whisper")
}
func (s *BackendTestSuite) TestSelectAccount() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
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)
require.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s}", address1, pubKey1)
address2, pubKey2, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s}", address2, pubKey2)
// make sure that identity is not (yet injected)
require.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")
require.EqualError(expectedErr, err.Error(), "select account is expected to throw error: wrong password used")
err = s.backend.AccountManager().SelectAccount(address1, TestConfig.Account1.Password)
require.NoError(err)
require.True(whisperService.HasKeyPair(pubKey1), "identity not injected into whisper")
// select another account, make sure that previous account is wiped out from Whisper cache
require.False(whisperService.HasKeyPair(pubKey2), "identity already present in whisper")
require.NoError(s.backend.AccountManager().SelectAccount(address2, TestConfig.Account1.Password))
require.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
require.False(whisperService.HasKeyPair(pubKey1), "identity should be removed, but it is still present in whisper")
}
func (s *BackendTestSuite) TestLogout() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
defer s.StopTestBackend()
whisperService := s.WhisperService()
// create an account
address, pubKey, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err)
// make sure that identity doesn't exist (yet) in Whisper
require.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper")
require.NoError(s.backend.AccountManager().SelectAccount(address, TestConfig.Account1.Password))
require.True(whisperService.HasKeyPair(pubKey), "identity not injected into whisper")
require.NoError(s.backend.AccountManager().Logout())
require.False(whisperService.HasKeyPair(pubKey), "identity not cleared from whisper")
}
func (s *BackendTestSuite) TestSelectedAccountOnRestart() {
require := s.Require()
require.NotNil(s.backend)
s.StartTestBackend(params.RinkebyNetworkID)
// 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)
require.NoError(err)
address2, pubKey2, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err)
// make sure that identity is not (yet injected)
require.False(whisperService.HasKeyPair(pubKey1), "identity already present in whisper")
// make sure that no account is selected by default
selectedAccount, err := s.backend.AccountManager().SelectedAccount()
require.EqualError(node.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
require.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")
require.EqualError(expectedErr, err.Error())
require.NoError(s.backend.AccountManager().SelectAccount(address1, TestConfig.Account1.Password))
require.True(whisperService.HasKeyPair(pubKey1), "identity not injected into whisper")
// select another account, make sure that previous account is wiped out from Whisper cache
require.False(whisperService.HasKeyPair(pubKey2), "identity already present in whisper")
require.NoError(s.backend.AccountManager().SelectAccount(address2, TestConfig.Account1.Password))
require.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
require.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()
require.NoError(err)
require.NotNil(nodeConfig)
preservedNodeConfig := *nodeConfig
nodeStoped, err := s.backend.StopNode()
require.NoError(err)
<-nodeStoped
// make sure that account is still selected
selectedAccount, err = s.backend.AccountManager().SelectedAccount()
require.NoError(err)
require.NotNil(selectedAccount)
require.Equal(selectedAccount.Address.Hex(), "0x"+address2, "incorrect address selected")
// resume node
nodeStarted, err := s.backend.StartNode(&preservedNodeConfig)
require.NoError(err)
<-nodeStarted
// re-check selected account (account2 MUST be selected)
selectedAccount, err = s.backend.AccountManager().SelectedAccount()
require.NoError(err)
require.NotNil(selectedAccount)
require.Equal(selectedAccount.Address.Hex(), "0x"+address2, "incorrect address selected")
// make sure that Whisper gets identity re-injected
whisperService = s.WhisperService()
require.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
require.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()
require.True(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
require.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)
require.NoError(s.backend.AccountManager().Logout())
s.RestartTestNode()
whisperService = s.WhisperService()
require.False(whisperService.HasKeyPair(pubKey2), "identity not injected into whisper")
require.False(whisperService.HasKeyPair(pubKey1), "identity should not be present, but it is still present in whisper")
selectedAccount, err = s.backend.AccountManager().SelectedAccount()
require.EqualError(node.ErrNoAccountSelected, err.Error())
require.Nil(selectedAccount)
}
func (s *BackendTestSuite) TestRPCEthAccounts() {
require := s.Require()
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
// log into test account
err := s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
require.NoError(err)
rpcClient := s.backend.NodeManager().RPCClient()
expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + TestConfig.Account1.Address + `"]}`
resp := rpcClient.CallRaw(`{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_accounts",
"params": []
}`)
require.Equal(expectedResponse, resp)
}
func (s *BackendTestSuite) TestRPCEthAccountsWithUpstream() {
require := s.Require()
s.StartTestBackend(params.RopstenNetworkID, WithUpstream("https://ropsten.infura.io/z6GCTmjdP3FETEJmMBI4"))
defer s.StopTestBackend()
// log into test account
err := s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
require.NoError(err)
rpcClient := s.backend.NodeManager().RPCClient()
expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + TestConfig.Account1.Address + `"]}`
resp := rpcClient.CallRaw(`{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_accounts",
"params": []
}`)
require.Equal(expectedResponse, resp)
}