Multi account login (#1525)

* multi-account login and signing

put methods count threshold back to 20

* validate login params

* refactoring

* use common.Address

* remove unused var in test
This commit is contained in:
Andrea Franz 2019-07-26 16:45:10 +02:00 committed by GitHub
parent 2b96aa5456
commit acfe9a721c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 346 additions and 642 deletions

View File

@ -32,6 +32,8 @@ var (
ErrOnboardingAccountNotFound = errors.New("cannot find onboarding account with the given id")
)
var zeroAddress = common.Address{}
// GethServiceProvider provides required geth services.
type GethServiceProvider interface {
AccountManager() (*accounts.Manager, error)
@ -47,8 +49,9 @@ type Manager struct {
accountsGenerator *generator.Generator
onboarding *Onboarding
selectedWalletAccount *SelectedExtKey // account that was processed during the last call to SelectAccount()
selectedChatAccount *SelectedExtKey // account that was processed during the last call to SelectAccount()
selectedChatAccount *SelectedExtKey // account that was processed during the last call to SelectAccount()
mainAccountAddress common.Address
watchAddresses []common.Address
}
// NewManager returns new node account manager.
@ -103,66 +106,6 @@ func (m *Manager) CreateAccount(password string) (Info, string, error) {
return info, mnemonic, nil
}
// CreateChildAccount creates sub-account for an account identified by parent address.
// CKD#2 is used as root for master accounts (when parentAddress is "").
// Otherwise (when parentAddress != ""), child is derived directly from parent.
func (m *Manager) CreateChildAccount(parentAddress, password string) (address, pubKey string, err error) {
m.mu.Lock()
defer m.mu.Unlock()
keyStore, err := m.geth.AccountKeyStore()
if err != nil {
return "", "", err
}
if parentAddress == "" && m.selectedWalletAccount != nil { // derive from selected account by default
parentAddress = m.selectedWalletAccount.Address.Hex()
}
if parentAddress == "" {
return "", "", ErrNoAccountSelected
}
account, err := ParseAccountString(parentAddress)
if err != nil {
return "", "", ErrAddressToAccountMappingFailure
}
// make sure that given password can decrypt key associated with a given parent address
account, accountKey, err := keyStore.AccountDecryptedKey(account, password)
if err != nil {
return "", "", fmt.Errorf("%s: %v", ErrAccountToKeyMappingFailure.Error(), err)
}
parentKey, err := extkeys.NewKeyFromString(accountKey.ExtendedKey.String())
if err != nil {
return "", "", err
}
// derive child key
childKey, err := parentKey.Child(accountKey.SubAccountIndex)
if err != nil {
return "", "", err
}
if err = keyStore.IncSubAccountIndex(account, password); err != nil {
return "", "", err
}
accountKey.SubAccountIndex++
// import derived key into account keystore
address, pubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, childKey, password)
if err != nil {
return
}
// update in-memory selected account
if m.selectedWalletAccount != nil {
m.selectedWalletAccount.AccountKey = accountKey
}
return address, pubKey, nil
}
// RecoverAccount re-creates master key using given details.
// Once master key is re-generated, it is inserted into keystore (if not already there).
func (m *Manager) RecoverAccount(password, mnemonic string) (Info, error) {
@ -246,23 +189,19 @@ func (m *Manager) VerifyAccountPassword(keyStoreDir, address, password string) (
// SelectAccount selects current account, by verifying that address has corresponding account which can be decrypted
// using provided password. Once verification is done, all previous identities are removed).
func (m *Manager) SelectAccount(walletAddress, chatAddress, password string) error {
func (m *Manager) SelectAccount(loginParams LoginParams) error {
m.mu.Lock()
defer m.mu.Unlock()
m.accountsGenerator.Reset()
selectedWalletAccount, err := m.unlockExtendedKey(walletAddress, password)
selectedChatAccount, err := m.unlockExtendedKey(loginParams.ChatAddress.String(), loginParams.Password)
if err != nil {
return err
}
selectedChatAccount, err := m.unlockExtendedKey(chatAddress, password)
if err != nil {
return err
}
m.selectedWalletAccount = selectedWalletAccount
m.watchAddresses = loginParams.WatchAddresses
m.mainAccountAddress = loginParams.MainAccount
m.selectedChatAccount = selectedChatAccount
return nil
@ -287,15 +226,24 @@ func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
}
}
// SelectedWalletAccount returns currently selected wallet account
func (m *Manager) SelectedWalletAccount() (*SelectedExtKey, error) {
// MainAccountAddress returns currently selected watch addresses.
func (m *Manager) MainAccountAddress() (common.Address, error) {
m.mu.RLock()
defer m.mu.RUnlock()
if m.selectedWalletAccount == nil {
return nil, ErrNoAccountSelected
if m.mainAccountAddress == zeroAddress {
return zeroAddress, ErrNoAccountSelected
}
return m.selectedWalletAccount, nil
return m.mainAccountAddress, nil
}
// WatchAddresses returns currently selected watch addresses.
func (m *Manager) WatchAddresses() []common.Address {
m.mu.RLock()
defer m.mu.RUnlock()
return m.watchAddresses
}
// SelectedChatAccount returns currently selected chat account
@ -309,13 +257,14 @@ func (m *Manager) SelectedChatAccount() (*SelectedExtKey, error) {
return m.selectedChatAccount, nil
}
// Logout clears selectedWalletAccount.
// Logout clears selected accounts.
func (m *Manager) Logout() {
m.mu.Lock()
defer m.mu.Unlock()
m.accountsGenerator.Reset()
m.selectedWalletAccount = nil
m.mainAccountAddress = zeroAddress
m.watchAddresses = nil
m.selectedChatAccount = nil
}
@ -387,40 +336,12 @@ func (m *Manager) Accounts() ([]gethcommon.Address, error) {
m.mu.RLock()
defer m.mu.RUnlock()
am, err := m.geth.AccountManager()
if err != nil {
return nil, err
addresses := make([]gethcommon.Address, 0)
if m.mainAccountAddress != zeroAddress {
addresses = append(addresses, m.mainAccountAddress)
}
var addresses []gethcommon.Address
for _, wallet := range am.Wallets() {
for _, account := range wallet.Accounts() {
addresses = append(addresses, account.Address)
}
}
if m.selectedWalletAccount == nil {
return []gethcommon.Address{}, nil
}
m.refreshSelectedWalletAccount()
filtered := make([]gethcommon.Address, 0)
for _, account := range addresses {
// main account
if m.selectedWalletAccount.Address.Hex() == account.Hex() {
filtered = append(filtered, account)
} else {
// sub accounts
for _, subAccount := range m.selectedWalletAccount.SubAccounts {
if subAccount.Address.Hex() == account.Hex() {
filtered = append(filtered, account)
}
}
}
}
return filtered, nil
return addresses, nil
}
// StartOnboarding starts the onboarding process generating accountsCount accounts and returns a slice of OnboardingAccount.
@ -472,63 +393,6 @@ func (m *Manager) ImportOnboardingAccount(id string, password string) (Info, str
return info, acc.mnemonic, nil
}
// refreshSelectedWalletAccount re-populates list of sub-accounts of the currently selected account (if any)
func (m *Manager) refreshSelectedWalletAccount() {
if m.selectedWalletAccount == nil {
return
}
accountKey := m.selectedWalletAccount.AccountKey
if accountKey == nil {
return
}
// re-populate list of sub-accounts
subAccounts, err := m.findSubAccounts(accountKey.ExtendedKey, accountKey.SubAccountIndex)
if err != nil {
return
}
m.selectedWalletAccount = &SelectedExtKey{
Address: m.selectedWalletAccount.Address,
AccountKey: m.selectedWalletAccount.AccountKey,
SubAccounts: subAccounts,
}
}
// findSubAccounts traverses cached accounts and adds as a sub-accounts any
// that belong to the currently selected account.
// The extKey is CKD#2 := root of sub-accounts of the main account
func (m *Manager) findSubAccounts(extKey *extkeys.ExtendedKey, subAccountIndex uint32) ([]accounts.Account, error) {
keyStore, err := m.geth.AccountKeyStore()
if err != nil {
return []accounts.Account{}, err
}
subAccounts := make([]accounts.Account, 0)
if extKey.Depth == 5 { // CKD#2 level
// gather possible sub-account addresses
subAccountAddresses := make([]gethcommon.Address, 0)
for i := uint32(0); i < subAccountIndex; i++ {
childKey, err := extKey.Child(i)
if err != nil {
return []accounts.Account{}, err
}
subAccountAddresses = append(subAccountAddresses, crypto.PubkeyToAddress(childKey.ToECDSA().PublicKey))
}
// see if any of the gathered addresses actually exist in cached accounts list
for _, cachedAccount := range keyStore.Accounts() {
for _, possibleAddress := range subAccountAddresses {
if possibleAddress.Hex() == cachedAccount.Address.Hex() {
subAccounts = append(subAccounts, cachedAccount)
}
}
}
}
return subAccounts, nil
}
// AddressToDecryptedAccount tries to load decrypted key for a given account.
// The running node, has a keystore directory which is loaded on start. Key file
// for a given address is expected to be in that directory prior to node start.
@ -558,16 +422,9 @@ func (m *Manager) unlockExtendedKey(address, password string) (*SelectedExtKey,
return nil, err
}
// persist account key for easier recovery of currently selected key
subAccounts, err := m.findSubAccounts(accountKey.ExtendedKey, accountKey.SubAccountIndex)
if err != nil {
return nil, err
}
selectedExtendedKey := &SelectedExtKey{
Address: account.Address,
AccountKey: accountKey,
SubAccounts: subAccounts,
Address: account.Address,
AccountKey: accountKey,
}
return selectedExtendedKey, nil

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/golang/mock/gomock"
@ -114,10 +115,7 @@ func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) {
require.NoError(t, err)
}
var (
errKeyStore = errors.New("Can't return a key store")
errAccManager = errors.New("Can't return an account manager")
)
var errKeyStore = errors.New("Can't return a key store")
func TestManagerTestSuite(t *testing.T) {
gethServiceProvider := newMockGethServiceProvider(t)
@ -289,21 +287,13 @@ func (s *ManagerTestSuite) TestSelectAccount() {
s.password,
errKeyStore,
},
{
"fail_wrongWalletAddress",
[]interface{}{s.keyStore, nil},
"wrong-wallet-address",
s.chatAddress,
s.password,
ErrAddressToAccountMappingFailure,
},
{
"fail_wrongChatAddress",
[]interface{}{s.keyStore, nil},
s.walletAddress,
"wrong-chat-address",
"0x0000000000000000000000000000000000000001",
s.password,
ErrAddressToAccountMappingFailure,
errors.New("cannot retrieve a valid key for a given account: no key for given address or file"),
},
{
"fail_wrongPassword",
@ -319,18 +309,24 @@ func (s *ManagerTestSuite) TestSelectAccount() {
s.T().Run(testCase.name, func(t *testing.T) {
s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes()
err := s.accManager.SelectAccount(testCase.walletAddress, testCase.chatAddress, testCase.password)
loginParams := LoginParams{
ChatAddress: common.HexToAddress(testCase.chatAddress),
MainAccount: common.HexToAddress(testCase.walletAddress),
Password: testCase.password,
}
err := s.accManager.SelectAccount(loginParams)
s.Equal(testCase.expectedError, err)
selectedWalletAccount, walletErr := s.accManager.SelectedWalletAccount()
selectedMainAccountAddress, walletErr := s.accManager.MainAccountAddress()
selectedChatAccount, chatErr := s.accManager.SelectedChatAccount()
if testCase.expectedError == nil {
s.Equal(selectedWalletAccount.AccountKey, selectedChatAccount.AccountKey)
s.Equal(testCase.walletAddress, selectedMainAccountAddress.String())
s.Equal(testCase.chatAddress, crypto.PubkeyToAddress(selectedChatAccount.AccountKey.PrivateKey.PublicKey).Hex())
s.NoError(walletErr)
s.NoError(chatErr)
} else {
s.Nil(selectedWalletAccount)
s.Equal(common.Address{}, selectedMainAccountAddress)
s.Nil(selectedChatAccount)
s.Equal(walletErr, ErrNoAccountSelected)
s.Equal(chatErr, ErrNoAccountSelected)
@ -356,95 +352,28 @@ func (s *ManagerTestSuite) TestSetChatAccount() {
s.Equal(privKey, selectedChatAccount.AccountKey.PrivateKey)
s.Equal(address, selectedChatAccount.Address)
selectedWalletAccount, err := s.accManager.SelectedWalletAccount()
selectedMainAccountAddress, err := s.accManager.MainAccountAddress()
s.Error(err)
s.Nil(selectedWalletAccount)
}
func (s *ManagerTestSuite) TestCreateChildAccount() {
// First, test the negative case where an account is not selected
// and an address is not provided.
s.accManager.selectedWalletAccount = nil
s.T().Run("fail_noAccount", func(t *testing.T) {
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes()
_, _, err := s.accManager.CreateChildAccount("", s.password)
s.Equal(ErrNoAccountSelected, err)
})
// Now, select the test account for rest of the test cases.
s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes()
err := s.accManager.SelectAccount(s.walletAddress, s.chatAddress, s.password)
s.NoError(err)
testCases := []struct {
name string
walletAddress string
chatAddress string
password string
accountKeyStoreReturn []interface{}
expectedError error
}{
{
"success",
s.walletAddress,
s.chatAddress,
s.password,
[]interface{}{s.keyStore, nil},
nil,
},
{
"fail_keyStore",
s.walletAddress,
s.chatAddress,
s.password,
[]interface{}{nil, errKeyStore},
errKeyStore,
},
{
"fail_wrongWalletAddress",
"wrong-address",
s.chatAddress,
s.password,
[]interface{}{s.keyStore, nil},
ErrAddressToAccountMappingFailure,
},
{
"fail_wrongPassword",
s.walletAddress,
s.chatAddress,
"wrong-password",
[]interface{}{s.keyStore, nil},
errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"),
},
}
for _, testCase := range testCases {
s.T().Run(testCase.name, func(t *testing.T) {
s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes()
childAddr, childPubKey, err := s.accManager.CreateChildAccount(testCase.walletAddress, testCase.password)
if testCase.expectedError != nil {
s.Equal(testCase.expectedError, err)
} else {
s.NoError(err)
s.NotEmpty(childAddr)
s.NotEmpty(childPubKey)
}
})
}
s.Equal(common.Address{}, selectedMainAccountAddress)
}
func (s *ManagerTestSuite) TestLogout() {
s.accManager.Logout()
s.Nil(s.accManager.selectedWalletAccount)
s.Equal(common.Address{}, s.accManager.mainAccountAddress)
s.Nil(s.accManager.selectedChatAccount)
s.Len(s.accManager.watchAddresses, 0)
}
// TestAccounts tests cases for (*Manager).Accounts.
func (s *ManagerTestSuite) TestAccounts() {
// Select the test account
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes()
err := s.accManager.SelectAccount(s.walletAddress, s.chatAddress, s.password)
loginParams := LoginParams{
MainAccount: common.HexToAddress(s.walletAddress),
ChatAddress: common.HexToAddress(s.chatAddress),
Password: s.password,
}
err := s.accManager.SelectAccount(loginParams)
s.NoError(err)
// Success
@ -453,13 +382,8 @@ func (s *ManagerTestSuite) TestAccounts() {
s.NoError(err)
s.NotNil(accs)
// Can't get an account manager
s.gethServiceProvider.EXPECT().AccountManager().Return(nil, errAccManager)
_, err = s.accManager.Accounts()
s.Equal(errAccManager, err)
// Selected account is nil but doesn't fail
s.accManager.selectedWalletAccount = nil
// Selected main account address is zero address but doesn't fail
s.accManager.mainAccountAddress = common.Address{}
s.gethServiceProvider.EXPECT().AccountManager().Return(s.gethAccManager, nil)
accs, err = s.accManager.Accounts()
s.NoError(err)

View File

@ -1,7 +1,9 @@
package account
import (
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
@ -14,6 +16,54 @@ var (
ErrInvalidMnemonicPhraseLength = errors.New("invalid mnemonic phrase length; valid lengths are 12, 15, 18, 21, and 24")
)
type LoginParams struct {
ChatAddress common.Address `json:"chatAddress"`
Password string `json:"password"`
MainAccount common.Address `json:"mainAccount"`
WatchAddresses []common.Address `json:"watchAddresses"`
}
type ErrZeroAddress struct {
field string
}
func (e *ErrZeroAddress) Error() string {
return fmt.Sprintf("%s contains an empty address", e.field)
}
func newErrZeroAddress(field string) *ErrZeroAddress {
return &ErrZeroAddress{
field: field,
}
}
func ParseLoginParams(paramsJSON string) (LoginParams, error) {
var (
params LoginParams
zeroAddress common.Address
)
if err := json.Unmarshal([]byte(paramsJSON), &params); err != nil {
return params, err
}
if params.ChatAddress == zeroAddress {
return params, newErrZeroAddress("ChatAddress")
}
if params.MainAccount == zeroAddress {
return params, newErrZeroAddress("MainAccount")
}
for _, address := range params.WatchAddresses {
if address == zeroAddress {
return params, newErrZeroAddress("WatchAddresses")
}
}
return params, nil
}
// Info contains wallet and chat addresses and public keys of an account.
type Info struct {
WalletAddress string

View File

@ -295,7 +295,7 @@ func (b *StatusBackend) CallPrivateRPC(inputJSON string) (string, error) {
// SendTransaction creates a new transaction and waits until it's complete.
func (b *StatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, password string) (hash gethcommon.Hash, err error) {
verifiedAccount, err := b.getVerifiedWalletAccount(password)
verifiedAccount, err := b.getVerifiedWalletAccount(sendArgs.From.String(), password)
if err != nil {
return hash, err
}
@ -329,7 +329,7 @@ func (b *StatusBackend) HashTransaction(sendArgs transactions.SendTxArgs) (trans
// SignMessage checks the pwd vs the selected account and passes on the signParams
// to personalAPI for message signature
func (b *StatusBackend) SignMessage(rpcParams personal.SignParams) (hexutil.Bytes, error) {
verifiedAccount, err := b.getVerifiedWalletAccount(rpcParams.Password)
verifiedAccount, err := b.getVerifiedWalletAccount(rpcParams.Address, rpcParams.Password)
if err != nil {
return hexutil.Bytes{}, err
}
@ -343,8 +343,8 @@ func (b *StatusBackend) Recover(rpcParams personal.RecoverParams) (gethcommon.Ad
}
// SignTypedData accepts data and password. Gets verified account and signs typed data.
func (b *StatusBackend) SignTypedData(typed typeddata.TypedData, password string) (hexutil.Bytes, error) {
account, err := b.getVerifiedWalletAccount(password)
func (b *StatusBackend) SignTypedData(typed typeddata.TypedData, address string, password string) (hexutil.Bytes, error) {
account, err := b.getVerifiedWalletAccount(address, password)
if err != nil {
return hexutil.Bytes{}, err
}
@ -366,19 +366,40 @@ func (b *StatusBackend) HashTypedData(typed typeddata.TypedData) (common.Hash, e
return hash, err
}
func (b *StatusBackend) getVerifiedWalletAccount(password string) (*account.SelectedExtKey, error) {
selectedWalletAccount, err := b.accountManager.SelectedWalletAccount()
if err != nil {
b.log.Error("failed to get a selected account", "err", err)
return nil, err
}
func (b *StatusBackend) getVerifiedWalletAccount(address, password string) (*account.SelectedExtKey, error) {
config := b.StatusNode().Config()
_, err = b.accountManager.VerifyAccountPassword(config.KeyStoreDir, selectedWalletAccount.Address.String(), password)
var validAddress bool
addresses := b.accountManager.WatchAddresses()
mainAccountAddress, err := b.accountManager.MainAccountAddress()
if err != nil {
b.log.Error("failed to verify account", "account", selectedWalletAccount.Address.String(), "error", err)
return nil, err
}
return selectedWalletAccount, nil
addresses = append(addresses, mainAccountAddress)
for _, a := range addresses {
if a.String() == address {
validAddress = true
break
}
}
if !validAddress {
b.log.Error("failed to get a selected account", "err", transactions.ErrInvalidTxSender)
return nil, transactions.ErrInvalidTxSender
}
key, err := b.accountManager.VerifyAccountPassword(config.KeyStoreDir, address, password)
if err != nil {
b.log.Error("failed to verify account", "account", address, "error", err)
return nil, err
}
return &account.SelectedExtKey{
Address: key.Address,
AccountKey: key,
}, nil
}
// registerHandlers attaches Status callback handlers to running node
@ -531,13 +552,13 @@ func (b *StatusBackend) reSelectAccount() error {
// SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted
// using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity,
// all previous identities are removed).
func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password string) error {
func (b *StatusBackend) SelectAccount(loginParams account.LoginParams) error {
b.mu.Lock()
defer b.mu.Unlock()
b.AccountManager().RemoveOnboarding()
err := b.accountManager.SelectAccount(walletAddress, chatAddress, password)
err := b.accountManager.SelectAccount(loginParams)
if err != nil {
return err
}
@ -564,37 +585,48 @@ func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password strin
return err
}
if err := st.InitProtocolWithPassword(chatAddress, password); err != nil {
if err := st.InitProtocolWithPassword(loginParams.ChatAddress.String(), loginParams.Password); err != nil {
return err
}
}
err = b.startWallet(password)
err = b.startWallet(loginParams.Password)
if err != nil {
return err
}
err = b.startBrowsers(password)
err = b.startBrowsers(loginParams.Password)
if err != nil {
return err
}
return b.startPermissions(password)
return b.startPermissions(loginParams.Password)
}
func (b *StatusBackend) startWallet(password string) error {
if !b.statusNode.Config().WalletConfig.Enabled {
return nil
}
wallet, err := b.statusNode.WalletService()
if err != nil {
return err
}
account, err := b.accountManager.SelectedWalletAccount()
watchAddresses := b.accountManager.WatchAddresses()
mainAccountAddress, err := b.accountManager.MainAccountAddress()
if err != nil {
return err
}
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("wallet-%x.sql", account.Address))
allAddresses := make([]common.Address, len(watchAddresses)+1)
allAddresses[0] = mainAccountAddress
copy(allAddresses[1:], watchAddresses)
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("wallet-%x.sql", mainAccountAddress))
return wallet.StartReactor(path, password,
b.statusNode.RPCClient().Ethclient(),
[]common.Address{account.Address},
allAddresses,
new(big.Int).SetUint64(b.statusNode.Config().NetworkID))
}
@ -606,11 +638,13 @@ func (b *StatusBackend) startBrowsers(password string) error {
if err != nil {
return err
}
account, err := b.accountManager.SelectedWalletAccount()
mainAccountAddress, err := b.accountManager.MainAccountAddress()
if err != nil {
return err
}
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("browsers-%x.sql", account.Address))
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("browsers-%x.sql", mainAccountAddress))
return svc.StartDatabase(path, password)
}
@ -622,11 +656,11 @@ func (b *StatusBackend) startPermissions(password string) error {
if err != nil {
return err
}
account, err := b.accountManager.SelectedWalletAccount()
mainAccountAddress, err := b.accountManager.MainAccountAddress()
if err != nil {
return err
}
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("permissions-%x.sql", account.Address))
path := path.Join(b.statusNode.Config().DataDir, fmt.Sprintf("permissions-%x.sql", mainAccountAddress))
return svc.StartDatabase(path, password)
}

View File

@ -6,6 +6,8 @@ import (
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/signal"
"github.com/status-im/status-go/t/utils"
@ -226,7 +228,12 @@ func initNodeAndLogin(t *testing.T, backend *StatusBackend) (string, string) {
info, _, err := backend.AccountManager().CreateAccount(password)
require.NoError(t, err)
require.NoError(t, backend.AccountManager().SelectAccount(info.WalletAddress, info.ChatAddress, password))
loginParams := account.LoginParams{
MainAccount: common.HexToAddress(info.WalletAddress),
ChatAddress: common.HexToAddress(info.ChatAddress),
Password: password,
}
require.NoError(t, backend.AccountManager().SelectAccount(loginParams))
unlockFmt := `
{

View File

@ -167,7 +167,12 @@ func TestBackendAccountsConcurrently(t *testing.T) {
for tuple := range addressCh {
wg.Add(1)
go func(tuple [3]string) {
assert.NoError(t, backend.SelectAccount(tuple[0], tuple[1], tuple[2]))
loginParams := account.LoginParams{
MainAccount: common.HexToAddress(tuple[0]),
ChatAddress: common.HexToAddress(tuple[1]),
Password: tuple[2],
}
assert.NoError(t, backend.SelectAccount(loginParams))
wg.Done()
}(tuple)
@ -219,8 +224,8 @@ func TestBackendInjectChatAccount(t *testing.T) {
require.True(t, whisperService.HasKeyPair(chatPubKeyHex), "identity not injected into whisper")
// wallet account should not be selected
walletAcc, err := backend.AccountManager().SelectedWalletAccount()
require.Nil(t, walletAcc)
mainAccountAddress, err := backend.AccountManager().MainAccountAddress()
require.Equal(t, common.Address{}, mainAccountAddress)
require.Equal(t, account.ErrNoAccountSelected, err)
// selected chat account should have the key injected previously

View File

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/exportlogs"
"github.com/status-im/status-go/logutils"
@ -225,26 +226,6 @@ func CreateAccount(password *C.char) *C.char {
return C.CString(string(outBytes))
}
//CreateChildAccount creates sub-account
//export CreateChildAccount
func CreateChildAccount(parentAddress, password *C.char) *C.char {
address, pubKey, err := statusBackend.AccountManager().CreateChildAccount(C.GoString(parentAddress), C.GoString(password))
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := AccountInfo{
Address: address,
PubKey: pubKey,
Error: errString,
}
outBytes, _ := json.Marshal(out)
return C.CString(string(outBytes))
}
//RecoverAccount re-creates master key using given details
//export RecoverAccount
func RecoverAccount(password, mnemonic *C.char) *C.char {
@ -346,8 +327,13 @@ func VerifyAccountPassword(keyStoreDir, address, password *C.char) *C.char {
//Login loads a key file (for a given address), tries to decrypt it using the password, to verify ownership
// if verified, purges all the previous identities from Whisper, and injects verified key as shh identity
//export Login
func Login(address, password *C.char) *C.char {
err := statusBackend.SelectAccount(C.GoString(address), C.GoString(address), C.GoString(password))
func Login(loginParamsJSON *C.char) *C.char {
params, err := account.ParseLoginParams(C.GoString(loginParamsJSON))
if err != nil {
return C.CString(prepareJSONResponseWithCode(nil, err, codeFailedParseParams))
}
err = statusBackend.SelectAccount(params)
return makeJSONResponse(err)
}
@ -473,7 +459,7 @@ func HashMessage(message *C.char) *C.char {
// SignTypedData unmarshall data into TypedData, validate it and signs with selected account,
// if password matches selected account.
//export SignTypedData
func SignTypedData(data, password *C.char) *C.char {
func SignTypedData(data, address, password *C.char) *C.char {
var typed typeddata.TypedData
err := json.Unmarshal([]byte(C.GoString(data)), &typed)
if err != nil {
@ -482,7 +468,7 @@ func SignTypedData(data, password *C.char) *C.char {
if err := typed.Validate(); err != nil {
return C.CString(prepareJSONResponseWithCode(nil, err, codeFailedParseParams))
}
result, err := statusBackend.SignTypedData(typed, C.GoString(password))
result, err := statusBackend.SignTypedData(typed, C.GoString(address), C.GoString(password))
return C.CString(prepareJSONResponse(result.String(), err))
}

View File

@ -13,6 +13,7 @@ import "C"
import (
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"os"
@ -46,6 +47,22 @@ var (
nodeConfigJSON string
)
func buildLoginParamsJSON(chatAddress, password string) *C.char {
return C.CString(fmt.Sprintf(`{
"chatAddress": "%s",
"password": "%s",
"mainAccount": "%s"
}`, chatAddress, password, chatAddress))
}
func buildLoginParams(mainAccountAddress, chatAddress, password string) account.LoginParams {
return account.LoginParams{
ChatAddress: gethcommon.HexToAddress(chatAddress),
Password: password,
MainAccount: gethcommon.HexToAddress(mainAccountAddress),
}
}
func init() {
testChainDir = filepath.Join(TestDataDir, TestNetworkNames[GetNetworkID()])
@ -110,10 +127,6 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
"call private API using private RPC client",
testCallPrivateRPCWithPrivateAPI,
},
{
"create main and child accounts",
testCreateChildAccount,
},
{
"verify account password",
testVerifyAccountPassword,
@ -261,7 +274,7 @@ func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo
// select account
loginResponse := APIResponse{}
rawResponse := Login(C.CString(account1.WalletAddress), C.CString(TestConfig.Account1.Password))
rawResponse := Login(buildLoginParamsJSON(account1.WalletAddress, TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -377,149 +390,6 @@ func testCallPrivateRPCWithPrivateAPI(t *testing.T) bool {
return true
}
func testCreateChildAccount(t *testing.T) bool { //nolint: gocyclo
// to make sure that we start with empty account (which might get populated during previous tests)
if err := statusBackend.Logout(); err != nil {
t.Fatal(err)
}
keyStore, err := statusBackend.StatusNode().AccountKeyStore()
if err != nil {
t.Error(err)
return false
}
// create an account
createAccountResponse := AccountInfo{}
rawResponse := CreateAccount(C.CString(TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &createAccountResponse); err != nil {
t.Errorf("cannot decode CreateAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createAccountResponse.Error != "" {
t.Errorf("could not create account: %s", err)
return false
}
if createAccountResponse.Address != createAccountResponse.WalletAddress ||
createAccountResponse.PubKey != createAccountResponse.WalletPubKey {
t.Error("for backward compatibility pubkey/address should be equal to walletAddress/walletPubKey")
}
walletAddress, walletPubKey, chatAddress, _, mnemonic := createAccountResponse.Address, createAccountResponse.PubKey,
createAccountResponse.ChatAddress, createAccountResponse.ChatPubKey, createAccountResponse.Mnemonic
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", walletAddress, walletPubKey, mnemonic)
acct, err := account.ParseAccountString(walletAddress)
if err != nil {
t.Errorf("can not get account from address: %v", err)
return false
}
// 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)
if err != nil {
t.Errorf("can not obtain decrypted account key: %v", err)
return false
}
if key.ExtendedKey == nil {
t.Error("CKD#2 has not been generated for new account")
return false
}
// try creating sub-account, w/o selecting main account i.e. w/o login to main account
createSubAccountResponse := AccountInfo{}
rawResponse = CreateChildAccount(C.CString(""), C.CString(TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
t.Errorf("cannot decode CreateChildAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createSubAccountResponse.Error != account.ErrNoAccountSelected.Error() {
t.Errorf("expected error is not returned (tried to create sub-account w/o login): %v", createSubAccountResponse.Error)
return false
}
err = statusBackend.SelectAccount(walletAddress, chatAddress, TestConfig.Account1.Password)
if err != nil {
t.Errorf("Test failed: could not select account: %v", err)
return false
}
// try to create sub-account with wrong password
createSubAccountResponse = AccountInfo{}
rawResponse = CreateChildAccount(C.CString(""), C.CString("wrong password"))
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil {
t.Errorf("cannot decode CreateChildAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createSubAccountResponse.Error != "cannot retrieve a valid key for a given account: could not decrypt key with given passphrase" {
t.Errorf("expected error is not returned (tried to create sub-account with wrong password): %v", createSubAccountResponse.Error)
return false
}
// create sub-account (from implicit parent)
createSubAccountResponse1 := AccountInfo{}
rawResponse = CreateChildAccount(C.CString(""), C.CString(TestConfig.Account1.Password))
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse1); err != nil {
t.Errorf("cannot decode CreateChildAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createSubAccountResponse1.Error != "" {
t.Errorf("cannot create sub-account: %v", createSubAccountResponse1.Error)
return false
}
// make sure that sub-account index automatically progresses
createSubAccountResponse2 := AccountInfo{}
rawResponse = CreateChildAccount(C.CString(""), C.CString(TestConfig.Account1.Password))
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse2); err != nil {
t.Errorf("cannot decode CreateChildAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createSubAccountResponse2.Error != "" {
t.Errorf("cannot create sub-account: %v", createSubAccountResponse2.Error)
}
if createSubAccountResponse1.Address == createSubAccountResponse2.Address || createSubAccountResponse1.PubKey == createSubAccountResponse2.PubKey {
t.Error("sub-account index auto-increament failed")
return false
}
// create sub-account (from explicit parent)
createSubAccountResponse3 := AccountInfo{}
rawResponse = CreateChildAccount(C.CString(createSubAccountResponse2.Address), C.CString(TestConfig.Account1.Password))
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse3); err != nil {
t.Errorf("cannot decode CreateChildAccount response (%s): %v", C.GoString(rawResponse), err)
return false
}
if createSubAccountResponse3.Error != "" {
t.Errorf("cannot create sub-account: %v", createSubAccountResponse3.Error)
}
subAccount1, subAccount2, subAccount3 := createSubAccountResponse1.Address, createSubAccountResponse2.Address, createSubAccountResponse3.Address
subPubKey1, subPubKey2, subPubKey3 := createSubAccountResponse1.PubKey, createSubAccountResponse2.PubKey, createSubAccountResponse3.PubKey
if subAccount1 == subAccount3 || subPubKey1 == subPubKey3 || subAccount2 == subAccount3 || subPubKey2 == subPubKey3 {
t.Error("sub-account index auto-increament failed")
return false
}
return true
}
func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
keyStore, _ := statusBackend.StatusNode().AccountKeyStore()
@ -643,7 +513,7 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
if whisperService.HasKeyPair(chatPubKeyCheck) {
t.Error("identity already present in whisper")
}
err = statusBackend.SelectAccount(walletAddressCheck, chatAddressCheck, TestConfig.Account1.Password)
err = statusBackend.SelectAccount(buildLoginParams(walletAddressCheck, chatAddressCheck, TestConfig.Account1.Password))
if err != nil {
t.Errorf("Test failed: could not select account: %v", err)
return false
@ -684,7 +554,7 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
// try selecting with wrong password
loginResponse := APIResponse{}
rawResponse := Login(C.CString(accountInfo1.WalletAddress), C.CString("wrongPassword"))
rawResponse := Login(buildLoginParamsJSON(accountInfo1.WalletAddress, "wrongPassword"))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -697,7 +567,7 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
}
loginResponse = APIResponse{}
rawResponse = Login(C.CString(accountInfo1.WalletAddress), C.CString(TestConfig.Account1.Password))
rawResponse = Login(buildLoginParamsJSON(accountInfo1.WalletAddress, TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -718,7 +588,7 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
}
loginResponse = APIResponse{}
rawResponse = Login(C.CString(accountInfo2.WalletAddress), C.CString(TestConfig.Account1.Password))
rawResponse = Login(buildLoginParamsJSON(accountInfo2.WalletAddress, TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -807,7 +677,7 @@ func testAccountLogout(t *testing.T) bool {
}
// select/login
err = statusBackend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)
err = statusBackend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
if err != nil {
t.Errorf("Test failed: could not select account: %v", err)
return false
@ -848,7 +718,7 @@ func testSendTransaction(t *testing.T) bool {
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
// log into account from which transactions will be sent
if err := statusBackend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password); err != nil {
if err := statusBackend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
return false
}
@ -886,11 +756,11 @@ func testSendTransactionInvalidPassword(t *testing.T) bool {
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
// log into account from which transactions will be sent
if err := statusBackend.SelectAccount(
if err := statusBackend.SelectAccount(buildLoginParams(
TestConfig.Account1.WalletAddress,
TestConfig.Account1.ChatAddress,
TestConfig.Account1.Password,
); err != nil {
)); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
return false
}
@ -923,8 +793,8 @@ func testFailedTransaction(t *testing.T) bool {
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
// log into wrong account in order to get selectedAccount error
if err := statusBackend.SelectAccount(TestConfig.Account2.WalletAddress, TestConfig.Account2.ChatAddress, TestConfig.Account2.Password); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
if err := statusBackend.SelectAccount(buildLoginParams(TestConfig.Account2.WalletAddress, TestConfig.Account2.ChatAddress, TestConfig.Account2.Password)); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account2.WalletAddress, err)
return false
}

View File

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/exportlogs"
"github.com/status-im/status-go/logutils"
@ -229,25 +230,6 @@ func CreateAccount(password string) string {
return string(outBytes)
}
// CreateChildAccount creates sub-account.
func CreateChildAccount(parentAddress, password string) string {
address, pubKey, err := statusBackend.AccountManager().CreateChildAccount(parentAddress, password)
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := AccountInfo{
Address: address,
PubKey: pubKey,
Error: errString,
}
outBytes, _ := json.Marshal(out)
return string(outBytes)
}
// RecoverAccount re-creates master key using given details.
func RecoverAccount(password, mnemonic string) string {
info, err := statusBackend.AccountManager().RecoverAccount(password, mnemonic)
@ -344,8 +326,13 @@ func VerifyAccountPassword(keyStoreDir, address, password string) string {
// Login loads a key file (for a given address), tries to decrypt it using the password,
// to verify ownership if verified, purges all the previous identities from Whisper,
// and injects verified key as shh identity.
func Login(address, password string) string {
err := statusBackend.SelectAccount(address, address, password)
func Login(loginParamsJSON string) string {
params, err := account.ParseLoginParams(loginParamsJSON)
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
err = statusBackend.SelectAccount(params)
return makeJSONResponse(err)
}
@ -377,7 +364,7 @@ func SignMessage(rpcParams string) string {
// SignTypedData unmarshall data into TypedData, validate it and signs with selected account,
// if password matches selected account.
//export SignTypedData
func SignTypedData(data, password string) string {
func SignTypedData(data, address, password string) string {
var typed typeddata.TypedData
err := json.Unmarshal([]byte(data), &typed)
if err != nil {
@ -386,7 +373,7 @@ func SignTypedData(data, password string) string {
if err := typed.Validate(); err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
result, err := statusBackend.SignTypedData(typed, password)
result, err := statusBackend.SignTypedData(typed, address, password)
return prepareJSONResponse(result.String(), err)
}

View File

@ -91,17 +91,17 @@ func (mr *MockAccountManagerMockRecorder) AddressToDecryptedAccount(arg0, arg1 i
}
// SelectAccount mocks base method
func (m *MockAccountManager) SelectAccount(walletAddress, chatAddress, password string) error {
func (m *MockAccountManager) SelectAccount(arg0 account.LoginParams) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SelectAccount", walletAddress, chatAddress, password)
ret := m.ctrl.Call(m, "SelectAccount", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// SelectAccount indicates an expected call of SelectAccount
func (mr *MockAccountManagerMockRecorder) SelectAccount(walletAddress, chatAddress, password interface{}) *gomock.Call {
func (mr *MockAccountManagerMockRecorder) SelectAccount(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAccount", reflect.TypeOf((*MockAccountManager)(nil).SelectAccount), walletAddress, chatAddress, password)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAccount", reflect.TypeOf((*MockAccountManager)(nil).SelectAccount), arg0)
}
// CreateAccount mocks base method

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/account"
)
@ -40,7 +41,12 @@ func (api *PublicAPI) Login(context context.Context, req LoginRequest) (res Logi
return
}
if err = api.s.am.SelectAccount(req.Addr, req.Addr, req.Password); err != nil {
loginParams := account.LoginParams{
ChatAddress: common.HexToAddress(req.Addr),
Password: req.Password,
MainAccount: common.HexToAddress(req.Addr),
}
if err = api.s.am.SelectAccount(loginParams); err != nil {
return
}

View File

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/golang/mock/gomock"
"github.com/status-im/status-go/account"
"github.com/stretchr/testify/suite"
@ -48,9 +49,15 @@ var logintests = []struct {
key := keystore.Key{
PrivateKey: &ecdsa.PrivateKey{},
}
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil)
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(accounts.Account{}, &key, nil)
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("addressKey", nil)
s.am.EXPECT().SelectAccount("address...", "address...", "password").Return(nil)
loginParams := account.LoginParams{
MainAccount: common.HexToAddress("0x01"),
ChatAddress: common.HexToAddress("0x01"),
Password: "password",
}
s.am.EXPECT().SelectAccount(loginParams).Return(nil)
},
},
{
@ -61,7 +68,7 @@ var logintests = []struct {
key := keystore.Key{
PrivateKey: &ecdsa.PrivateKey{},
}
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, errors.New("foo"))
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(accounts.Account{}, &key, errors.New("foo"))
},
},
{
@ -72,7 +79,7 @@ var logintests = []struct {
key := keystore.Key{
PrivateKey: &ecdsa.PrivateKey{},
}
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil)
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(accounts.Account{}, &key, nil)
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", errors.New("foo"))
},
},
@ -84,16 +91,22 @@ var logintests = []struct {
key := keystore.Key{
PrivateKey: &ecdsa.PrivateKey{},
}
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil)
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(accounts.Account{}, &key, nil)
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", nil)
s.am.EXPECT().SelectAccount("address...", "address...", "password").Return(errors.New("foo"))
loginParams := account.LoginParams{
MainAccount: common.HexToAddress("0x01"),
ChatAddress: common.HexToAddress("0x01"),
Password: "password",
}
s.am.EXPECT().SelectAccount(loginParams).Return(errors.New("foo"))
},
},
}
func (s *StatusSuite) TestLogin() {
for _, t := range logintests {
req := LoginRequest{Addr: "address...", Password: "password"}
req := LoginRequest{Addr: "0x01", Password: "password"}
t.prepareExpectations(s)

View File

@ -22,7 +22,7 @@ type WhisperService interface {
// AccountManager interface to manage account actions
type AccountManager interface {
AddressToDecryptedAccount(string, string) (accounts.Account, *keystore.Key, error)
SelectAccount(walletAddress, chatAddress, password string) error
SelectAccount(account.LoginParams) error
CreateAccount(password string) (accountInfo account.Info, mnemonic string, err error)
}

View File

@ -30,8 +30,17 @@ type TransfersSuite struct {
}
func (s *TransfersSuite) SelectAccount() {
s.Require().NoError(s.backend.SelectAccount(s.Info.WalletAddress, s.Info.ChatAddress, s.Password))
_, err := s.backend.AccountManager().SelectedWalletAccount()
loginParams := account.LoginParams{
ChatAddress: common.HexToAddress(s.Info.ChatAddress),
Password: s.Password,
MainAccount: common.HexToAddress(s.Info.WalletAddress),
}
s.Require().NoError(s.backend.SelectAccount(loginParams))
_, err := s.backend.AccountManager().MainAccountAddress()
s.Require().NoError(err)
_, err = s.backend.AccountManager().SelectedChatAccount()
s.Require().NoError(err)
}

View File

@ -23,7 +23,7 @@ func (s *AccountsTestSuite) TestRPCEthAccounts() {
defer s.StopTestBackend()
// log into test account
err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err := s.Backend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password, nil))
s.NoError(err)
rpcClient := s.Backend.StatusNode().RPCClient()
@ -51,7 +51,7 @@ func (s *AccountsTestSuite) TestRPCEthAccountsWithUpstream() {
defer s.StopTestBackend()
// log into test account
err = s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err = s.Backend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password, nil))
s.NoError(err)
rpcClient := s.Backend.StatusNode().RPCClient()

View File

@ -6,6 +6,7 @@ import (
"fmt"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/extkeys"
@ -14,6 +15,15 @@ import (
"github.com/stretchr/testify/suite"
)
func buildLoginParams(mainAccountAddress, chatAddress, password string, watchAddresses []common.Address) account.LoginParams {
return account.LoginParams{
ChatAddress: common.HexToAddress(chatAddress),
Password: password,
MainAccount: common.HexToAddress(mainAccountAddress),
WatchAddresses: watchAddresses,
}
}
func TestAccountsTestSuite(t *testing.T) {
suite.Run(t, new(AccountsTestSuite))
}
@ -42,7 +52,7 @@ func (s *AccountsTestSuite) TestAccountsList() {
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.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)
err = s.Backend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password, nil))
s.NoError(err, "account selection failed")
// at this point main account should show up
@ -51,36 +61,6 @@ func (s *AccountsTestSuite) TestAccountsList() {
s.Equal(1, len(accounts), "exactly single account is expected (main account)")
s.Equal(accounts[0].Hex(), accountInfo.WalletAddress,
fmt.Sprintf("main account is not retured as the first key: got %s, expected %s", accounts[0].Hex(), "0x"+accountInfo.WalletAddress))
// 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(accounts[0].Hex(), accountInfo.WalletAddress, "main account is not retured as the first key")
s.Equal(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(accounts[0].Hex(), accountInfo.WalletAddress, "main account is not retured as the first key")
subAccount1MatchesKey1 := accounts[1].Hex() != "0x"+subAccount1
subAccount1MatchesKey2 := accounts[2].Hex() != "0x"+subAccount1
s.False(!subAccount1MatchesKey1 && !subAccount1MatchesKey2, "subAcount1 not returned")
subAccount2MatchesKey1 := accounts[1].Hex() != "0x"+subAccount2
subAccount2MatchesKey2 := accounts[2].Hex() != "0x"+subAccount2
s.False(!subAccount2MatchesKey1 && !subAccount2MatchesKey2, "subAcount2 not returned")
}
func (s *AccountsTestSuite) TestImportSingleExtendedKey() {
@ -135,55 +115,6 @@ func (s *AccountsTestSuite) TestImportAccount() {
s.True(key.ExtendedKey.IsZeroed())
}
func (s *AccountsTestSuite) TestCreateChildAccount() {
s.StartTestBackend()
defer s.StopTestBackend()
keyStore, err := s.Backend.StatusNode().AccountKeyStore()
s.NoError(err)
s.NotNil(keyStore)
// create an account
accountInfo, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err)
s.T().Logf("Account created: {walletAddress: %s, walletKey: %s, chatAddress: %s, chatKey: %s, mnemonic:%s}",
accountInfo.WalletAddress, accountInfo.WalletPubKey, accountInfo.ChatAddress, accountInfo.ChatPubKey, mnemonic)
acct, err := account.ParseAccountString(accountInfo.WalletAddress)
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.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, 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()
@ -244,15 +175,15 @@ func (s *AccountsTestSuite) TestSelectAccount() {
accountInfo2.WalletAddress, accountInfo2.WalletPubKey, accountInfo2.ChatAddress, accountInfo2.ChatPubKey)
// try selecting with wrong password
err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword", nil))
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.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password, nil))
s.NoError(err)
// select another account, make sure that previous account is wiped out from Whisper cache
s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password, nil)))
}
func (s *AccountsTestSuite) TestSetChatAccount() {
@ -285,19 +216,23 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.NoError(err)
// make sure that no account is selected by default
selectedWalletAccount, err := s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err := s.Backend.AccountManager().MainAccountAddress()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedWalletAccount)
s.Equal(common.Address{}, selectedWalletAccount)
selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedChatAccount)
// select account
err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword", nil))
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.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password))
watchAddresses := []common.Address{
common.HexToAddress("0x00000000000000000000000000000000000001"),
common.HexToAddress("0x00000000000000000000000000000000000002"),
}
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password, watchAddresses)))
// stop node (and all of its sub-protocols)
nodeConfig := s.Backend.StatusNode().Config()
@ -306,27 +241,29 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.NoError(s.Backend.StopNode())
// make sure that account is still selected
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress()
s.Require().NoError(err)
s.NotNil(selectedWalletAccount)
s.Equal(selectedWalletAccount.Address.Hex(), accountInfo2.WalletAddress, "incorrect wallet address selected")
s.Equal(selectedWalletAccount.String(), accountInfo2.WalletAddress, "incorrect wallet address selected")
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err)
s.NotNil(selectedChatAccount)
s.Equal(selectedChatAccount.Address.Hex(), accountInfo2.ChatAddress, "incorrect chat address selected")
s.Equal(watchAddresses, s.Backend.AccountManager().WatchAddresses())
// resume node
s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig))
// re-check selected account (account2 MUST be selected)
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress()
s.NoError(err)
s.NotNil(selectedWalletAccount)
s.Equal(selectedWalletAccount.Address.Hex(), accountInfo2.WalletAddress, "incorrect wallet address selected")
s.Equal(selectedWalletAccount.String(), accountInfo2.WalletAddress, "incorrect wallet address selected")
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err)
s.NotNil(selectedChatAccount)
s.Equal(selectedChatAccount.Address.Hex(), accountInfo2.WalletAddress, "incorrect chat address selected")
s.Equal(watchAddresses, s.Backend.AccountManager().WatchAddresses())
// now restart node using RestartNode() method, and make sure that account is still available
s.RestartTestNode()
@ -336,10 +273,11 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.NoError(s.Backend.Logout())
s.RestartTestNode()
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress()
s.EqualError(account.ErrNoAccountSelected, err.Error())
s.Nil(selectedWalletAccount)
s.Equal(common.Address{}, selectedWalletAccount)
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error())
s.Nil(selectedChatAccount)
s.Len(s.Backend.AccountManager().WatchAddresses(), 0)
}

View File

@ -5,6 +5,7 @@ import (
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/account"
@ -17,6 +18,14 @@ import (
type initFunc func([]byte, *transactions.SendTxArgs)
func buildLoginParams(mainAccountAddress, chatAddress, password string) account.LoginParams {
return account.LoginParams{
ChatAddress: common.HexToAddress(chatAddress),
Password: password,
MainAccount: common.HexToAddress(mainAccountAddress),
}
}
func TestTransactionsTestSuite(t *testing.T) {
suite.Run(t, new(TransactionsTestSuite))
}
@ -70,7 +79,7 @@ func (s *TransactionsTestSuite) TestCallUpstreamPrivateRPCSendTransaction() {
func (s *TransactionsTestSuite) sendTransactionUsingRPCClient(
callRPCFn func(string) (string, error),
) {
err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err := s.Backend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
result, err := callRPCFn(`{
@ -94,7 +103,7 @@ func (s *TransactionsTestSuite) TestEmptyToFieldPreserved() {
defer s.StopTestBackend()
EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err := s.Backend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
args := transactions.SendTxArgs{
@ -162,7 +171,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err := s.Backend.AccountManager().SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
// this call blocks, up until Complete Transaction is called
@ -196,7 +205,7 @@ func (s *TransactionsTestSuite) TestSendEther() {
EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err := s.Backend.AccountManager().SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{
@ -216,7 +225,7 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() {
s.StartTestBackend(e2e.WithUpstream(addr))
defer s.StopTestBackend()
err = s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
err = s.Backend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{

View File

@ -5,6 +5,7 @@ import (
"errors"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/status-im/status-go/account"
@ -22,6 +23,14 @@ type WhisperTestSuite struct {
e2e.BackendTestSuite
}
func buildLoginParams(mainAccountAddress, chatAddress, password string) account.LoginParams {
return account.LoginParams{
ChatAddress: common.HexToAddress(chatAddress),
Password: password,
MainAccount: common.HexToAddress(mainAccountAddress),
}
}
// TODO(adam): can anyone explain what this test is testing?
// I don't see any race condition testing here.
func (s *WhisperTestSuite) TestWhisperFilterRace() {
@ -109,17 +118,17 @@ func (s *WhisperTestSuite) TestSelectAccount() {
s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper")
// try selecting with wrong password
err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongpassword")
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongpassword"))
s.NotNil(err)
// select account 1
err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password))
s.NoError(err)
s.True(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity not injected in whisper")
// select account 2, make sure that previous account is wiped out from Whisper cache
s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper")
s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password)))
s.True(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity not injected into whisper")
}
@ -136,7 +145,7 @@ func (s *WhisperTestSuite) TestLogout() {
// make sure that identity doesn't exist (yet) in Whisper
s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity already present in whisper")
s.NoError(s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)))
s.True(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not injected into whisper")
s.NoError(s.Backend.Logout())
@ -159,9 +168,9 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
s.False(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity already present in whisper")
// make sure that no wallet account is selected by default
selectedWalletAccount, err := s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err := s.Backend.AccountManager().MainAccountAddress()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedWalletAccount)
s.Equal(common.Address{}, selectedWalletAccount)
// make sure that no chat account is selected by default
selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount()
@ -169,12 +178,12 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
s.Nil(selectedChatAccount)
// select account with wrong password
err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
err = s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "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 with right password
s.NoError(s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)))
selectedChatAccount1, err := s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err)
selectedChatPubKey1 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount1.AccountKey.PrivateKey.PublicKey))
@ -183,7 +192,7 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
// select another account, make sure that previous account is wiped out from Whisper cache
s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper")
s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password)))
selectedChatAccount2, err := s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err)
selectedChatPubKey2 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount2.AccountKey.PrivateKey.PublicKey))
@ -201,10 +210,10 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig))
// re-check selected account (account2 MUST be selected)
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress()
s.NoError(err)
s.NotNil(selectedWalletAccount)
s.Equal(selectedWalletAccount.Address.Hex(), accountInfo2.WalletAddress, "incorrect wallet address selected")
s.Equal(selectedWalletAccount.String(), accountInfo2.WalletAddress, "incorrect wallet address selected")
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err)
s.NotNil(selectedChatAccount)
@ -230,9 +239,9 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
s.False(whisperService.HasKeyPair(selectedChatPubKey2), "identity not injected into whisper")
s.False(whisperService.HasKeyPair(selectedChatPubKey1), "identity should not be present, but it is still present in whisper")
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
selectedWalletAccount, err = s.Backend.AccountManager().MainAccountAddress()
s.EqualError(account.ErrNoAccountSelected, err.Error())
s.Nil(selectedWalletAccount)
s.Equal(common.Address{}, selectedWalletAccount)
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error())
@ -251,7 +260,7 @@ func (s *WhisperTestSuite) TestSelectedChatKeyIsUsedInWhisper() {
s.NoError(err)
// select account
s.NoError(s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
s.NoError(s.Backend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)))
// Get the chat account
selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount()