Unlock wallet and chat keys (#1346)

* select account decrypting wallet and chat keys

* adapt account tests to use chat and wallet account/keys

* fix tests using chat address

* changes after review

* fix status service e2e tests

* add account.Info struct returned when creating and recovering an account

* use s.EqualValues to compare recovered accounts

* return Info instead of *Info

* add both address and walletAddress to responses

* Update lib/types.go

Co-Authored-By: gravityblast <andrea@gravityblast.com>

* Update lib/types.go

Co-Authored-By: gravityblast <andrea@gravityblast.com>

* update comment to fix lint
This commit is contained in:
Andrea Franz 2019-01-18 10:01:14 +01:00 committed by GitHub
parent 6e88828d76
commit 4939268edf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 486 additions and 332 deletions

View File

@ -51,12 +51,13 @@ func NewManager(geth GethServiceProvider) *Manager {
// BIP44-compatible keys are generated: CKD#1 is stored as account key, CKD#2 stored as sub-account root // BIP44-compatible keys are generated: CKD#1 is stored as account key, CKD#2 stored as sub-account root
// Public key of CKD#1 is returned, with CKD#2 securely encoded into account key file (to be used for // Public key of CKD#1 is returned, with CKD#2 securely encoded into account key file (to be used for
// sub-account derivations) // sub-account derivations)
func (m *Manager) CreateAccount(password string) (address, pubKey, mnemonic string, err error) { func (m *Manager) CreateAccount(password string) (Info, string, error) {
info := Info{}
// generate mnemonic phrase // generate mnemonic phrase
mn := extkeys.NewMnemonic() mn := extkeys.NewMnemonic()
mnemonic, err = mn.MnemonicPhrase(extkeys.EntropyStrength128, extkeys.EnglishLanguage) mnemonic, err := mn.MnemonicPhrase(extkeys.EntropyStrength128, extkeys.EnglishLanguage)
if err != nil { if err != nil {
return "", "", "", fmt.Errorf("can not create mnemonic seed: %v", err) return info, "", fmt.Errorf("can not create mnemonic seed: %v", err)
} }
// Generate extended master key (see BIP32) // Generate extended master key (see BIP32)
@ -66,16 +67,19 @@ func (m *Manager) CreateAccount(password string) (address, pubKey, mnemonic stri
// for expert users, to be able to add a passphrase to the generation of the seed. // for expert users, to be able to add a passphrase to the generation of the seed.
extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, "")) extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, ""))
if err != nil { if err != nil {
return "", "", "", fmt.Errorf("can not create master extended key: %v", err) return info, "", fmt.Errorf("can not create master extended key: %v", err)
} }
// import created key into account keystore // import created key into account keystore
address, pubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password) info.WalletAddress, info.WalletPubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password)
if err != nil { if err != nil {
return "", "", "", err return info, "", err
} }
return address, pubKey, mnemonic, nil info.ChatAddress = info.WalletAddress
info.ChatPubKey = info.WalletPubKey
return info, mnemonic, nil
} }
// CreateChildAccount creates sub-account for an account identified by parent address. // CreateChildAccount creates sub-account for an account identified by parent address.
@ -140,21 +144,25 @@ func (m *Manager) CreateChildAccount(parentAddress, password string) (address, p
// RecoverAccount re-creates master key using given details. // RecoverAccount re-creates master key using given details.
// Once master key is re-generated, it is inserted into keystore (if not already there). // Once master key is re-generated, it is inserted into keystore (if not already there).
func (m *Manager) RecoverAccount(password, mnemonic string) (address, pubKey string, err error) { func (m *Manager) RecoverAccount(password, mnemonic string) (Info, error) {
info := Info{}
// re-create extended key (see BIP32) // re-create extended key (see BIP32)
mn := extkeys.NewMnemonic() mn := extkeys.NewMnemonic()
extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, "")) extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, ""))
if err != nil { if err != nil {
return "", "", ErrInvalidMasterKeyCreated return info, ErrInvalidMasterKeyCreated
} }
// import re-created key into account keystore // import re-created key into account keystore
address, pubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password) info.WalletAddress, info.WalletPubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password)
if err != nil { if err != nil {
return return info, err
} }
return address, pubKey, nil info.ChatAddress = info.WalletAddress
info.ChatPubKey = info.WalletPubKey
return info, nil
} }
// VerifyAccountPassword tries to decrypt a given account key file, with a provided password. // VerifyAccountPassword tries to decrypt a given account key file, with a provided password.
@ -217,44 +225,22 @@ func (m *Manager) VerifyAccountPassword(keyStoreDir, address, password string) (
// SelectAccount selects current account, by verifying that address has corresponding account which can be decrypted // 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). // using provided password. Once verification is done, all previous identities are removed).
func (m *Manager) SelectAccount(address, password string) error { func (m *Manager) SelectAccount(walletAddress, chatAddress, password string) error {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
keyStore, err := m.geth.AccountKeyStore() selectedWalletAccount, err := m.unlockExtendedKey(walletAddress, password)
if err != nil { if err != nil {
return err return err
} }
account, err := ParseAccountString(address) selectedChatAccount, err := m.unlockExtendedKey(chatAddress, password)
if err != nil {
return ErrAddressToAccountMappingFailure
}
account, accountKey, err := keyStore.AccountDecryptedKey(account, password)
if err != nil {
return fmt.Errorf("%s: %v", ErrAccountToKeyMappingFailure.Error(), err)
}
// persist account key for easier recovery of currently selected key
subAccounts, err := m.findSubAccounts(accountKey.ExtendedKey, accountKey.SubAccountIndex)
if err != nil { if err != nil {
return err return err
} }
m.selectedWalletAccount = &SelectedExtKey{ m.selectedWalletAccount = selectedWalletAccount
Address: account.Address, m.selectedChatAccount = selectedChatAccount
AccountKey: accountKey,
SubAccounts: subAccounts,
}
// Before completely decoupling the wallet and chat keys,
// we have a selectedChatAccount with the same key used for the wallet.
m.selectedChatAccount = &SelectedExtKey{
Address: account.Address,
AccountKey: accountKey,
SubAccounts: subAccounts,
}
return nil return nil
} }
@ -428,5 +414,33 @@ func (m *Manager) AddressToDecryptedAccount(address, password string) (accounts.
return accounts.Account{}, nil, ErrAddressToAccountMappingFailure return accounts.Account{}, nil, ErrAddressToAccountMappingFailure
} }
return keyStore.AccountDecryptedKey(account, password) var key *keystore.Key
account, key, err = keyStore.AccountDecryptedKey(account, password)
if err != nil {
err = fmt.Errorf("%s: %s", ErrAccountToKeyMappingFailure, err)
}
return account, key, err
}
func (m *Manager) unlockExtendedKey(address, password string) (*SelectedExtKey, error) {
account, accountKey, err := m.AddressToDecryptedAccount(address, password)
if err != nil {
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,
}
return selectedExtendedKey, nil
} }

View File

@ -14,6 +14,7 @@ import (
gethcommon "github.com/ethereum/go-ethereum/common" gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
. "github.com/status-im/status-go/t/utils" . "github.com/status-im/status-go/t/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
@ -32,7 +33,7 @@ func TestVerifyAccountPassword(t *testing.T) {
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount1PKFile())) require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount1PKFile()))
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount2PKFile())) require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount2PKFile()))
account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.Address)) account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.WalletAddress))
testCases := []struct { testCases := []struct {
name string name string
@ -44,21 +45,21 @@ func TestVerifyAccountPassword(t *testing.T) {
{ {
"correct address, correct password (decrypt should succeed)", "correct address, correct password (decrypt should succeed)",
keyStoreDir, keyStoreDir,
TestConfig.Account1.Address, TestConfig.Account1.WalletAddress,
TestConfig.Account1.Password, TestConfig.Account1.Password,
nil, nil,
}, },
{ {
"correct address, correct password, non-existent key store", "correct address, correct password, non-existent key store",
filepath.Join(keyStoreDir, "non-existent-folder"), filepath.Join(keyStoreDir, "non-existent-folder"),
TestConfig.Account1.Address, TestConfig.Account1.WalletAddress,
TestConfig.Account1.Password, TestConfig.Account1.Password,
fmt.Errorf("cannot traverse key store folder: lstat %s/non-existent-folder: no such file or directory", keyStoreDir), fmt.Errorf("cannot traverse key store folder: lstat %s/non-existent-folder: no such file or directory", keyStoreDir),
}, },
{ {
"correct address, correct password, empty key store (pk is not there)", "correct address, correct password, empty key store (pk is not there)",
emptyKeyStoreDir, emptyKeyStoreDir,
TestConfig.Account1.Address, TestConfig.Account1.WalletAddress,
TestConfig.Account1.Password, TestConfig.Account1.Password,
fmt.Errorf("cannot locate account for address: %s", account1Address.Hex()), fmt.Errorf("cannot locate account for address: %s", account1Address.Hex()),
}, },
@ -72,7 +73,7 @@ func TestVerifyAccountPassword(t *testing.T) {
{ {
"correct address, wrong password", "correct address, wrong password",
keyStoreDir, keyStoreDir,
TestConfig.Account1.Address, TestConfig.Account1.WalletAddress,
"wrong password", // wrong password "wrong password", // wrong password
errors.New("could not decrypt key with given passphrase"), errors.New("could not decrypt key with given passphrase"),
}, },
@ -107,7 +108,7 @@ func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) {
accManager := NewManager(nil) accManager := NewManager(nil)
address := gethcommon.HexToAddress(TestConfig.Account3.Address) address := gethcommon.HexToAddress(TestConfig.Account3.WalletAddress)
_, err = accManager.VerifyAccountPassword(keyStoreDir, address.Hex(), TestConfig.Account3.Password) _, err = accManager.VerifyAccountPassword(keyStoreDir, address.Hex(), TestConfig.Account3.Password)
require.NoError(t, err) require.NoError(t, err)
} }
@ -130,17 +131,25 @@ func TestManagerTestSuite(t *testing.T) {
// Initial test - create test account // Initial test - create test account
gethServiceProvider.EXPECT().AccountKeyStore().Return(keyStore, nil) gethServiceProvider.EXPECT().AccountKeyStore().Return(keyStore, nil)
addr, pubKey, mnemonic, err := accManager.CreateAccount(testPassword) accountInfo, mnemonic, err := accManager.CreateAccount(testPassword)
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, addr) require.NotEmpty(t, accountInfo.WalletAddress)
require.NotEmpty(t, pubKey) require.NotEmpty(t, accountInfo.WalletPubKey)
require.NotEmpty(t, accountInfo.ChatAddress)
require.NotEmpty(t, accountInfo.ChatPubKey)
require.NotEmpty(t, mnemonic) require.NotEmpty(t, mnemonic)
// Before the complete decoupling of the keys, wallet and chat keys are the same
assert.Equal(t, accountInfo.WalletAddress, accountInfo.ChatAddress)
assert.Equal(t, accountInfo.WalletPubKey, accountInfo.ChatPubKey)
s := &ManagerTestSuite{ s := &ManagerTestSuite{
testAccount: testAccount{ testAccount: testAccount{
"test-password", "test-password",
addr, accountInfo.WalletAddress,
pubKey, accountInfo.WalletPubKey,
accountInfo.ChatAddress,
accountInfo.ChatPubKey,
mnemonic, mnemonic,
}, },
gethServiceProvider: gethServiceProvider, gethServiceProvider: gethServiceProvider,
@ -167,10 +176,12 @@ type ManagerTestSuite struct {
} }
type testAccount struct { type testAccount struct {
password string password string
address string walletAddress string
pubKey string walletPubKey string
mnemonic string chatAddress string
chatPubKey string
mnemonic string
} }
// reinitMock is for reassigning a new mock node manager to account manager. // reinitMock is for reassigning a new mock node manager to account manager.
@ -190,23 +201,25 @@ func (s *ManagerTestSuite) SetupTest() {
func (s *ManagerTestSuite) TestCreateAccount() { func (s *ManagerTestSuite) TestCreateAccount() {
// Don't fail on empty password // Don't fail on empty password
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil) s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil)
_, _, _, err := s.accManager.CreateAccount(s.password) _, _, err := s.accManager.CreateAccount(s.password)
s.NoError(err) s.NoError(err)
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(nil, errKeyStore) s.gethServiceProvider.EXPECT().AccountKeyStore().Return(nil, errKeyStore)
_, _, _, err = s.accManager.CreateAccount(s.password) _, _, err = s.accManager.CreateAccount(s.password)
s.Equal(errKeyStore, err) s.Equal(errKeyStore, err)
} }
func (s *ManagerTestSuite) TestRecoverAccount() { func (s *ManagerTestSuite) TestRecoverAccount() {
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil) s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil)
addr, pubKey, err := s.accManager.RecoverAccount(s.password, s.mnemonic) accountInfo, err := s.accManager.RecoverAccount(s.password, s.mnemonic)
s.NoError(err) s.NoError(err)
s.Equal(s.address, addr) s.Equal(s.walletAddress, accountInfo.WalletAddress)
s.Equal(s.pubKey, pubKey) s.Equal(s.walletPubKey, accountInfo.WalletPubKey)
s.Equal(s.chatAddress, accountInfo.ChatAddress)
s.Equal(s.chatPubKey, accountInfo.ChatPubKey)
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(nil, errKeyStore) s.gethServiceProvider.EXPECT().AccountKeyStore().Return(nil, errKeyStore)
_, _, err = s.accManager.RecoverAccount(s.password, s.mnemonic) _, err = s.accManager.RecoverAccount(s.password, s.mnemonic)
s.Equal(errKeyStore, err) s.Equal(errKeyStore, err)
} }
@ -214,35 +227,48 @@ func (s *ManagerTestSuite) TestSelectAccount() {
testCases := []struct { testCases := []struct {
name string name string
accountKeyStoreReturn []interface{} accountKeyStoreReturn []interface{}
address string walletAddress string
chatAddress string
password string password string
expectedError error expectedError error
}{ }{
{ {
"success", "success",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
s.address, s.walletAddress,
s.chatAddress,
s.password, s.password,
nil, nil,
}, },
{ {
"fail_keyStore", "fail_keyStore",
[]interface{}{nil, errKeyStore}, []interface{}{nil, errKeyStore},
s.address, s.walletAddress,
s.chatAddress,
s.password, s.password,
errKeyStore, errKeyStore,
}, },
{ {
"fail_wrongAddress", "fail_wrongWalletAddress",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
"wrong-address", "wrong-wallet-address",
s.chatAddress,
s.password,
ErrAddressToAccountMappingFailure,
},
{
"fail_wrongChatAddress",
[]interface{}{s.keyStore, nil},
s.walletAddress,
"wrong-chat-address",
s.password, s.password,
ErrAddressToAccountMappingFailure, ErrAddressToAccountMappingFailure,
}, },
{ {
"fail_wrongPassword", "fail_wrongPassword",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
s.address, s.walletAddress,
s.chatAddress,
"wrong-password", "wrong-password",
errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"), errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"),
}, },
@ -252,15 +278,24 @@ func (s *ManagerTestSuite) TestSelectAccount() {
s.T().Run(testCase.name, func(t *testing.T) { s.T().Run(testCase.name, func(t *testing.T) {
s.reinitMock() s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes()
err := s.accManager.SelectAccount(testCase.address, testCase.password) err := s.accManager.SelectAccount(testCase.walletAddress, testCase.chatAddress, testCase.password)
s.Equal(testCase.expectedError, err) s.Equal(testCase.expectedError, err)
selectedWalletAccount, err := s.accManager.SelectedWalletAccount() selectedWalletAccount, walletErr := s.accManager.SelectedWalletAccount()
s.NoError(err) selectedChatAccount, chatErr := s.accManager.SelectedChatAccount()
selectedChatAccount, err := s.accManager.SelectedChatAccount()
s.NoError(err)
s.Equal(selectedWalletAccount.AccountKey, selectedChatAccount.AccountKey) if testCase.expectedError == nil {
s.Equal(selectedWalletAccount.AccountKey, selectedChatAccount.AccountKey)
s.NoError(walletErr)
s.NoError(chatErr)
} else {
s.Nil(selectedWalletAccount)
s.Nil(selectedChatAccount)
s.Equal(walletErr, ErrNoAccountSelected)
s.Equal(chatErr, ErrNoAccountSelected)
}
s.accManager.Logout()
}) })
} }
} }
@ -278,40 +313,45 @@ func (s *ManagerTestSuite) TestCreateChildAccount() {
// Now, select the test account for rest of the test cases. // Now, select the test account for rest of the test cases.
s.reinitMock() s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes()
err := s.accManager.SelectAccount(s.address, s.password) err := s.accManager.SelectAccount(s.walletAddress, s.chatAddress, s.password)
s.NoError(err) s.NoError(err)
testCases := []struct { testCases := []struct {
name string name string
address string walletAddress string
chatAddress string
password string password string
accountKeyStoreReturn []interface{} accountKeyStoreReturn []interface{}
expectedError error expectedError error
}{ }{
{ {
"success", "success",
s.address, s.walletAddress,
s.chatAddress,
s.password, s.password,
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
nil, nil,
}, },
{ {
"fail_keyStore", "fail_keyStore",
s.address, s.walletAddress,
s.chatAddress,
s.password, s.password,
[]interface{}{nil, errKeyStore}, []interface{}{nil, errKeyStore},
errKeyStore, errKeyStore,
}, },
{ {
"fail_wrongAddress", "fail_wrongWalletAddress",
"wrong-address", "wrong-address",
s.chatAddress,
s.password, s.password,
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
ErrAddressToAccountMappingFailure, ErrAddressToAccountMappingFailure,
}, },
{ {
"fail_wrongPassword", "fail_wrongPassword",
s.address, s.walletAddress,
s.chatAddress,
"wrong-password", "wrong-password",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"), errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"),
@ -322,7 +362,7 @@ func (s *ManagerTestSuite) TestCreateChildAccount() {
s.T().Run(testCase.name, func(t *testing.T) { s.T().Run(testCase.name, func(t *testing.T) {
s.reinitMock() s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes()
childAddr, childPubKey, err := s.accManager.CreateChildAccount(testCase.address, testCase.password) childAddr, childPubKey, err := s.accManager.CreateChildAccount(testCase.walletAddress, testCase.password)
if testCase.expectedError != nil { if testCase.expectedError != nil {
s.Equal(testCase.expectedError, err) s.Equal(testCase.expectedError, err)
} else { } else {
@ -343,7 +383,7 @@ func (s *ManagerTestSuite) TestLogout() {
func (s *ManagerTestSuite) TestAccounts() { func (s *ManagerTestSuite) TestAccounts() {
// Select the test account // Select the test account
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil).AnyTimes()
err := s.accManager.SelectAccount(s.address, s.password) err := s.accManager.SelectAccount(s.walletAddress, s.chatAddress, s.password)
s.NoError(err) s.NoError(err)
// Success // Success
@ -369,37 +409,37 @@ func (s *ManagerTestSuite) TestAddressToDecryptedAccount() {
testCases := []struct { testCases := []struct {
name string name string
accountKeyStoreReturn []interface{} accountKeyStoreReturn []interface{}
address string walletAddress string
password string password string
expectedError error expectedError error
}{ }{
{ {
"success", "success",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
s.address, s.walletAddress,
s.password, s.password,
nil, nil,
}, },
{ {
"fail_keyStore", "fail_keyStore",
[]interface{}{nil, errKeyStore}, []interface{}{nil, errKeyStore},
s.address, s.walletAddress,
s.password, s.password,
errKeyStore, errKeyStore,
}, },
{ {
"fail_wrongAddress", "fail_wrongWalletAddress",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
"wrong-address", "wrong-wallet-address",
s.password, s.password,
ErrAddressToAccountMappingFailure, ErrAddressToAccountMappingFailure,
}, },
{ {
"fail_wrongPassword", "fail_wrongPassword",
[]interface{}{s.keyStore, nil}, []interface{}{s.keyStore, nil},
s.address, s.walletAddress,
"wrong-password", "wrong-password",
errors.New("could not decrypt key with given passphrase"), errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"),
}, },
} }
@ -407,7 +447,7 @@ func (s *ManagerTestSuite) TestAddressToDecryptedAccount() {
s.T().Run(testCase.name, func(t *testing.T) { s.T().Run(testCase.name, func(t *testing.T) {
s.reinitMock() s.reinitMock()
s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes()
acc, key, err := s.accManager.AddressToDecryptedAccount(testCase.address, testCase.password) acc, key, err := s.accManager.AddressToDecryptedAccount(testCase.walletAddress, testCase.password)
if testCase.expectedError != nil { if testCase.expectedError != nil {
s.Equal(testCase.expectedError, err) s.Equal(testCase.expectedError, err)
} else { } else {

View File

@ -13,6 +13,14 @@ var (
ErrInvalidAccountAddressOrKey = errors.New("cannot parse address or key to valid account address") ErrInvalidAccountAddressOrKey = errors.New("cannot parse address or key to valid account address")
) )
// Info contains wallet and chat addresses and public keys of an account.
type Info struct {
WalletAddress string
WalletPubKey string
ChatAddress string
ChatPubKey string
}
// SelectedExtKey is a container for the selected (logged in) external account. // SelectedExtKey is a container for the selected (logged in) external account.
type SelectedExtKey struct { type SelectedExtKey struct {
Address common.Address Address common.Address

View File

@ -422,17 +422,18 @@ func (b *StatusBackend) reSelectAccount() error {
return nil return nil
} }
// SelectAccount selects current account, by verifying that address has corresponding account which can be decrypted // 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, decrypted key is injected into Whisper (as a single identity, // using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity,
// all previous identities are removed). // all previous identities are removed).
func (b *StatusBackend) SelectAccount(address, password string) error { func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password string) error {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
err := b.accountManager.SelectAccount(address, password) err := b.accountManager.SelectAccount(walletAddress, chatAddress, password)
if err != nil { if err != nil {
return err return err
} }
chatAccount, err := b.accountManager.SelectedChatAccount() chatAccount, err := b.accountManager.SelectedChatAccount()
if err != nil { if err != nil {
return err return err
@ -455,7 +456,7 @@ func (b *StatusBackend) SelectAccount(address, password string) error {
return err return err
} }
if err := st.InitProtocol(address, password); err != nil { if err := st.InitProtocol(chatAddress, password); err != nil {
return err return err
} }
} }

View File

@ -138,15 +138,15 @@ func TestBackendAccountsConcurrently(t *testing.T) {
var wgCreateAccounts sync.WaitGroup var wgCreateAccounts sync.WaitGroup
count := 3 count := 3
addressCh := make(chan [2]string, count) // use buffered channel to avoid blocking addressCh := make(chan [3]string, count) // use buffered channel to avoid blocking
// create new accounts concurrently // create new accounts concurrently
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
wgCreateAccounts.Add(1) wgCreateAccounts.Add(1)
go func(pass string) { go func(pass string) {
address, _, _, err := backend.AccountManager().CreateAccount(pass) accountInfo, _, err := backend.AccountManager().CreateAccount(pass)
assert.NoError(t, err) assert.NoError(t, err)
addressCh <- [...]string{address, pass} addressCh <- [...]string{accountInfo.WalletAddress, accountInfo.ChatAddress, pass}
wgCreateAccounts.Done() wgCreateAccounts.Done()
}("password-00" + string(i)) }("password-00" + string(i))
} }
@ -159,8 +159,8 @@ func TestBackendAccountsConcurrently(t *testing.T) {
for tuple := range addressCh { for tuple := range addressCh {
wg.Add(1) wg.Add(1)
go func(tuple [2]string) { go func(tuple [3]string) {
assert.NoError(t, backend.SelectAccount(tuple[0], tuple[1])) assert.NoError(t, backend.SelectAccount(tuple[0], tuple[1], tuple[2]))
wg.Done() wg.Done()
}(tuple) }(tuple)

View File

@ -246,7 +246,7 @@ func CallPrivateRPC(inputJSON *C.char) *C.char {
// just modified to handle the function arg passing // just modified to handle the function arg passing
//export CreateAccount //export CreateAccount
func CreateAccount(password *C.char) *C.char { func CreateAccount(password *C.char) *C.char {
address, pubKey, mnemonic, err := statusBackend.AccountManager().CreateAccount(C.GoString(password)) info, mnemonic, err := statusBackend.AccountManager().CreateAccount(C.GoString(password))
errString := "" errString := ""
if err != nil { if err != nil {
@ -255,10 +255,14 @@ func CreateAccount(password *C.char) *C.char {
} }
out := AccountInfo{ out := AccountInfo{
Address: address, Address: info.WalletAddress,
PubKey: pubKey, PubKey: info.WalletPubKey,
Mnemonic: mnemonic, WalletAddress: info.WalletAddress,
Error: errString, WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: mnemonic,
Error: errString,
} }
outBytes, _ := json.Marshal(out) outBytes, _ := json.Marshal(out)
return C.CString(string(outBytes)) return C.CString(string(outBytes))
@ -287,7 +291,7 @@ func CreateChildAccount(parentAddress, password *C.char) *C.char {
//RecoverAccount re-creates master key using given details //RecoverAccount re-creates master key using given details
//export RecoverAccount //export RecoverAccount
func RecoverAccount(password, mnemonic *C.char) *C.char { func RecoverAccount(password, mnemonic *C.char) *C.char {
address, pubKey, err := statusBackend.AccountManager().RecoverAccount(C.GoString(password), C.GoString(mnemonic)) info, err := statusBackend.AccountManager().RecoverAccount(C.GoString(password), C.GoString(mnemonic))
errString := "" errString := ""
if err != nil { if err != nil {
@ -296,10 +300,14 @@ func RecoverAccount(password, mnemonic *C.char) *C.char {
} }
out := AccountInfo{ out := AccountInfo{
Address: address, Address: info.WalletAddress,
PubKey: pubKey, PubKey: info.WalletPubKey,
Mnemonic: C.GoString(mnemonic), WalletAddress: info.WalletAddress,
Error: errString, WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: C.GoString(mnemonic),
Error: errString,
} }
outBytes, _ := json.Marshal(out) outBytes, _ := json.Marshal(out)
return C.CString(string(outBytes)) return C.CString(string(outBytes))
@ -316,7 +324,7 @@ func VerifyAccountPassword(keyStoreDir, address, password *C.char) *C.char {
// if verified, purges all the previous identities from Whisper, and injects verified key as shh identity // if verified, purges all the previous identities from Whisper, and injects verified key as shh identity
//export Login //export Login
func Login(address, password *C.char) *C.char { func Login(address, password *C.char) *C.char {
err := statusBackend.SelectAccount(C.GoString(address), C.GoString(password)) err := statusBackend.SelectAccount(C.GoString(address), C.GoString(address), C.GoString(password))
return makeJSONResponse(err) return makeJSONResponse(err)
} }

View File

@ -26,13 +26,11 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
gethcommon "github.com/ethereum/go-ethereum/common" gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/signal" "github.com/status-im/status-go/signal"
. "github.com/status-im/status-go/t/utils" //nolint: golint . "github.com/status-im/status-go/t/utils" //nolint: golint
"github.com/status-im/status-go/transactions" "github.com/status-im/status-go/transactions"
"github.com/stretchr/testify/require"
) )
const initJS = ` const initJS = `
@ -169,7 +167,7 @@ func testVerifyAccountPassword(t *testing.T) bool {
// rename account file (to see that file's internals reviewed, when locating account key) // rename account file (to see that file's internals reviewed, when locating account key)
accountFilePathOriginal := filepath.Join(tmpDir, GetAccount1PKFile()) accountFilePathOriginal := filepath.Join(tmpDir, GetAccount1PKFile())
accountFilePath := filepath.Join(tmpDir, "foo"+TestConfig.Account1.Address+"bar.pk") accountFilePath := filepath.Join(tmpDir, "foo"+TestConfig.Account1.WalletAddress+"bar.pk")
if err := os.Rename(accountFilePathOriginal, accountFilePath); err != nil { if err := os.Rename(accountFilePathOriginal, accountFilePath); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -177,7 +175,7 @@ func testVerifyAccountPassword(t *testing.T) bool {
response := APIResponse{} response := APIResponse{}
rawResponse := VerifyAccountPassword( rawResponse := VerifyAccountPassword(
C.CString(tmpDir), C.CString(tmpDir),
C.CString(TestConfig.Account1.Address), C.CString(TestConfig.Account1.WalletAddress),
C.CString(TestConfig.Account1.Password)) C.CString(TestConfig.Account1.Password))
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil { if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
@ -227,21 +225,21 @@ func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo
} }
// create an account // create an account
address1, pubKey1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) account1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("could not create account: %v", err) t.Errorf("could not create account: %v", err)
return false return false
} }
t.Logf("account created: {address: %s, key: %s}", address1, pubKey1) t.Logf("account created: {address: %s, key: %s}", account1.WalletAddress, account1.WalletPubKey)
// make sure that identity is not (yet injected) // make sure that identity is not (yet injected)
if whisperService.HasKeyPair(pubKey1) { if whisperService.HasKeyPair(account1.ChatPubKey) {
t.Error("identity already present in whisper") t.Error("identity already present in whisper")
} }
// select account // select account
loginResponse := APIResponse{} loginResponse := APIResponse{}
rawResponse := Login(C.CString(address1), C.CString(TestConfig.Account1.Password)) rawResponse := Login(C.CString(account1.WalletAddress), C.CString(TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err) t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -252,7 +250,7 @@ func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo
t.Errorf("could not select account: %v", err) t.Errorf("could not select account: %v", err)
return false return false
} }
if !whisperService.HasKeyPair(pubKey1) { if !whisperService.HasKeyPair(account1.ChatPubKey) {
t.Errorf("identity not injected into whisper: %v", err) t.Errorf("identity not injected into whisper: %v", err)
} }
@ -312,7 +310,7 @@ func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo
if err != nil { if err != nil {
t.Errorf("whisper service not running: %v", err) t.Errorf("whisper service not running: %v", err)
} }
if !whisperService.HasKeyPair(pubKey1) { if !whisperService.HasKeyPair(account1.ChatPubKey) {
t.Errorf("identity evicted from whisper on node restart: %v", err) t.Errorf("identity evicted from whisper on node restart: %v", err)
} }
@ -382,10 +380,17 @@ func testCreateChildAccount(t *testing.T) bool { //nolint: gocyclo
t.Errorf("could not create account: %s", err) t.Errorf("could not create account: %s", err)
return false return false
} }
address, pubKey, mnemonic := createAccountResponse.Address, createAccountResponse.PubKey, createAccountResponse.Mnemonic
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic)
acct, err := account.ParseAccountString(address) 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 { if err != nil {
t.Errorf("can not get account from address: %v", err) t.Errorf("can not get account from address: %v", err)
return false return false
@ -417,7 +422,7 @@ func testCreateChildAccount(t *testing.T) bool { //nolint: gocyclo
return false return false
} }
err = statusBackend.SelectAccount(address, TestConfig.Account1.Password) err = statusBackend.SelectAccount(walletAddress, chatAddress, TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("Test failed: could not select account: %v", err) t.Errorf("Test failed: could not select account: %v", err)
return false return false
@ -497,12 +502,12 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
keyStore, _ := statusBackend.StatusNode().AccountKeyStore() keyStore, _ := statusBackend.StatusNode().AccountKeyStore()
// create an account // create an account
address, pubKey, mnemonic, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, mnemonic, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("could not create account: %v", err) t.Errorf("could not create account: %v", err)
return false return false
} }
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", accountInfo.WalletAddress, accountInfo.WalletPubKey, mnemonic)
// try recovering using password + mnemonic // try recovering using password + mnemonic
recoverAccountResponse := AccountInfo{} recoverAccountResponse := AccountInfo{}
@ -517,13 +522,25 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
t.Errorf("recover account failed: %v", recoverAccountResponse.Error) t.Errorf("recover account failed: %v", recoverAccountResponse.Error)
return false return false
} }
addressCheck, pubKeyCheck := recoverAccountResponse.Address, recoverAccountResponse.PubKey
if address != addressCheck || pubKey != pubKeyCheck { if recoverAccountResponse.Address != recoverAccountResponse.WalletAddress ||
t.Error("recover account details failed to pull the correct details") recoverAccountResponse.PubKey != recoverAccountResponse.WalletPubKey {
t.Error("for backward compatibility pubkey/address should be equal to walletAddress/walletPubKey")
}
walletAddressCheck, walletPubKeyCheck := recoverAccountResponse.Address, recoverAccountResponse.PubKey
chatAddressCheck, chatPubKeyCheck := recoverAccountResponse.ChatAddress, recoverAccountResponse.ChatPubKey
if accountInfo.WalletAddress != walletAddressCheck || accountInfo.WalletPubKey != walletPubKeyCheck {
t.Error("recover wallet account details failed to pull the correct details")
}
if accountInfo.ChatAddress != chatAddressCheck || accountInfo.ChatPubKey != chatPubKeyCheck {
t.Error("recover chat account details failed to pull the correct details")
} }
// now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device // now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device
account, err := account.ParseAccountString(address) account, err := account.ParseAccountString(accountInfo.WalletAddress)
if err != nil { if err != nil {
t.Errorf("can not get account from address: %v", err) t.Errorf("can not get account from address: %v", err)
} }
@ -551,9 +568,14 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error) t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
return false return false
} }
addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey walletAddressCheck, walletPubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey
if address != addressCheck || pubKey != pubKeyCheck { if accountInfo.WalletAddress != walletAddressCheck || accountInfo.WalletPubKey != walletPubKeyCheck {
t.Error("recover account details failed to pull the correct details (for non-cached account)") t.Error("recover wallet account details failed to pull the correct details (for non-cached account)")
}
chatAddressCheck, chatPubKeyCheck = recoverAccountResponse.ChatAddress, recoverAccountResponse.ChatPubKey
if accountInfo.ChatAddress != chatAddressCheck || accountInfo.ChatPubKey != chatPubKeyCheck {
t.Error("recover chat account details failed to pull the correct details (for non-cached account)")
} }
// make sure that extended key exists and is imported ok too // make sure that extended key exists and is imported ok too
@ -579,9 +601,14 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error) t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
return false return false
} }
addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey walletAddressCheck, walletPubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey
if address != addressCheck || pubKey != pubKeyCheck { if accountInfo.WalletAddress != walletAddressCheck || accountInfo.WalletPubKey != walletPubKeyCheck {
t.Error("recover account details failed to pull the correct details (for non-cached account)") t.Error("recover wallet account details failed to pull the correct details (for non-cached account)")
}
chatAddressCheck, chatPubKeyCheck = recoverAccountResponse.ChatAddress, recoverAccountResponse.ChatPubKey
if accountInfo.ChatAddress != chatAddressCheck || accountInfo.ChatPubKey != chatPubKeyCheck {
t.Error("recover chat account details failed to pull the correct details (for non-cached account)")
} }
// time to login with recovered data // time to login with recovered data
@ -591,15 +618,15 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
} }
// make sure that identity is not (yet injected) // make sure that identity is not (yet injected)
if whisperService.HasKeyPair(pubKeyCheck) { if whisperService.HasKeyPair(chatPubKeyCheck) {
t.Error("identity already present in whisper") t.Error("identity already present in whisper")
} }
err = statusBackend.SelectAccount(addressCheck, TestConfig.Account1.Password) err = statusBackend.SelectAccount(walletAddressCheck, chatAddressCheck, TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("Test failed: could not select account: %v", err) t.Errorf("Test failed: could not select account: %v", err)
return false return false
} }
if !whisperService.HasKeyPair(pubKeyCheck) { if !whisperService.HasKeyPair(chatPubKeyCheck) {
t.Errorf("identity not injected into whisper: %v", err) t.Errorf("identity not injected into whisper: %v", err)
} }
@ -614,28 +641,28 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
} }
// create an account // create an account
address1, pubKey1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("could not create account: %v", err) t.Errorf("could not create account: %v", err)
return false return false
} }
t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1) t.Logf("Account created: {address: %s, key: %s}", accountInfo1.WalletAddress, accountInfo1.WalletPubKey)
address2, pubKey2, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo2, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Error("Test failed: could not create account") t.Error("Test failed: could not create account")
return false return false
} }
t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2) t.Logf("Account created: {address: %s, key: %s}", accountInfo2.WalletAddress, accountInfo2.WalletPubKey)
// make sure that identity is not (yet injected) // make sure that identity is not (yet injected)
if whisperService.HasKeyPair(pubKey1) { if whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
t.Error("identity already present in whisper") t.Error("identity already present in whisper")
} }
// try selecting with wrong password // try selecting with wrong password
loginResponse := APIResponse{} loginResponse := APIResponse{}
rawResponse := Login(C.CString(address1), C.CString("wrongPassword")) rawResponse := Login(C.CString(accountInfo1.WalletAddress), C.CString("wrongPassword"))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err) t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -648,7 +675,7 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
} }
loginResponse = APIResponse{} loginResponse = APIResponse{}
rawResponse = Login(C.CString(address1), C.CString(TestConfig.Account1.Password)) rawResponse = Login(C.CString(accountInfo1.WalletAddress), C.CString(TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err) t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -659,17 +686,17 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
t.Errorf("Test failed: could not select account: %v", err) t.Errorf("Test failed: could not select account: %v", err)
return false return false
} }
if !whisperService.HasKeyPair(pubKey1) { if !whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
t.Errorf("identity not injected into whisper: %v", err) t.Errorf("identity not injected into whisper: %v", err)
} }
// select another account, make sure that previous account is wiped out from Whisper cache // select another account, make sure that previous account is wiped out from Whisper cache
if whisperService.HasKeyPair(pubKey2) { if whisperService.HasKeyPair(accountInfo2.ChatPubKey) {
t.Error("identity already present in whisper") t.Error("identity already present in whisper")
} }
loginResponse = APIResponse{} loginResponse = APIResponse{}
rawResponse = Login(C.CString(address2), C.CString(TestConfig.Account1.Password)) rawResponse = Login(C.CString(accountInfo2.WalletAddress), C.CString(TestConfig.Account1.Password))
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err) t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
@ -680,10 +707,10 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
t.Errorf("Test failed: could not select account: %v", loginResponse.Error) t.Errorf("Test failed: could not select account: %v", loginResponse.Error)
return false return false
} }
if !whisperService.HasKeyPair(pubKey2) { if !whisperService.HasKeyPair(accountInfo2.ChatPubKey) {
t.Errorf("identity not injected into whisper: %v", err) t.Errorf("identity not injected into whisper: %v", err)
} }
if whisperService.HasKeyPair(pubKey1) { if whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
t.Error("identity should be removed, but it is still present in whisper") t.Error("identity should be removed, but it is still present in whisper")
} }
@ -698,25 +725,25 @@ func testAccountLogout(t *testing.T) bool {
} }
// create an account // create an account
address, pubKey, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("could not create account: %v", err) t.Errorf("could not create account: %v", err)
return false return false
} }
// make sure that identity doesn't exist (yet) in Whisper // make sure that identity doesn't exist (yet) in Whisper
if whisperService.HasKeyPair(pubKey) { if whisperService.HasKeyPair(accountInfo.ChatPubKey) {
t.Error("identity already present in whisper") t.Error("identity already present in whisper")
return false return false
} }
// select/login // select/login
err = statusBackend.SelectAccount(address, TestConfig.Account1.Password) err = statusBackend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)
if err != nil { if err != nil {
t.Errorf("Test failed: could not select account: %v", err) t.Errorf("Test failed: could not select account: %v", err)
return false return false
} }
if !whisperService.HasKeyPair(pubKey) { if !whisperService.HasKeyPair(accountInfo.ChatPubKey) {
t.Error("identity not injected into whisper") t.Error("identity not injected into whisper")
return false return false
} }
@ -735,7 +762,7 @@ func testAccountLogout(t *testing.T) bool {
} }
// now, logout and check if identity is removed indeed // now, logout and check if identity is removed indeed
if whisperService.HasKeyPair(pubKey) { if whisperService.HasKeyPair(accountInfo.ChatPubKey) {
t.Error("identity not cleared from whisper") t.Error("identity not cleared from whisper")
return false return false
} }
@ -752,14 +779,14 @@ func testSendTransaction(t *testing.T) bool {
EnsureNodeSync(statusBackend.StatusNode().EnsureSync) EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
// log into account from which transactions will be sent // log into account from which transactions will be sent
if err := statusBackend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password); err != nil { if err := statusBackend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.Address, err) t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
return false return false
} }
args, err := json.Marshal(transactions.SendTxArgs{ args, err := json.Marshal(transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Value: (*hexutil.Big)(big.NewInt(1000000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)),
}) })
if err != nil { if err != nil {
@ -791,16 +818,17 @@ func testSendTransactionInvalidPassword(t *testing.T) bool {
// log into account from which transactions will be sent // log into account from which transactions will be sent
if err := statusBackend.SelectAccount( if err := statusBackend.SelectAccount(
TestConfig.Account1.Address, TestConfig.Account1.WalletAddress,
TestConfig.Account1.ChatAddress,
TestConfig.Account1.Password, TestConfig.Account1.Password,
); err != nil { ); err != nil {
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.Address, err) t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
return false return false
} }
args, err := json.Marshal(transactions.SendTxArgs{ args, err := json.Marshal(transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Value: (*hexutil.Big)(big.NewInt(1000000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)),
}) })
if err != nil { if err != nil {
@ -826,14 +854,14 @@ func testFailedTransaction(t *testing.T) bool {
EnsureNodeSync(statusBackend.StatusNode().EnsureSync) EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
// log into wrong account in order to get selectedAccount error // log into wrong account in order to get selectedAccount error
if err := statusBackend.SelectAccount(TestConfig.Account2.Address, TestConfig.Account2.Password); err != nil { 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.Address, err) t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
return false return false
} }
args, err := json.Marshal(transactions.SendTxArgs{ args, err := json.Marshal(transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Value: (*hexutil.Big)(big.NewInt(1000000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)),
}) })
if err != nil { if err != nil {

View File

@ -64,10 +64,14 @@ func (e APIError) Error() string {
// AccountInfo represents account's info. // AccountInfo represents account's info.
type AccountInfo struct { type AccountInfo struct {
Address string `json:"address"` Address string `json:"address"` // DEPRECATED
PubKey string `json:"pubkey"` PubKey string `json:"pubkey"` // DEPRECATED
Mnemonic string `json:"mnemonic"` WalletAddress string `json:"walletAddress"`
Error string `json:"error"` WalletPubKey string `json:"walletPubKey"`
ChatAddress string `json:"chatAddress"`
ChatPubKey string `json:"chatPubKey"`
Mnemonic string `json:"mnemonic"`
Error string `json:"error"`
} }
// NotifyResult is a JSON returned from notify message. // NotifyResult is a JSON returned from notify message.

View File

@ -10,9 +10,8 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/params"
gethrpc "github.com/ethereum/go-ethereum/rpc" gethrpc "github.com/ethereum/go-ethereum/rpc"
"github.com/status-im/status-go/params"
) )
const ( const (

View File

@ -9,6 +9,7 @@ import (
accounts "github.com/ethereum/go-ethereum/accounts" accounts "github.com/ethereum/go-ethereum/accounts"
keystore "github.com/ethereum/go-ethereum/accounts/keystore" keystore "github.com/ethereum/go-ethereum/accounts/keystore"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
account "github.com/status-im/status-go/account"
reflect "reflect" reflect "reflect"
) )
@ -90,28 +91,27 @@ func (mr *MockAccountManagerMockRecorder) AddressToDecryptedAccount(arg0, arg1 i
} }
// SelectAccount mocks base method // SelectAccount mocks base method
func (m *MockAccountManager) SelectAccount(address, password string) error { func (m *MockAccountManager) SelectAccount(walletAddress, chatAddress, password string) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SelectAccount", address, password) ret := m.ctrl.Call(m, "SelectAccount", walletAddress, chatAddress, password)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// SelectAccount indicates an expected call of SelectAccount // SelectAccount indicates an expected call of SelectAccount
func (mr *MockAccountManagerMockRecorder) SelectAccount(address, password interface{}) *gomock.Call { func (mr *MockAccountManagerMockRecorder) SelectAccount(walletAddress, chatAddress, password interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAccount", reflect.TypeOf((*MockAccountManager)(nil).SelectAccount), address, password) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAccount", reflect.TypeOf((*MockAccountManager)(nil).SelectAccount), walletAddress, chatAddress, password)
} }
// CreateAccount mocks base method // CreateAccount mocks base method
func (m *MockAccountManager) CreateAccount(password string) (string, string, string, error) { func (m *MockAccountManager) CreateAccount(password string) (account.Info, string, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateAccount", password) ret := m.ctrl.Call(m, "CreateAccount", password)
ret0, _ := ret[0].(string) ret0, _ := ret[0].(account.Info)
ret1, _ := ret[1].(string) ret1, _ := ret[1].(string)
ret2, _ := ret[2].(string) ret2, _ := ret[2].(error)
ret3, _ := ret[3].(error) return ret0, ret1, ret2
return ret0, ret1, ret2, ret3
} }
// CreateAccount indicates an expected call of CreateAccount // CreateAccount indicates an expected call of CreateAccount

View File

@ -40,7 +40,7 @@ func (api *PublicAPI) Login(context context.Context, req LoginRequest) (res Logi
return return
} }
if err = api.s.am.SelectAccount(req.Addr, req.Password); err != nil { if err = api.s.am.SelectAccount(req.Addr, req.Addr, req.Password); err != nil {
return return
} }
@ -54,18 +54,31 @@ type SignupRequest struct {
// SignupResponse : json response returned by status_signup. // SignupResponse : json response returned by status_signup.
type SignupResponse struct { type SignupResponse struct {
Address string `json:"address"` Address string `json:"address"`
Pubkey string `json:"pubkey"` Pubkey string `json:"pubkey"`
Mnemonic string `json:"mnemonic"` WalletAddress string `json:"walletAddress"`
WalletPubkey string `json:"walletPubKey"`
ChatAddress string `json:"chatAddress"`
ChatPubkey string `json:"chatPubkey"`
Mnemonic string `json:"mnemonic"`
} }
// Signup is an implementation of `status_signup` or `web3.status.signup` API // Signup is an implementation of `status_signup` or `web3.status.signup` API
func (api *PublicAPI) Signup(context context.Context, req SignupRequest) (res SignupResponse, err error) { func (api *PublicAPI) Signup(context context.Context, req SignupRequest) (res SignupResponse, err error) {
if res.Address, res.Pubkey, res.Mnemonic, err = api.s.am.CreateAccount(req.Password); err != nil { accountInfo, mnemonic, err := api.s.am.CreateAccount(req.Password)
if err != nil {
err = errors.New("could not create the specified account : " + err.Error()) err = errors.New("could not create the specified account : " + err.Error())
return return
} }
res.Address = accountInfo.WalletAddress
res.Pubkey = accountInfo.WalletPubKey
res.WalletAddress = accountInfo.WalletAddress
res.WalletPubkey = accountInfo.WalletPubKey
res.ChatAddress = accountInfo.ChatAddress
res.ChatPubkey = accountInfo.ChatPubKey
res.Mnemonic = mnemonic
return return
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/status-im/status-go/account"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
@ -49,7 +50,7 @@ var logintests = []struct {
} }
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil) s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil)
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("addressKey", nil) s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("addressKey", nil)
s.am.EXPECT().SelectAccount("address...", "password").Return(nil) s.am.EXPECT().SelectAccount("address...", "address...", "password").Return(nil)
}, },
}, },
{ {
@ -85,7 +86,7 @@ var logintests = []struct {
} }
s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil) s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, nil)
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", nil) s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", nil)
s.am.EXPECT().SelectAccount("address...", "password").Return(errors.New("foo")) s.am.EXPECT().SelectAccount("address...", "address...", "password").Return(errors.New("foo"))
}, },
}, },
} }
@ -112,25 +113,31 @@ var signuptests = []struct {
{ {
name: "success signup", name: "success signup",
expectedResponse: SignupResponse{ expectedResponse: SignupResponse{
Address: "addr", WalletAddress: "addr",
Pubkey: "pubkey", WalletPubkey: "pubkey",
Mnemonic: "mnemonic", Mnemonic: "mnemonic",
}, },
expectedError: nil, expectedError: nil,
prepareExpectations: func(s *StatusSuite) { prepareExpectations: func(s *StatusSuite) {
s.am.EXPECT().CreateAccount("password").Return("addr", "pubkey", "mnemonic", nil) accountInfo := account.Info{
WalletAddress: "addr",
WalletPubKey: "pubkey",
ChatAddress: "addr",
ChatPubKey: "pubkey",
}
s.am.EXPECT().CreateAccount("password").Return(accountInfo, "mnemonic", nil)
}, },
}, },
{ {
name: "success signup", name: "success signup",
expectedResponse: SignupResponse{ expectedResponse: SignupResponse{
Address: "", WalletAddress: "",
Pubkey: "", WalletPubkey: "",
Mnemonic: "", Mnemonic: "",
}, },
expectedError: errors.New("could not create the specified account : foo"), expectedError: errors.New("could not create the specified account : foo"),
prepareExpectations: func(s *StatusSuite) { prepareExpectations: func(s *StatusSuite) {
s.am.EXPECT().CreateAccount("password").Return("", "", "", errors.New("foo")) s.am.EXPECT().CreateAccount("password").Return(account.Info{}, "", errors.New("foo"))
}, },
}, },
} }
@ -141,8 +148,8 @@ func (s *StatusSuite) TestSignup() {
var ctx context.Context var ctx context.Context
res, err := s.api.Signup(ctx, SignupRequest{Password: "password"}) res, err := s.api.Signup(ctx, SignupRequest{Password: "password"})
s.Equal(t.expectedResponse.Address, res.Address, "failed scenario : "+t.name) s.Equal(t.expectedResponse.WalletAddress, res.WalletAddress, "failed scenario : "+t.name)
s.Equal(t.expectedResponse.Pubkey, res.Pubkey, "failed scenario : "+t.name) s.Equal(t.expectedResponse.WalletPubkey, res.WalletPubkey, "failed scenario : "+t.name)
s.Equal(t.expectedResponse.Mnemonic, res.Mnemonic, "failed scenario : "+t.name) s.Equal(t.expectedResponse.Mnemonic, res.Mnemonic, "failed scenario : "+t.name)
s.Equal(t.expectedError, err, "failed scenario : "+t.name) s.Equal(t.expectedError, err, "failed scenario : "+t.name)
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/status-im/status-go/account"
) )
// Make sure that Service implements node.Service interface. // Make sure that Service implements node.Service interface.
@ -21,8 +22,8 @@ type WhisperService interface {
// AccountManager interface to manage account actions // AccountManager interface to manage account actions
type AccountManager interface { type AccountManager interface {
AddressToDecryptedAccount(string, string) (accounts.Account, *keystore.Key, error) AddressToDecryptedAccount(string, string) (accounts.Account, *keystore.Key, error)
SelectAccount(address, password string) error SelectAccount(walletAddress, chatAddress, password string) error
CreateAccount(password string) (address, pubKey, mnemonic string, err error) CreateAccount(password string) (accountInfo account.Info, mnemonic string, err error)
} }
// Service represents our own implementation of status status operations. // Service represents our own implementation of status status operations.

View File

@ -1,8 +1,10 @@
{ {
"Account1": { "Account1": {
"Address": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c" "WalletAddress": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c",
"ChatAddress": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c"
}, },
"Account2": { "Account2": {
"Address": "0xA0a19221268d939c3a972bf5461dC10f7980E814" "WalletAddress": "0xA0a19221268d939c3a972bf5461dC10f7980E814",
"ChatAddress": "0xA0a19221268d939c3a972bf5461dC10f7980E814"
} }
} }

View File

@ -1,14 +1,17 @@
{ {
"Account1": { "Account1": {
"Address": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9", "WalletAddress": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9",
"ChatAddress": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9",
"Password": "password" "Password": "password"
}, },
"Account2": { "Account2": {
"Address": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C", "WalletAddress": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C",
"ChatAddress": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C",
"Password": "password" "Password": "password"
}, },
"Account3": { "Account3": {
"Address": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4", "WalletAddress": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4",
"ChatAddress": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4",
"Password": "password" "Password": "password"
} }
} }

View File

@ -23,19 +23,20 @@ func (s *AccountsTestSuite) TestRPCEthAccounts() {
defer s.StopTestBackend() defer s.StopTestBackend()
// log into test account // log into test account
err := s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
rpcClient := s.Backend.StatusNode().RPCClient() rpcClient := s.Backend.StatusNode().RPCClient()
s.NotNil(rpcClient) s.NotNil(rpcClient)
expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + strings.ToLower(TestConfig.Account1.Address) + `"]}` expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + strings.ToLower(TestConfig.Account1.WalletAddress) + `"]}`
resp := rpcClient.CallRaw(`{ resp := rpcClient.CallRaw(`{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
"method": "eth_accounts", "method": "eth_accounts",
"params": [] "params": []
}`) }`)
s.Equal(expectedResponse, resp) s.Equal(expectedResponse, resp)
} }
@ -50,13 +51,13 @@ func (s *AccountsTestSuite) TestRPCEthAccountsWithUpstream() {
defer s.StopTestBackend() defer s.StopTestBackend()
// log into test account // log into test account
err = s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err = s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
rpcClient := s.Backend.StatusNode().RPCClient() rpcClient := s.Backend.StatusNode().RPCClient()
s.NotNil(rpcClient) s.NotNil(rpcClient)
expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + strings.ToLower(TestConfig.Account1.Address) + `"]}` expectedResponse := `{"jsonrpc":"2.0","id":1,"result":["` + strings.ToLower(TestConfig.Account1.WalletAddress) + `"]}`
resp := rpcClient.CallRaw(`{ resp := rpcClient.CallRaw(`{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,

View File

@ -30,7 +30,7 @@ func (s *AccountsTestSuite) TestAccountsList() {
s.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)") s.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)")
// create an account // create an account
address, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// ensure that there is still no accounts returned // ensure that there is still no accounts returned
@ -39,15 +39,15 @@ func (s *AccountsTestSuite) TestAccountsList() {
s.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)") 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) // select account (sub-accounts will be created for this key)
err = s.Backend.SelectAccount(address, TestConfig.Account1.Password) err = s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)
s.NoError(err, "account selection failed") s.NoError(err, "account selection failed")
// at this point main account should show up // at this point main account should show up
accounts, err = s.Backend.AccountManager().Accounts() accounts, err = s.Backend.AccountManager().Accounts()
s.NoError(err) s.NoError(err)
s.Equal(1, len(accounts), "exactly single account is expected (main account)") s.Equal(1, len(accounts), "exactly single account is expected (main account)")
s.Equal(accounts[0].Hex(), address, 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"+address)) 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 // create sub-account 1
subAccount1, subPubKey1, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password) subAccount1, subPubKey1, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password)
@ -57,7 +57,7 @@ func (s *AccountsTestSuite) TestAccountsList() {
accounts, err = s.Backend.AccountManager().Accounts() accounts, err = s.Backend.AccountManager().Accounts()
s.NoError(err) s.NoError(err)
s.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)") s.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)")
s.Equal(accounts[0].Hex(), address, "main account is not retured as the first key") 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") s.Equal(accounts[1].Hex(), subAccount1, "subAcount1 not returned")
// create sub-account 2, index automatically progresses // create sub-account 2, index automatically progresses
@ -69,7 +69,7 @@ func (s *AccountsTestSuite) TestAccountsList() {
accounts, err = s.Backend.AccountManager().Accounts() accounts, err = s.Backend.AccountManager().Accounts()
s.NoError(err) s.NoError(err)
s.Equal(3, len(accounts), "unexpected number of accounts") s.Equal(3, len(accounts), "unexpected number of accounts")
s.Equal(accounts[0].Hex(), address, "main account is not retured as the first key") s.Equal(accounts[0].Hex(), accountInfo.WalletAddress, "main account is not retured as the first key")
subAccount1MatchesKey1 := accounts[1].Hex() != "0x"+subAccount1 subAccount1MatchesKey1 := accounts[1].Hex() != "0x"+subAccount1
subAccount1MatchesKey2 := accounts[2].Hex() != "0x"+subAccount1 subAccount1MatchesKey2 := accounts[2].Hex() != "0x"+subAccount1
@ -89,11 +89,12 @@ func (s *AccountsTestSuite) TestCreateChildAccount() {
s.NotNil(keyStore) s.NotNil(keyStore)
// create an account // create an account
address, pubKey, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) 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(address) acct, err := account.ParseAccountString(accountInfo.WalletAddress)
s.NoError(err, "can not get account from 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 // obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present
@ -105,7 +106,7 @@ func (s *AccountsTestSuite) TestCreateChildAccount() {
_, _, err = s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password) _, _, 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)") s.EqualError(account.ErrNoAccountSelected, err.Error(), "expected error is not returned (tried to create sub-account w/o login)")
err = s.Backend.SelectAccount(address, TestConfig.Account1.Password) err = s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)
s.NoError(err, "cannot select account") s.NoError(err, "cannot select account")
// try to create sub-account with wrong password // try to create sub-account with wrong password
@ -136,17 +137,19 @@ func (s *AccountsTestSuite) TestRecoverAccount() {
s.NoError(err) s.NoError(err)
// create an acc // create an acc
address, pubKey, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, mnemonic, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) s.T().Logf("Account created: {walletAddress: %s, walletKey: %s, chatAddress: %s, chatKey: %s, mnemonic:%s}",
accountInfo.WalletAddress, accountInfo.WalletPubKey, accountInfo.ChatAddress, accountInfo.ChatPubKey, mnemonic)
// try recovering using password + mnemonic // try recovering using password + mnemonic
addressCheck, pubKeyCheck, err := s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic) accountInfoCheck, err := s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
s.NoError(err, "recover acc failed") s.NoError(err, "recover acc failed")
s.False(address != addressCheck || pubKey != pubKeyCheck, "incorrect accound details recovered")
s.EqualValues(accountInfo, accountInfoCheck, "incorrect accound details recovered")
// now test recovering, but make sure that acc/key file is removed i.e. simulate recovering on a new device // now test recovering, but make sure that acc/key file is removed i.e. simulate recovering on a new device
acc, err := account.ParseAccountString(address) acc, err := account.ParseAccountString(accountInfo.WalletAddress)
s.NoError(err, "can not get acc from address") s.NoError(err, "can not get acc from address")
acc, key, err := keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password) acc, key, err := keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password)
@ -155,10 +158,9 @@ func (s *AccountsTestSuite) TestRecoverAccount() {
s.NoError(keyStore.Delete(acc, TestConfig.Account1.Password), "cannot remove acc") s.NoError(keyStore.Delete(acc, TestConfig.Account1.Password), "cannot remove acc")
addressCheck, pubKeyCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic) accountInfoCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
s.NoError(err, "recover acc failed (for non-cached acc)") s.NoError(err, "recover acc failed (for non-cached acc)")
s.False(address != addressCheck || pubKey != pubKeyCheck, s.EqualValues(accountInfo, accountInfoCheck, "incorrect acc details recovered (for non-cached acc)")
"incorrect acc details recovered (for non-cached acc)")
// make sure that extended key exists and is imported ok too // make sure that extended key exists and is imported ok too
_, key, err = keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password) _, key, err = keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password)
@ -166,10 +168,9 @@ func (s *AccountsTestSuite) TestRecoverAccount() {
s.Equal(extChild2String, key.ExtendedKey.String(), "CKD#2 key mismatch") 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) // 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) accountInfoCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic)
s.NoError(err, "recover acc failed (for non-cached acc)") s.NoError(err, "recover acc failed (for non-cached acc)")
s.False(address != addressCheck || pubKey != pubKeyCheck, s.EqualValues(accountInfo, accountInfoCheck, "incorrect acc details recovered (for non-cached acc)")
"incorrect acc details recovered (for non-cached acc)")
} }
func (s *AccountsTestSuite) TestSelectAccount() { func (s *AccountsTestSuite) TestSelectAccount() {
@ -177,46 +178,51 @@ func (s *AccountsTestSuite) TestSelectAccount() {
defer s.StopTestBackend() defer s.StopTestBackend()
// create an account // create an account
address1, pubKey1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s}", address1, pubKey1) s.T().Logf("Account created: {walletAddress: %s, walletKey: %s, chatAddress: %s, chatKey: %s}",
accountInfo1.WalletAddress, accountInfo1.WalletPubKey, accountInfo1.ChatAddress, accountInfo1.ChatPubKey)
address2, pubKey2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
s.T().Logf("Account created: {address: %s, key: %s}", address2, pubKey2) s.T().Logf("Account created: {walletAddress: %s, walletKey: %s, chatAddress: %s, chatKey: %s}",
accountInfo2.WalletAddress, accountInfo2.WalletPubKey, accountInfo2.ChatAddress, accountInfo2.ChatPubKey)
// try selecting with wrong password // try selecting with wrong password
err = s.Backend.SelectAccount(address1, "wrongPassword") err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase") 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") s.EqualError(expectedErr, err.Error(), "select account is expected to throw error: wrong password used")
err = s.Backend.SelectAccount(address1, TestConfig.Account1.Password) err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// select another account, make sure that previous account is wiped out from Whisper cache // select another account, make sure that previous account is wiped out from Whisper cache
s.NoError(s.Backend.SelectAccount(address2, TestConfig.Account1.Password)) s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password))
} }
func (s *AccountsTestSuite) TestSelectedAccountOnRestart() { func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.StartTestBackend() s.StartTestBackend()
// create test accounts // create test accounts
address1, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
address2, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// make sure that no account is selected by default // make sure that no account is selected by default
selectedAccount, err := s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err := s.Backend.AccountManager().SelectedWalletAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be") s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedAccount) s.Nil(selectedWalletAccount)
selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedChatAccount)
// select account // select account
err = s.Backend.SelectAccount(address1, "wrongPassword") err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase") 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.EqualError(expectedErr, err.Error())
s.NoError(s.Backend.SelectAccount(address2, TestConfig.Account1.Password)) s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account1.Password))
// stop node (and all of its sub-protocols) // stop node (and all of its sub-protocols)
nodeConfig := s.Backend.StatusNode().Config() nodeConfig := s.Backend.StatusNode().Config()
@ -225,19 +231,27 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.NoError(s.Backend.StopNode()) s.NoError(s.Backend.StopNode())
// make sure that account is still selected // make sure that account is still selected
selectedAccount, err = s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
s.Require().NoError(err)
s.NotNil(selectedWalletAccount)
s.Equal(selectedWalletAccount.Address.Hex(), accountInfo2.WalletAddress, "incorrect wallet address selected")
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err) s.NoError(err)
s.NotNil(selectedAccount) s.NotNil(selectedChatAccount)
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected") s.Equal(selectedChatAccount.Address.Hex(), accountInfo2.ChatAddress, "incorrect chat address selected")
// resume node // resume node
s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig)) s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig))
// re-check selected account (account2 MUST be selected) // re-check selected account (account2 MUST be selected)
selectedAccount, err = s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
s.NoError(err) s.NoError(err)
s.NotNil(selectedAccount) s.NotNil(selectedWalletAccount)
s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected") s.Equal(selectedWalletAccount.Address.Hex(), 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")
// now restart node using RestartNode() method, and make sure that account is still available // now restart node using RestartNode() method, and make sure that account is still available
s.RestartTestNode() s.RestartTestNode()
@ -247,7 +261,10 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() {
s.NoError(s.Backend.Logout()) s.NoError(s.Backend.Logout())
s.RestartTestNode() s.RestartTestNode()
selectedAccount, err = s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error()) s.EqualError(account.ErrNoAccountSelected, err.Error())
s.Nil(selectedAccount) s.Nil(selectedWalletAccount)
selectedChatAccount, err = s.Backend.AccountManager().SelectedChatAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error())
s.Nil(selectedChatAccount)
} }

View File

@ -3,12 +3,11 @@ package rpc
import ( import (
"context" "context"
"fmt" "fmt"
"math/big"
"sync" "sync"
"testing" "testing"
"time" "time"
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/node" "github.com/status-im/status-go/node"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
@ -174,7 +173,7 @@ func (s *RPCTestSuite) TestCallContextResult() {
defer cancel() defer cancel()
var balance hexutil.Big var balance hexutil.Big
err := client.CallContext(ctx, &balance, "eth_getBalance", TestConfig.Account1.Address, "latest") err := client.CallContext(ctx, &balance, "eth_getBalance", TestConfig.Account1.WalletAddress, "latest")
s.NoError(err) s.NoError(err)
s.True(balance.ToInt().Cmp(big.NewInt(0)) > 0, "balance should be higher than 0") s.True(balance.ToInt().Cmp(big.NewInt(0)) > 0, "balance should be higher than 0")
} }

View File

@ -5,9 +5,8 @@ import (
"testing" "testing"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/stretchr/testify/suite"
. "github.com/status-im/status-go/t/utils" . "github.com/status-im/status-go/t/utils"
"github.com/stretchr/testify/suite"
) )
const ( const (
@ -65,7 +64,7 @@ func (s *PersonalSignSuite) TestPersonalSignUnsupportedMethod() {
basicCall := fmt.Sprintf( basicCall := fmt.Sprintf(
`{"jsonrpc":"2.0","method":"personal_sign","params":["%s", "%s"],"id":67}`, `{"jsonrpc":"2.0","method":"personal_sign","params":["%s", "%s"],"id":67}`,
signDataString, signDataString,
TestConfig.Account1.Address) TestConfig.Account1.WalletAddress)
rawResult, err := s.Backend.CallRPC(basicCall) rawResult, err := s.Backend.CallRPC(basicCall)
s.NoError(err) s.NoError(err)

View File

@ -9,9 +9,8 @@ import (
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/status" "github.com/status-im/status-go/services/status"
"github.com/stretchr/testify/suite"
. "github.com/status-im/status-go/t/utils" . "github.com/status-im/status-go/t/utils"
"github.com/stretchr/testify/suite"
) )
type statusTestParams struct { type statusTestParams struct {
@ -62,7 +61,7 @@ func (s *StatusAPISuite) TestAccessibleStatusAPIs() {
func (s *StatusAPISuite) TestStatusLoginSuccess() { func (s *StatusAPISuite) TestStatusLoginSuccess() {
addressKeyID := s.testStatusLogin(statusTestParams{ addressKeyID := s.testStatusLogin(statusTestParams{
Address: TestConfig.Account1.Address, Address: TestConfig.Account1.WalletAddress,
Password: TestConfig.Account1.Password, Password: TestConfig.Account1.Password,
}) })
s.NotEmpty(addressKeyID) s.NotEmpty(addressKeyID)
@ -90,13 +89,13 @@ func (s *StatusAPISuite) TestStatusSignupSuccess() {
res := s.testStatusSignup(statusTestParams{ res := s.testStatusSignup(statusTestParams{
Password: pwd, Password: pwd,
}) })
s.NotEmpty(res.Address) s.NotEmpty(res.WalletAddress)
s.NotEmpty(res.Pubkey) s.NotEmpty(res.WalletPubkey)
s.Equal(12, len(strings.Split(res.Mnemonic, " "))) s.Equal(12, len(strings.Split(res.Mnemonic, " ")))
// I should be able to login with the newly created account // I should be able to login with the newly created account
_ = s.testStatusLogin(statusTestParams{ _ = s.testStatusLogin(statusTestParams{
Address: res.Address, Address: res.WalletAddress,
Password: pwd, Password: pwd,
}) })
} }

View File

@ -70,7 +70,7 @@ func (s *TransactionsTestSuite) TestCallUpstreamPrivateRPCSendTransaction() {
func (s *TransactionsTestSuite) sendTransactionUsingRPCClient( func (s *TransactionsTestSuite) sendTransactionUsingRPCClient(
callRPCFn func(string) (string, error), callRPCFn func(string) (string, error),
) { ) {
err := s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
result, err := callRPCFn(`{ result, err := callRPCFn(`{
@ -78,7 +78,7 @@ func (s *TransactionsTestSuite) sendTransactionUsingRPCClient(
"id": 1, "id": 1,
"method": "eth_sendTransaction", "method": "eth_sendTransaction",
"params": [{ "params": [{
"from": "` + TestConfig.Account1.Address + `", "from": "` + TestConfig.Account1.WalletAddress + `",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x9184e72a" "value": "0x9184e72a"
}] }]
@ -94,11 +94,11 @@ func (s *TransactionsTestSuite) TestEmptyToFieldPreserved() {
defer s.StopTestBackend() defer s.StopTestBackend()
EnsureNodeSync(s.Backend.StatusNode().EnsureSync) EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
args := transactions.SendTxArgs{ args := transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
} }
hash, err := s.Backend.SendTransaction(args, TestConfig.Account1.Password) hash, err := s.Backend.SendTransaction(args, TestConfig.Account1.Password)
@ -162,7 +162,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
EnsureNodeSync(s.Backend.StatusNode().EnsureSync) EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// this call blocks, up until Complete Transaction is called // this call blocks, up until Complete Transaction is called
@ -171,7 +171,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
gas := uint64(params.DefaultGas) gas := uint64(params.DefaultGas)
args := transactions.SendTxArgs{ args := transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: nil, // marker, contract creation is expected To: nil, // marker, contract creation is expected
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)), //Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)),
Gas: (*hexutil.Uint64)(&gas), Gas: (*hexutil.Uint64)(&gas),
@ -196,12 +196,12 @@ func (s *TransactionsTestSuite) TestSendEther() {
EnsureNodeSync(s.Backend.StatusNode().EnsureSync) EnsureNodeSync(s.Backend.StatusNode().EnsureSync)
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Value: (*hexutil.Big)(big.NewInt(1000000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)),
}, TestConfig.Account1.Password) }, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
@ -216,12 +216,12 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() {
s.StartTestBackend(e2e.WithUpstream(addr)) s.StartTestBackend(e2e.WithUpstream(addr))
defer s.StopTestBackend() defer s.StopTestBackend()
err = s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err = s.Backend.SelectAccount(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
GasPrice: (*hexutil.Big)(big.NewInt(28000000000)), GasPrice: (*hexutil.Big)(big.NewInt(28000000000)),
Value: (*hexutil.Big)(big.NewInt(1000000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)),
}, TestConfig.Account1.Password) }, TestConfig.Account1.Password)

View File

@ -37,7 +37,7 @@ func (s *WhisperTestSuite) TestWhisperFilterRace() {
whisperAPI := whisper.NewPublicWhisperAPI(whisperService) whisperAPI := whisper.NewPublicWhisperAPI(whisperService)
// account1 // account1
_, accountKey1, err := accountManager.AddressToDecryptedAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) _, accountKey1, err := accountManager.AddressToDecryptedAccount(TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
accountKey1Byte := crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey) accountKey1Byte := crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey)
@ -47,7 +47,7 @@ func (s *WhisperTestSuite) TestWhisperFilterRace() {
s.True(ok, "identity not injected") s.True(ok, "identity not injected")
// account2 // account2
_, accountKey2, err := accountManager.AddressToDecryptedAccount(TestConfig.Account2.Address, TestConfig.Account2.Password) _, accountKey2, err := accountManager.AddressToDecryptedAccount(TestConfig.Account2.ChatAddress, TestConfig.Account2.Password)
s.NoError(err) s.NoError(err)
key2ID, err := whisperService.AddKeyPair(accountKey2.PrivateKey) key2ID, err := whisperService.AddKeyPair(accountKey2.PrivateKey)
s.NoError(err) s.NoError(err)
@ -96,21 +96,31 @@ func (s *WhisperTestSuite) TestSelectAccount() {
whisperService, err := s.Backend.StatusNode().WhisperService() whisperService, err := s.Backend.StatusNode().WhisperService()
s.NoError(err) s.NoError(err)
// create an acc // create account 1
address, pubKey, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// make sure that identity is not (yet injected) // create account 2
s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password)
s.NoError(err)
// make sure that identities are not injected yet
s.False(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity already present in whisper")
s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper")
// try selecting with wrong password // try selecting with wrong password
err = s.Backend.SelectAccount(address, "wrongPassword") err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongpassword")
s.NotNil(err) s.NotNil(err)
// select another account, make sure that previous account is wiped out from Whisper cache // select account 1
s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password)
s.NoError(s.Backend.SelectAccount(address, TestConfig.Account1.Password)) s.NoError(err)
s.True(whisperService.HasKeyPair(pubKey), "identity not injected into whisper") 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.True(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity not injected into whisper")
} }
func (s *WhisperTestSuite) TestLogout() { func (s *WhisperTestSuite) TestLogout() {
@ -121,16 +131,16 @@ func (s *WhisperTestSuite) TestLogout() {
s.NoError(err) s.NoError(err)
// create an account // create an account
address, pubKey, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// make sure that identity doesn't exist (yet) in Whisper // make sure that identity doesn't exist (yet) in Whisper
s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity already present in whisper")
s.NoError(s.Backend.SelectAccount(address, TestConfig.Account1.Password)) s.NoError(s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
s.True(whisperService.HasKeyPair(pubKey), "identity not injected into whisper") s.True(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not injected into whisper")
s.NoError(s.Backend.Logout()) s.NoError(s.Backend.Logout())
s.False(whisperService.HasKeyPair(pubKey), "identity not cleared from whisper") s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not cleared from whisper")
} }
func (s *WhisperTestSuite) TestSelectedAccountOnRestart() { func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
@ -140,15 +150,15 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
whisperService := s.WhisperService() whisperService := s.WhisperService()
// create test accounts // create test accounts
address1, pubKey1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
address2, pubKey2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password) accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password)
s.NoError(err) s.NoError(err)
// make sure that identity is not (yet injected) // make sure that identity is not (yet injected)
s.False(whisperService.HasKeyPair(pubKey1), "identity already present in whisper") s.False(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity already present in whisper")
// make sure that no account is selected by default // make sure that no wallet account is selected by default
selectedWalletAccount, err := s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err := s.Backend.AccountManager().SelectedWalletAccount()
s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be") s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be")
s.Nil(selectedWalletAccount) s.Nil(selectedWalletAccount)
@ -159,25 +169,25 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
s.Nil(selectedChatAccount) s.Nil(selectedChatAccount)
// select account with wrong password // select account with wrong password
err = s.Backend.SelectAccount(address1, "wrongPassword") err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongPassword")
expectedErr := errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase") 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.EqualError(expectedErr, err.Error())
// select account with right password // select account with right password
s.NoError(s.Backend.SelectAccount(address1, TestConfig.Account1.Password)) s.NoError(s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password))
selectedChatAccount1, err := s.Backend.AccountManager().SelectedChatAccount() selectedChatAccount1, err := s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err) s.NoError(err)
selectedChatPubKey1 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount1.AccountKey.PrivateKey.PublicKey)) selectedChatPubKey1 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount1.AccountKey.PrivateKey.PublicKey))
s.Equal(selectedChatPubKey1, pubKey1) s.Equal(selectedChatPubKey1, accountInfo1.ChatPubKey)
s.True(whisperService.HasKeyPair(selectedChatPubKey1), "identity not injected into whisper") s.True(whisperService.HasKeyPair(selectedChatPubKey1), "identity not injected into whisper")
// select another account, make sure that previous account is wiped out from Whisper cache // 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.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper")
s.NoError(s.Backend.SelectAccount(address2, TestConfig.Account2.Password)) s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password))
selectedChatAccount2, err := s.Backend.AccountManager().SelectedChatAccount() selectedChatAccount2, err := s.Backend.AccountManager().SelectedChatAccount()
s.NoError(err) s.NoError(err)
selectedChatPubKey2 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount2.AccountKey.PrivateKey.PublicKey)) selectedChatPubKey2 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount2.AccountKey.PrivateKey.PublicKey))
s.Equal(selectedChatPubKey2, pubKey2) s.Equal(selectedChatPubKey2, accountInfo2.ChatPubKey)
s.True(whisperService.HasKeyPair(selectedChatPubKey2), "identity not injected into whisper") s.True(whisperService.HasKeyPair(selectedChatPubKey2), "identity not injected into whisper")
s.False(whisperService.HasKeyPair(selectedChatPubKey1), "identity should be removed, but it is still present in whisper") s.False(whisperService.HasKeyPair(selectedChatPubKey1), "identity should be removed, but it is still present in whisper")
@ -194,7 +204,11 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() {
selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount() selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount()
s.NoError(err) s.NoError(err)
s.NotNil(selectedWalletAccount) s.NotNil(selectedWalletAccount)
s.Equal(selectedWalletAccount.Address.Hex(), address2, "incorrect address selected") s.Equal(selectedWalletAccount.Address.Hex(), 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")
// make sure that Whisper gets identity re-injected // make sure that Whisper gets identity re-injected
whisperService = s.WhisperService() whisperService = s.WhisperService()
@ -233,11 +247,11 @@ func (s *WhisperTestSuite) TestSelectedChatKeyIsUsedInWhisper() {
s.NoError(err) s.NoError(err)
// create an account // create an account
address, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err) s.NoError(err)
// select account // select account
s.NoError(s.Backend.SelectAccount(address, TestConfig.Account1.Password)) s.NoError(s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
// Get the chat account // Get the chat account
selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount() selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount()

View File

@ -19,11 +19,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/status-im/status-go/logutils"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
_ "github.com/stretchr/testify/suite" // required to register testify flags _ "github.com/stretchr/testify/suite" // required to register testify flags
) )
@ -307,8 +305,9 @@ func MakeTestNodeConfigWithDataDir(name, dataDir string, networkID uint64) (*par
} }
type account struct { type account struct {
Address string WalletAddress string
Password string ChatAddress string
Password string
} }
// testConfig contains shared (among different test packages) parameters // testConfig contains shared (among different test packages) parameters

View File

@ -21,14 +21,12 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
gethrpc "github.com/ethereum/go-ethereum/rpc" gethrpc "github.com/ethereum/go-ethereum/rpc"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/suite"
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
"github.com/status-im/status-go/rpc" "github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/transactions/fake"
. "github.com/status-im/status-go/t/utils" . "github.com/status-im/status-go/t/utils"
"github.com/status-im/status-go/transactions/fake"
"github.com/stretchr/testify/suite"
) )
func TestTransactorSuite(t *testing.T) { func TestTransactorSuite(t *testing.T) {
@ -120,7 +118,7 @@ func (s *TransactorSuite) rlpEncodeTx(args SendTxArgs, config *params.NodeConfig
func (s *TransactorSuite) TestGasValues() { func (s *TransactorSuite) TestGasValues() {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
selectedAccount := &account.SelectedExtKey{ selectedAccount := &account.SelectedExtKey{
Address: account.FromAddress(TestConfig.Account1.Address), Address: account.FromAddress(TestConfig.Account1.WalletAddress),
AccountKey: &keystore.Key{PrivateKey: key}, AccountKey: &keystore.Key{PrivateKey: key},
} }
testCases := []struct { testCases := []struct {
@ -154,8 +152,8 @@ func (s *TransactorSuite) TestGasValues() {
s.T().Run(testCase.name, func(t *testing.T) { s.T().Run(testCase.name, func(t *testing.T) {
s.SetupTest() s.SetupTest()
args := SendTxArgs{ args := SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Gas: testCase.gas, Gas: testCase.gas,
GasPrice: testCase.gasPrice, GasPrice: testCase.gasPrice,
} }
@ -170,14 +168,14 @@ func (s *TransactorSuite) TestGasValues() {
func (s *TransactorSuite) TestArgsValidation() { func (s *TransactorSuite) TestArgsValidation() {
args := SendTxArgs{ args := SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
Data: hexutil.Bytes([]byte{0x01, 0x02}), Data: hexutil.Bytes([]byte{0x01, 0x02}),
Input: hexutil.Bytes([]byte{0x02, 0x01}), Input: hexutil.Bytes([]byte{0x02, 0x01}),
} }
s.False(args.Valid()) s.False(args.Valid())
selectedAccount := &account.SelectedExtKey{ selectedAccount := &account.SelectedExtKey{
Address: account.FromAddress(TestConfig.Account1.Address), Address: account.FromAddress(TestConfig.Account1.WalletAddress),
} }
_, err := s.manager.SendTransaction(args, selectedAccount) _, err := s.manager.SendTransaction(args, selectedAccount)
s.EqualError(err, ErrInvalidSendTxArgs.Error()) s.EqualError(err, ErrInvalidSendTxArgs.Error())
@ -185,8 +183,8 @@ func (s *TransactorSuite) TestArgsValidation() {
func (s *TransactorSuite) TestAccountMismatch() { func (s *TransactorSuite) TestAccountMismatch() {
args := SendTxArgs{ args := SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
} }
var err error var err error
@ -197,7 +195,7 @@ func (s *TransactorSuite) TestAccountMismatch() {
// mismatched accounts // mismatched accounts
selectedAccount := &account.SelectedExtKey{ selectedAccount := &account.SelectedExtKey{
Address: account.FromAddress(TestConfig.Account2.Address), Address: account.FromAddress(TestConfig.Account2.WalletAddress),
} }
_, err = s.manager.SendTransaction(args, selectedAccount) _, err = s.manager.SendTransaction(args, selectedAccount)
s.EqualError(err, ErrInvalidTxSender.Error()) s.EqualError(err, ErrInvalidTxSender.Error())
@ -214,15 +212,15 @@ func (s *TransactorSuite) TestLocalNonce() {
txCount := 3 txCount := 3
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
selectedAccount := &account.SelectedExtKey{ selectedAccount := &account.SelectedExtKey{
Address: account.FromAddress(TestConfig.Account1.Address), Address: account.FromAddress(TestConfig.Account1.WalletAddress),
AccountKey: &keystore.Key{PrivateKey: key}, AccountKey: &keystore.Key{PrivateKey: key},
} }
nonce := hexutil.Uint64(0) nonce := hexutil.Uint64(0)
for i := 0; i < txCount; i++ { for i := 0; i < txCount; i++ {
args := SendTxArgs{ args := SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
} }
s.setupTransactionPoolAPI(args, nonce, hexutil.Uint64(i), selectedAccount, nil) s.setupTransactionPoolAPI(args, nonce, hexutil.Uint64(i), selectedAccount, nil)
@ -234,8 +232,8 @@ func (s *TransactorSuite) TestLocalNonce() {
nonce = hexutil.Uint64(5) nonce = hexutil.Uint64(5)
args := SendTxArgs{ args := SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
} }
s.setupTransactionPoolAPI(args, nonce, nonce, selectedAccount, nil) s.setupTransactionPoolAPI(args, nonce, nonce, selectedAccount, nil)
@ -249,8 +247,8 @@ func (s *TransactorSuite) TestLocalNonce() {
testErr := errors.New("test") testErr := errors.New("test")
s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), selectedAccount.Address, gethrpc.PendingBlockNumber).Return(nil, testErr) s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), selectedAccount.Address, gethrpc.PendingBlockNumber).Return(nil, testErr)
args = SendTxArgs{ args = SendTxArgs{
From: account.FromAddress(TestConfig.Account1.Address), From: account.FromAddress(TestConfig.Account1.WalletAddress),
To: account.ToAddress(TestConfig.Account2.Address), To: account.ToAddress(TestConfig.Account2.WalletAddress),
} }
_, err = s.manager.SendTransaction(args, selectedAccount) _, err = s.manager.SendTransaction(args, selectedAccount)