diff --git a/account/accounts.go b/account/accounts.go index d5989261b..afb51c13e 100644 --- a/account/accounts.go +++ b/account/accounts.go @@ -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 // Public key of CKD#1 is returned, with CKD#2 securely encoded into account key file (to be used for // 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 mn := extkeys.NewMnemonic() - mnemonic, err = mn.MnemonicPhrase(extkeys.EntropyStrength128, extkeys.EnglishLanguage) + mnemonic, err := mn.MnemonicPhrase(extkeys.EntropyStrength128, extkeys.EnglishLanguage) 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) @@ -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. extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, "")) 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 - address, pubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password) + info.WalletAddress, info.WalletPubKey, err = m.importExtendedKey(extkeys.KeyPurposeWallet, extKey, password) 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. @@ -140,21 +144,25 @@ func (m *Manager) CreateChildAccount(parentAddress, password string) (address, p // RecoverAccount re-creates master key using given details. // Once master key is re-generated, it is inserted into keystore (if not already there). -func (m *Manager) RecoverAccount(password, mnemonic string) (address, pubKey string, err error) { +func (m *Manager) RecoverAccount(password, mnemonic string) (Info, error) { + info := Info{} // re-create extended key (see BIP32) mn := extkeys.NewMnemonic() extKey, err := extkeys.NewMaster(mn.MnemonicSeed(mnemonic, "")) if err != nil { - return "", "", ErrInvalidMasterKeyCreated + return info, ErrInvalidMasterKeyCreated } // 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 { - 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. @@ -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 // 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() defer m.mu.Unlock() - keyStore, err := m.geth.AccountKeyStore() + selectedWalletAccount, err := m.unlockExtendedKey(walletAddress, password) if err != nil { return err } - account, err := ParseAccountString(address) - 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) + selectedChatAccount, err := m.unlockExtendedKey(chatAddress, password) if err != nil { return err } - m.selectedWalletAccount = &SelectedExtKey{ - Address: account.Address, - 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, - } + m.selectedWalletAccount = selectedWalletAccount + m.selectedChatAccount = selectedChatAccount return nil } @@ -428,5 +414,33 @@ func (m *Manager) AddressToDecryptedAccount(address, password string) (accounts. 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 } diff --git a/account/accounts_test.go b/account/accounts_test.go index 11eab7b70..2b7e0241b 100644 --- a/account/accounts_test.go +++ b/account/accounts_test.go @@ -14,6 +14,7 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" "github.com/golang/mock/gomock" . "github.com/status-im/status-go/t/utils" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "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, GetAccount2PKFile())) - account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.Address)) + account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.WalletAddress)) testCases := []struct { name string @@ -44,21 +45,21 @@ func TestVerifyAccountPassword(t *testing.T) { { "correct address, correct password (decrypt should succeed)", keyStoreDir, - TestConfig.Account1.Address, + TestConfig.Account1.WalletAddress, TestConfig.Account1.Password, nil, }, { "correct address, correct password, non-existent key store", filepath.Join(keyStoreDir, "non-existent-folder"), - TestConfig.Account1.Address, + TestConfig.Account1.WalletAddress, TestConfig.Account1.Password, 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)", emptyKeyStoreDir, - TestConfig.Account1.Address, + TestConfig.Account1.WalletAddress, TestConfig.Account1.Password, fmt.Errorf("cannot locate account for address: %s", account1Address.Hex()), }, @@ -72,7 +73,7 @@ func TestVerifyAccountPassword(t *testing.T) { { "correct address, wrong password", keyStoreDir, - TestConfig.Account1.Address, + TestConfig.Account1.WalletAddress, "wrong password", // wrong password errors.New("could not decrypt key with given passphrase"), }, @@ -107,7 +108,7 @@ func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) { accManager := NewManager(nil) - address := gethcommon.HexToAddress(TestConfig.Account3.Address) + address := gethcommon.HexToAddress(TestConfig.Account3.WalletAddress) _, err = accManager.VerifyAccountPassword(keyStoreDir, address.Hex(), TestConfig.Account3.Password) require.NoError(t, err) } @@ -130,17 +131,25 @@ func TestManagerTestSuite(t *testing.T) { // Initial test - create test account gethServiceProvider.EXPECT().AccountKeyStore().Return(keyStore, nil) - addr, pubKey, mnemonic, err := accManager.CreateAccount(testPassword) + accountInfo, mnemonic, err := accManager.CreateAccount(testPassword) require.NoError(t, err) - require.NotEmpty(t, addr) - require.NotEmpty(t, pubKey) + require.NotEmpty(t, accountInfo.WalletAddress) + require.NotEmpty(t, accountInfo.WalletPubKey) + require.NotEmpty(t, accountInfo.ChatAddress) + require.NotEmpty(t, accountInfo.ChatPubKey) 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{ testAccount: testAccount{ "test-password", - addr, - pubKey, + accountInfo.WalletAddress, + accountInfo.WalletPubKey, + accountInfo.ChatAddress, + accountInfo.ChatPubKey, mnemonic, }, gethServiceProvider: gethServiceProvider, @@ -167,10 +176,12 @@ type ManagerTestSuite struct { } type testAccount struct { - password string - address string - pubKey string - mnemonic string + password string + walletAddress string + walletPubKey string + chatAddress string + chatPubKey string + mnemonic string } // reinitMock is for reassigning a new mock node manager to account manager. @@ -190,23 +201,25 @@ func (s *ManagerTestSuite) SetupTest() { func (s *ManagerTestSuite) TestCreateAccount() { // Don't fail on empty password s.gethServiceProvider.EXPECT().AccountKeyStore().Return(s.keyStore, nil) - _, _, _, err := s.accManager.CreateAccount(s.password) + _, _, err := s.accManager.CreateAccount(s.password) s.NoError(err) s.gethServiceProvider.EXPECT().AccountKeyStore().Return(nil, errKeyStore) - _, _, _, err = s.accManager.CreateAccount(s.password) + _, _, err = s.accManager.CreateAccount(s.password) s.Equal(errKeyStore, err) } func (s *ManagerTestSuite) TestRecoverAccount() { 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.Equal(s.address, addr) - s.Equal(s.pubKey, pubKey) + s.Equal(s.walletAddress, accountInfo.WalletAddress) + 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) - _, _, err = s.accManager.RecoverAccount(s.password, s.mnemonic) + _, err = s.accManager.RecoverAccount(s.password, s.mnemonic) s.Equal(errKeyStore, err) } @@ -214,35 +227,48 @@ func (s *ManagerTestSuite) TestSelectAccount() { testCases := []struct { name string accountKeyStoreReturn []interface{} - address string + walletAddress string + chatAddress string password string expectedError error }{ { "success", []interface{}{s.keyStore, nil}, - s.address, + s.walletAddress, + s.chatAddress, s.password, nil, }, { "fail_keyStore", []interface{}{nil, errKeyStore}, - s.address, + s.walletAddress, + s.chatAddress, s.password, errKeyStore, }, { - "fail_wrongAddress", + "fail_wrongWalletAddress", []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, ErrAddressToAccountMappingFailure, }, { "fail_wrongPassword", []interface{}{s.keyStore, nil}, - s.address, + s.walletAddress, + s.chatAddress, "wrong-password", 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.reinitMock() 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) - selectedWalletAccount, err := s.accManager.SelectedWalletAccount() - s.NoError(err) - selectedChatAccount, err := s.accManager.SelectedChatAccount() - s.NoError(err) + selectedWalletAccount, walletErr := s.accManager.SelectedWalletAccount() + selectedChatAccount, chatErr := s.accManager.SelectedChatAccount() - 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. s.reinitMock() 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) testCases := []struct { name string - address string + walletAddress string + chatAddress string password string accountKeyStoreReturn []interface{} expectedError error }{ { "success", - s.address, + s.walletAddress, + s.chatAddress, s.password, []interface{}{s.keyStore, nil}, nil, }, { "fail_keyStore", - s.address, + s.walletAddress, + s.chatAddress, s.password, []interface{}{nil, errKeyStore}, errKeyStore, }, { - "fail_wrongAddress", + "fail_wrongWalletAddress", "wrong-address", + s.chatAddress, s.password, []interface{}{s.keyStore, nil}, ErrAddressToAccountMappingFailure, }, { "fail_wrongPassword", - s.address, + s.walletAddress, + s.chatAddress, "wrong-password", []interface{}{s.keyStore, nil}, errors.New("cannot retrieve a valid key for a given account: could not decrypt key with given passphrase"), @@ -322,7 +362,7 @@ func (s *ManagerTestSuite) TestCreateChildAccount() { s.T().Run(testCase.name, func(t *testing.T) { s.reinitMock() s.gethServiceProvider.EXPECT().AccountKeyStore().Return(testCase.accountKeyStoreReturn...).AnyTimes() - childAddr, childPubKey, err := s.accManager.CreateChildAccount(testCase.address, testCase.password) + childAddr, childPubKey, err := s.accManager.CreateChildAccount(testCase.walletAddress, testCase.password) if testCase.expectedError != nil { s.Equal(testCase.expectedError, err) } else { @@ -343,7 +383,7 @@ func (s *ManagerTestSuite) TestLogout() { func (s *ManagerTestSuite) TestAccounts() { // Select the test account 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) // Success @@ -369,37 +409,37 @@ func (s *ManagerTestSuite) TestAddressToDecryptedAccount() { testCases := []struct { name string accountKeyStoreReturn []interface{} - address string + walletAddress string password string expectedError error }{ { "success", []interface{}{s.keyStore, nil}, - s.address, + s.walletAddress, s.password, nil, }, { "fail_keyStore", []interface{}{nil, errKeyStore}, - s.address, + s.walletAddress, s.password, errKeyStore, }, { - "fail_wrongAddress", + "fail_wrongWalletAddress", []interface{}{s.keyStore, nil}, - "wrong-address", + "wrong-wallet-address", s.password, ErrAddressToAccountMappingFailure, }, { "fail_wrongPassword", []interface{}{s.keyStore, nil}, - s.address, + s.walletAddress, "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.reinitMock() 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 { s.Equal(testCase.expectedError, err) } else { diff --git a/account/utils.go b/account/utils.go index 2517f4623..a0d733ed7 100644 --- a/account/utils.go +++ b/account/utils.go @@ -13,6 +13,14 @@ var ( 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. type SelectedExtKey struct { Address common.Address diff --git a/api/backend.go b/api/backend.go index bf5e8a18e..d0c59210c 100644 --- a/api/backend.go +++ b/api/backend.go @@ -422,17 +422,18 @@ func (b *StatusBackend) reSelectAccount() error { return nil } -// SelectAccount selects current account, by verifying that 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, +// SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted +// using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity, // all previous identities are removed). -func (b *StatusBackend) SelectAccount(address, password string) error { +func (b *StatusBackend) SelectAccount(walletAddress, chatAddress, password string) error { b.mu.Lock() defer b.mu.Unlock() - err := b.accountManager.SelectAccount(address, password) + err := b.accountManager.SelectAccount(walletAddress, chatAddress, password) if err != nil { return err } + chatAccount, err := b.accountManager.SelectedChatAccount() if err != nil { return err @@ -455,7 +456,7 @@ func (b *StatusBackend) SelectAccount(address, password string) error { return err } - if err := st.InitProtocol(address, password); err != nil { + if err := st.InitProtocol(chatAddress, password); err != nil { return err } } diff --git a/api/backend_test.go b/api/backend_test.go index ac055874b..16e967b8b 100644 --- a/api/backend_test.go +++ b/api/backend_test.go @@ -138,15 +138,15 @@ func TestBackendAccountsConcurrently(t *testing.T) { var wgCreateAccounts sync.WaitGroup 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 for i := 0; i < count; i++ { wgCreateAccounts.Add(1) go func(pass string) { - address, _, _, err := backend.AccountManager().CreateAccount(pass) + accountInfo, _, err := backend.AccountManager().CreateAccount(pass) assert.NoError(t, err) - addressCh <- [...]string{address, pass} + addressCh <- [...]string{accountInfo.WalletAddress, accountInfo.ChatAddress, pass} wgCreateAccounts.Done() }("password-00" + string(i)) } @@ -159,8 +159,8 @@ func TestBackendAccountsConcurrently(t *testing.T) { for tuple := range addressCh { wg.Add(1) - go func(tuple [2]string) { - assert.NoError(t, backend.SelectAccount(tuple[0], tuple[1])) + go func(tuple [3]string) { + assert.NoError(t, backend.SelectAccount(tuple[0], tuple[1], tuple[2])) wg.Done() }(tuple) diff --git a/lib/library.go b/lib/library.go index 378aacd47..3392d2918 100644 --- a/lib/library.go +++ b/lib/library.go @@ -246,7 +246,7 @@ func CallPrivateRPC(inputJSON *C.char) *C.char { // just modified to handle the function arg passing //export CreateAccount 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 := "" if err != nil { @@ -255,10 +255,14 @@ func CreateAccount(password *C.char) *C.char { } out := AccountInfo{ - Address: address, - PubKey: pubKey, - Mnemonic: mnemonic, - Error: errString, + Address: info.WalletAddress, + PubKey: info.WalletPubKey, + WalletAddress: info.WalletAddress, + WalletPubKey: info.WalletPubKey, + ChatAddress: info.ChatAddress, + ChatPubKey: info.ChatPubKey, + Mnemonic: mnemonic, + Error: errString, } outBytes, _ := json.Marshal(out) 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 //export RecoverAccount 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 := "" if err != nil { @@ -296,10 +300,14 @@ func RecoverAccount(password, mnemonic *C.char) *C.char { } out := AccountInfo{ - Address: address, - PubKey: pubKey, - Mnemonic: C.GoString(mnemonic), - Error: errString, + Address: info.WalletAddress, + PubKey: info.WalletPubKey, + WalletAddress: info.WalletAddress, + WalletPubKey: info.WalletPubKey, + ChatAddress: info.ChatAddress, + ChatPubKey: info.ChatPubKey, + Mnemonic: C.GoString(mnemonic), + Error: errString, } outBytes, _ := json.Marshal(out) 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 //export Login 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) } diff --git a/lib/library_test_utils.go b/lib/library_test_utils.go index 5c1262bab..4d7ee834e 100644 --- a/lib/library_test_utils.go +++ b/lib/library_test_utils.go @@ -26,13 +26,11 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" gethcommon "github.com/ethereum/go-ethereum/common" "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/signal" . "github.com/status-im/status-go/t/utils" //nolint: golint "github.com/status-im/status-go/transactions" + "github.com/stretchr/testify/require" ) 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) 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 { t.Fatal(err) } @@ -177,7 +175,7 @@ func testVerifyAccountPassword(t *testing.T) bool { response := APIResponse{} rawResponse := VerifyAccountPassword( C.CString(tmpDir), - C.CString(TestConfig.Account1.Address), + C.CString(TestConfig.Account1.WalletAddress), C.CString(TestConfig.Account1.Password)) 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 - address1, pubKey1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) + account1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) if err != nil { t.Errorf("could not create account: %v", err) 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) - if whisperService.HasKeyPair(pubKey1) { + if whisperService.HasKeyPair(account1.ChatPubKey) { t.Error("identity already present in whisper") } // select account 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 { 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) return false } - if !whisperService.HasKeyPair(pubKey1) { + if !whisperService.HasKeyPair(account1.ChatPubKey) { t.Errorf("identity not injected into whisper: %v", err) } @@ -312,7 +310,7 @@ func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo if err != nil { 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) } @@ -382,10 +380,17 @@ func testCreateChildAccount(t *testing.T) bool { //nolint: gocyclo t.Errorf("could not create account: %s", err) 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 { t.Errorf("can not get account from address: %v", err) return false @@ -417,7 +422,7 @@ func testCreateChildAccount(t *testing.T) bool { //nolint: gocyclo return false } - err = statusBackend.SelectAccount(address, TestConfig.Account1.Password) + err = statusBackend.SelectAccount(walletAddress, chatAddress, TestConfig.Account1.Password) if err != nil { t.Errorf("Test failed: could not select account: %v", err) return false @@ -497,12 +502,12 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo keyStore, _ := statusBackend.StatusNode().AccountKeyStore() // 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 { t.Errorf("could not create account: %v", err) 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 recoverAccountResponse := AccountInfo{} @@ -517,13 +522,25 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo t.Errorf("recover account failed: %v", recoverAccountResponse.Error) return false } - addressCheck, pubKeyCheck := recoverAccountResponse.Address, recoverAccountResponse.PubKey - if address != addressCheck || pubKey != pubKeyCheck { - t.Error("recover account details failed to pull the correct details") + + if recoverAccountResponse.Address != recoverAccountResponse.WalletAddress || + 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 - account, err := account.ParseAccountString(address) + account, err := account.ParseAccountString(accountInfo.WalletAddress) if err != nil { 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) return false } - addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey - if address != addressCheck || pubKey != pubKeyCheck { - t.Error("recover account details failed to pull the correct details (for non-cached account)") + walletAddressCheck, walletPubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey + if accountInfo.WalletAddress != walletAddressCheck || accountInfo.WalletPubKey != walletPubKeyCheck { + 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 @@ -579,9 +601,14 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error) return false } - addressCheck, pubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey - if address != addressCheck || pubKey != pubKeyCheck { - t.Error("recover account details failed to pull the correct details (for non-cached account)") + walletAddressCheck, walletPubKeyCheck = recoverAccountResponse.Address, recoverAccountResponse.PubKey + if accountInfo.WalletAddress != walletAddressCheck || accountInfo.WalletPubKey != walletPubKeyCheck { + 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 @@ -591,15 +618,15 @@ func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo } // make sure that identity is not (yet injected) - if whisperService.HasKeyPair(pubKeyCheck) { + if whisperService.HasKeyPair(chatPubKeyCheck) { 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 { t.Errorf("Test failed: could not select account: %v", err) return false } - if !whisperService.HasKeyPair(pubKeyCheck) { + if !whisperService.HasKeyPair(chatPubKeyCheck) { t.Errorf("identity not injected into whisper: %v", err) } @@ -614,28 +641,28 @@ func testAccountSelect(t *testing.T) bool { //nolint: gocyclo } // create an account - address1, pubKey1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) if err != nil { t.Errorf("could not create account: %v", err) 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 { t.Error("Test failed: could not create account") 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) - if whisperService.HasKeyPair(pubKey1) { + if whisperService.HasKeyPair(accountInfo1.ChatPubKey) { t.Error("identity already present in whisper") } // try selecting with wrong password 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 { 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{} - 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 { 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) return false } - if !whisperService.HasKeyPair(pubKey1) { + if !whisperService.HasKeyPair(accountInfo1.ChatPubKey) { t.Errorf("identity not injected into whisper: %v", err) } // 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") } 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 { 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) return false } - if !whisperService.HasKeyPair(pubKey2) { + if !whisperService.HasKeyPair(accountInfo2.ChatPubKey) { 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") } @@ -698,25 +725,25 @@ func testAccountLogout(t *testing.T) bool { } // create an account - address, pubKey, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password) if err != nil { t.Errorf("could not create account: %v", err) return false } // 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") return false } // select/login - err = statusBackend.SelectAccount(address, TestConfig.Account1.Password) + err = statusBackend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password) if err != nil { t.Errorf("Test failed: could not select account: %v", err) return false } - if !whisperService.HasKeyPair(pubKey) { + if !whisperService.HasKeyPair(accountInfo.ChatPubKey) { t.Error("identity not injected into whisper") return false } @@ -735,7 +762,7 @@ func testAccountLogout(t *testing.T) bool { } // 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") return false } @@ -752,14 +779,14 @@ func testSendTransaction(t *testing.T) bool { EnsureNodeSync(statusBackend.StatusNode().EnsureSync) // log into account from which transactions will be sent - if err := statusBackend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password); err != nil { - t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.Address, err) + 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.WalletAddress, err) return false } args, err := json.Marshal(transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }) if err != nil { @@ -791,16 +818,17 @@ func testSendTransactionInvalidPassword(t *testing.T) bool { // log into account from which transactions will be sent if err := statusBackend.SelectAccount( - TestConfig.Account1.Address, + 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 } args, err := json.Marshal(transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }) if err != nil { @@ -826,14 +854,14 @@ func testFailedTransaction(t *testing.T) bool { EnsureNodeSync(statusBackend.StatusNode().EnsureSync) // log into wrong account in order to get selectedAccount error - if err := statusBackend.SelectAccount(TestConfig.Account2.Address, TestConfig.Account2.Password); err != nil { - t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.Address, err) + if err := statusBackend.SelectAccount(TestConfig.Account2.WalletAddress, TestConfig.Account2.ChatAddress, TestConfig.Account2.Password); err != nil { + t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err) return false } args, err := json.Marshal(transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }) if err != nil { diff --git a/lib/types.go b/lib/types.go index b8bd9fdf6..e6b338bc1 100644 --- a/lib/types.go +++ b/lib/types.go @@ -64,10 +64,14 @@ func (e APIError) Error() string { // AccountInfo represents account's info. type AccountInfo struct { - Address string `json:"address"` - PubKey string `json:"pubkey"` - Mnemonic string `json:"mnemonic"` - Error string `json:"error"` + Address string `json:"address"` // DEPRECATED + PubKey string `json:"pubkey"` // DEPRECATED + WalletAddress string `json:"walletAddress"` + 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. diff --git a/rpc/client.go b/rpc/client.go index abc0376f0..92fa5fad8 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -10,9 +10,8 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "github.com/status-im/status-go/params" - gethrpc "github.com/ethereum/go-ethereum/rpc" + "github.com/status-im/status-go/params" ) const ( diff --git a/services/status/account_mock.go b/services/status/account_mock.go index 8ec31259b..4d66bcef3 100644 --- a/services/status/account_mock.go +++ b/services/status/account_mock.go @@ -9,6 +9,7 @@ import ( accounts "github.com/ethereum/go-ethereum/accounts" keystore "github.com/ethereum/go-ethereum/accounts/keystore" gomock "github.com/golang/mock/gomock" + account "github.com/status-im/status-go/account" reflect "reflect" ) @@ -90,28 +91,27 @@ func (mr *MockAccountManagerMockRecorder) AddressToDecryptedAccount(arg0, arg1 i } // 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() - ret := m.ctrl.Call(m, "SelectAccount", address, password) + ret := m.ctrl.Call(m, "SelectAccount", walletAddress, chatAddress, password) ret0, _ := ret[0].(error) return ret0 } // 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() - 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 -func (m *MockAccountManager) CreateAccount(password string) (string, string, string, error) { +func (m *MockAccountManager) CreateAccount(password string) (account.Info, string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateAccount", password) - ret0, _ := ret[0].(string) + ret0, _ := ret[0].(account.Info) ret1, _ := ret[1].(string) - ret2, _ := ret[2].(string) - ret3, _ := ret[3].(error) - return ret0, ret1, ret2, ret3 + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // CreateAccount indicates an expected call of CreateAccount diff --git a/services/status/api.go b/services/status/api.go index f00c3ec60..141b628f6 100644 --- a/services/status/api.go +++ b/services/status/api.go @@ -40,7 +40,7 @@ func (api *PublicAPI) Login(context context.Context, req LoginRequest) (res Logi 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 } @@ -54,18 +54,31 @@ type SignupRequest struct { // SignupResponse : json response returned by status_signup. type SignupResponse struct { - Address string `json:"address"` - Pubkey string `json:"pubkey"` - Mnemonic string `json:"mnemonic"` + Address string `json:"address"` + Pubkey string `json:"pubkey"` + 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 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()) 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 } diff --git a/services/status/api_test.go b/services/status/api_test.go index 8ac3d83a5..283d8206d 100644 --- a/services/status/api_test.go +++ b/services/status/api_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/golang/mock/gomock" + "github.com/status-im/status-go/account" "github.com/stretchr/testify/suite" ) @@ -49,7 +50,7 @@ var logintests = []struct { } s.am.EXPECT().AddressToDecryptedAccount("address...", "password").Return(accounts.Account{}, &key, 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.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", expectedResponse: SignupResponse{ - Address: "addr", - Pubkey: "pubkey", - Mnemonic: "mnemonic", + WalletAddress: "addr", + WalletPubkey: "pubkey", + Mnemonic: "mnemonic", }, expectedError: nil, 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", expectedResponse: SignupResponse{ - Address: "", - Pubkey: "", - Mnemonic: "", + WalletAddress: "", + WalletPubkey: "", + Mnemonic: "", }, expectedError: errors.New("could not create the specified account : foo"), 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 res, err := s.api.Signup(ctx, SignupRequest{Password: "password"}) - s.Equal(t.expectedResponse.Address, res.Address, "failed scenario : "+t.name) - s.Equal(t.expectedResponse.Pubkey, res.Pubkey, "failed scenario : "+t.name) + s.Equal(t.expectedResponse.WalletAddress, res.WalletAddress, "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.expectedError, err, "failed scenario : "+t.name) } diff --git a/services/status/service.go b/services/status/service.go index 7c02448f2..701627ca8 100644 --- a/services/status/service.go +++ b/services/status/service.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" + "github.com/status-im/status-go/account" ) // Make sure that Service implements node.Service interface. @@ -21,8 +22,8 @@ type WhisperService interface { // AccountManager interface to manage account actions type AccountManager interface { AddressToDecryptedAccount(string, string) (accounts.Account, *keystore.Key, error) - SelectAccount(address, password string) error - CreateAccount(password string) (address, pubKey, mnemonic string, err error) + SelectAccount(walletAddress, chatAddress, password string) error + CreateAccount(password string) (accountInfo account.Info, mnemonic string, err error) } // Service represents our own implementation of status status operations. diff --git a/t/config/public-chain-accounts.json b/t/config/public-chain-accounts.json index 21cf1c866..d6202a393 100644 --- a/t/config/public-chain-accounts.json +++ b/t/config/public-chain-accounts.json @@ -1,8 +1,10 @@ { "Account1": { - "Address": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c" + "WalletAddress": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c", + "ChatAddress": "0xF35E0325dad87e2661c4eF951d58727e6d583d5c" }, "Account2": { - "Address": "0xA0a19221268d939c3a972bf5461dC10f7980E814" + "WalletAddress": "0xA0a19221268d939c3a972bf5461dC10f7980E814", + "ChatAddress": "0xA0a19221268d939c3a972bf5461dC10f7980E814" } } diff --git a/t/config/status-chain-accounts.json b/t/config/status-chain-accounts.json index 4e0a35f23..f452006b3 100644 --- a/t/config/status-chain-accounts.json +++ b/t/config/status-chain-accounts.json @@ -1,14 +1,17 @@ { "Account1": { - "Address": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9", + "WalletAddress": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9", + "ChatAddress": "0xbF164ca341326a03b547c05B343b2E21eFAe24b9", "Password": "password" }, "Account2": { - "Address": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C", + "WalletAddress": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C", + "ChatAddress": "0x205a5d0E72ff65079FCaBB4A63E33d28aA6Def2C", "Password": "password" }, "Account3": { - "Address": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4", + "WalletAddress": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4", + "ChatAddress": "0x3ad34e698d4806afd08b359b920f5c6b62b68ee4", "Password": "password" } } diff --git a/t/e2e/accounts/accounts_rpc_test.go b/t/e2e/accounts/accounts_rpc_test.go index 57785e1f8..dd00f2c3f 100644 --- a/t/e2e/accounts/accounts_rpc_test.go +++ b/t/e2e/accounts/accounts_rpc_test.go @@ -23,19 +23,20 @@ func (s *AccountsTestSuite) TestRPCEthAccounts() { defer s.StopTestBackend() // 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) rpcClient := s.Backend.StatusNode().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(`{ "jsonrpc": "2.0", "id": 1, "method": "eth_accounts", "params": [] }`) + s.Equal(expectedResponse, resp) } @@ -50,13 +51,13 @@ func (s *AccountsTestSuite) TestRPCEthAccountsWithUpstream() { defer s.StopTestBackend() // 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) rpcClient := s.Backend.StatusNode().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(`{ "jsonrpc": "2.0", "id": 1, diff --git a/t/e2e/accounts/accounts_test.go b/t/e2e/accounts/accounts_test.go index 5530562a1..b1fec367f 100644 --- a/t/e2e/accounts/accounts_test.go +++ b/t/e2e/accounts/accounts_test.go @@ -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)") // create an account - address, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // 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)") // 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") // at this point main account should show up accounts, err = s.Backend.AccountManager().Accounts() s.NoError(err) s.Equal(1, len(accounts), "exactly single account is expected (main account)") - s.Equal(accounts[0].Hex(), address, - fmt.Sprintf("main account is not retured as the first key: got %s, expected %s", accounts[0].Hex(), "0x"+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"+accountInfo.WalletAddress)) // create sub-account 1 subAccount1, subPubKey1, err := s.Backend.AccountManager().CreateChildAccount("", TestConfig.Account1.Password) @@ -57,7 +57,7 @@ func (s *AccountsTestSuite) TestAccountsList() { accounts, err = s.Backend.AccountManager().Accounts() s.NoError(err) s.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)") - s.Equal(accounts[0].Hex(), 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") // create sub-account 2, index automatically progresses @@ -69,7 +69,7 @@ func (s *AccountsTestSuite) TestAccountsList() { accounts, err = s.Backend.AccountManager().Accounts() s.NoError(err) 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 subAccount1MatchesKey2 := accounts[2].Hex() != "0x"+subAccount1 @@ -89,11 +89,12 @@ func (s *AccountsTestSuite) TestCreateChildAccount() { s.NotNil(keyStore) // 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.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") // 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) 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") // try to create sub-account with wrong password @@ -136,17 +137,19 @@ func (s *AccountsTestSuite) TestRecoverAccount() { s.NoError(err) // 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.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 - 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.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 - acc, err := account.ParseAccountString(address) + acc, err := account.ParseAccountString(accountInfo.WalletAddress) s.NoError(err, "can not get acc from address") 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") - 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.False(address != addressCheck || pubKey != pubKeyCheck, - "incorrect acc details recovered (for non-cached acc)") + s.EqualValues(accountInfo, accountInfoCheck, "incorrect acc details recovered (for non-cached acc)") // make sure that extended key exists and is imported ok too _, key, err = keyStore.AccountDecryptedKey(acc, TestConfig.Account1.Password) @@ -166,10 +168,9 @@ func (s *AccountsTestSuite) TestRecoverAccount() { s.Equal(extChild2String, key.ExtendedKey.String(), "CKD#2 key mismatch") // make sure that calling import several times, just returns from cache (no error is expected) - addressCheck, pubKeyCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic) + accountInfoCheck, err = s.Backend.AccountManager().RecoverAccount(TestConfig.Account1.Password, mnemonic) s.NoError(err, "recover acc failed (for non-cached acc)") - s.False(address != addressCheck || pubKey != pubKeyCheck, - "incorrect acc details recovered (for non-cached acc)") + s.EqualValues(accountInfo, accountInfoCheck, "incorrect acc details recovered (for non-cached acc)") } func (s *AccountsTestSuite) TestSelectAccount() { @@ -177,46 +178,51 @@ func (s *AccountsTestSuite) TestSelectAccount() { defer s.StopTestBackend() // 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.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.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 - 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") 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) // 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() { s.StartTestBackend() // create test accounts - address1, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) - address2, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // 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.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 - 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") 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) nodeConfig := s.Backend.StatusNode().Config() @@ -225,19 +231,27 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() { s.NoError(s.Backend.StopNode()) // 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.NotNil(selectedAccount) - s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected") + s.NotNil(selectedChatAccount) + s.Equal(selectedChatAccount.Address.Hex(), accountInfo2.ChatAddress, "incorrect chat address selected") // resume node s.Require().NoError(s.Backend.StartNode(&preservedNodeConfig)) // re-check selected account (account2 MUST be selected) - selectedAccount, err = s.Backend.AccountManager().SelectedWalletAccount() + selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount() s.NoError(err) - s.NotNil(selectedAccount) - s.Equal(selectedAccount.Address.Hex(), address2, "incorrect address selected") + s.NotNil(selectedWalletAccount) + 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 s.RestartTestNode() @@ -247,7 +261,10 @@ func (s *AccountsTestSuite) TestSelectedAccountOnRestart() { s.NoError(s.Backend.Logout()) s.RestartTestNode() - selectedAccount, err = s.Backend.AccountManager().SelectedWalletAccount() + selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount() 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) } diff --git a/t/e2e/rpc/rpc_test.go b/t/e2e/rpc/rpc_test.go index a942eb489..b194312c0 100644 --- a/t/e2e/rpc/rpc_test.go +++ b/t/e2e/rpc/rpc_test.go @@ -3,12 +3,11 @@ package rpc import ( "context" "fmt" + "math/big" "sync" "testing" "time" - "math/big" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/status-im/status-go/node" "github.com/status-im/status-go/params" @@ -174,7 +173,7 @@ func (s *RPCTestSuite) TestCallContextResult() { defer cancel() 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.True(balance.ToInt().Cmp(big.NewInt(0)) > 0, "balance should be higher than 0") } diff --git a/t/e2e/services/personal_api_test.go b/t/e2e/services/personal_api_test.go index b89650da2..de835aab1 100644 --- a/t/e2e/services/personal_api_test.go +++ b/t/e2e/services/personal_api_test.go @@ -5,9 +5,8 @@ import ( "testing" "github.com/status-im/status-go/params" - "github.com/stretchr/testify/suite" - . "github.com/status-im/status-go/t/utils" + "github.com/stretchr/testify/suite" ) const ( @@ -65,7 +64,7 @@ func (s *PersonalSignSuite) TestPersonalSignUnsupportedMethod() { basicCall := fmt.Sprintf( `{"jsonrpc":"2.0","method":"personal_sign","params":["%s", "%s"],"id":67}`, signDataString, - TestConfig.Account1.Address) + TestConfig.Account1.WalletAddress) rawResult, err := s.Backend.CallRPC(basicCall) s.NoError(err) diff --git a/t/e2e/services/status_api_test.go b/t/e2e/services/status_api_test.go index c02acdf1c..582efe63b 100644 --- a/t/e2e/services/status_api_test.go +++ b/t/e2e/services/status_api_test.go @@ -9,9 +9,8 @@ import ( "github.com/status-im/status-go/account" "github.com/status-im/status-go/params" "github.com/status-im/status-go/services/status" - "github.com/stretchr/testify/suite" - . "github.com/status-im/status-go/t/utils" + "github.com/stretchr/testify/suite" ) type statusTestParams struct { @@ -62,7 +61,7 @@ func (s *StatusAPISuite) TestAccessibleStatusAPIs() { func (s *StatusAPISuite) TestStatusLoginSuccess() { addressKeyID := s.testStatusLogin(statusTestParams{ - Address: TestConfig.Account1.Address, + Address: TestConfig.Account1.WalletAddress, Password: TestConfig.Account1.Password, }) s.NotEmpty(addressKeyID) @@ -90,13 +89,13 @@ func (s *StatusAPISuite) TestStatusSignupSuccess() { res := s.testStatusSignup(statusTestParams{ Password: pwd, }) - s.NotEmpty(res.Address) - s.NotEmpty(res.Pubkey) + s.NotEmpty(res.WalletAddress) + s.NotEmpty(res.WalletPubkey) s.Equal(12, len(strings.Split(res.Mnemonic, " "))) // I should be able to login with the newly created account _ = s.testStatusLogin(statusTestParams{ - Address: res.Address, + Address: res.WalletAddress, Password: pwd, }) } diff --git a/t/e2e/transactions/transactions_test.go b/t/e2e/transactions/transactions_test.go index 32ab1a1d9..ef8fb9ee7 100644 --- a/t/e2e/transactions/transactions_test.go +++ b/t/e2e/transactions/transactions_test.go @@ -70,7 +70,7 @@ func (s *TransactionsTestSuite) TestCallUpstreamPrivateRPCSendTransaction() { func (s *TransactionsTestSuite) sendTransactionUsingRPCClient( 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) result, err := callRPCFn(`{ @@ -78,7 +78,7 @@ func (s *TransactionsTestSuite) sendTransactionUsingRPCClient( "id": 1, "method": "eth_sendTransaction", "params": [{ - "from": "` + TestConfig.Account1.Address + `", + "from": "` + TestConfig.Account1.WalletAddress + `", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "value": "0x9184e72a" }] @@ -94,11 +94,11 @@ func (s *TransactionsTestSuite) TestEmptyToFieldPreserved() { defer s.StopTestBackend() 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) args := transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), } hash, err := s.Backend.SendTransaction(args, TestConfig.Account1.Password) @@ -162,7 +162,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc 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) // this call blocks, up until Complete Transaction is called @@ -171,7 +171,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc gas := uint64(params.DefaultGas) args := transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), To: nil, // marker, contract creation is expected //Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)), Gas: (*hexutil.Uint64)(&gas), @@ -196,12 +196,12 @@ func (s *TransactionsTestSuite) TestSendEther() { 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) hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }, TestConfig.Account1.Password) s.NoError(err) @@ -216,12 +216,12 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() { s.StartTestBackend(e2e.WithUpstream(addr)) 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) hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), GasPrice: (*hexutil.Big)(big.NewInt(28000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }, TestConfig.Account1.Password) diff --git a/t/e2e/whisper/whisper_test.go b/t/e2e/whisper/whisper_test.go index 52dafdd38..516d8e92e 100644 --- a/t/e2e/whisper/whisper_test.go +++ b/t/e2e/whisper/whisper_test.go @@ -37,7 +37,7 @@ func (s *WhisperTestSuite) TestWhisperFilterRace() { whisperAPI := whisper.NewPublicWhisperAPI(whisperService) // account1 - _, accountKey1, err := accountManager.AddressToDecryptedAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) + _, accountKey1, err := accountManager.AddressToDecryptedAccount(TestConfig.Account1.ChatAddress, TestConfig.Account1.Password) s.NoError(err) accountKey1Byte := crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey) @@ -47,7 +47,7 @@ func (s *WhisperTestSuite) TestWhisperFilterRace() { s.True(ok, "identity not injected") // account2 - _, accountKey2, err := accountManager.AddressToDecryptedAccount(TestConfig.Account2.Address, TestConfig.Account2.Password) + _, accountKey2, err := accountManager.AddressToDecryptedAccount(TestConfig.Account2.ChatAddress, TestConfig.Account2.Password) s.NoError(err) key2ID, err := whisperService.AddKeyPair(accountKey2.PrivateKey) s.NoError(err) @@ -96,21 +96,31 @@ func (s *WhisperTestSuite) TestSelectAccount() { whisperService, err := s.Backend.StatusNode().WhisperService() s.NoError(err) - // create an acc - address, pubKey, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) + // create account 1 + accountInfo1, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) - // make sure that identity is not (yet injected) - s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") + // create account 2 + 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 - err = s.Backend.SelectAccount(address, "wrongPassword") + err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, "wrongpassword") s.NotNil(err) - // select another account, make sure that previous account is wiped out from Whisper cache - s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") - s.NoError(s.Backend.SelectAccount(address, TestConfig.Account1.Password)) - s.True(whisperService.HasKeyPair(pubKey), "identity not injected into whisper") + // select account 1 + err = s.Backend.SelectAccount(accountInfo1.WalletAddress, accountInfo1.ChatAddress, TestConfig.Account1.Password) + s.NoError(err) + s.True(whisperService.HasKeyPair(accountInfo1.ChatPubKey), "identity not injected in whisper") + + // select account 2, make sure that previous account is wiped out from Whisper cache + s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper") + s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password)) + s.True(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity not injected into whisper") } func (s *WhisperTestSuite) TestLogout() { @@ -121,16 +131,16 @@ func (s *WhisperTestSuite) TestLogout() { s.NoError(err) // 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) // make sure that identity doesn't exist (yet) in Whisper - s.False(whisperService.HasKeyPair(pubKey), "identity already present in whisper") - s.NoError(s.Backend.SelectAccount(address, TestConfig.Account1.Password)) - s.True(whisperService.HasKeyPair(pubKey), "identity not injected into whisper") + s.False(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity already present in whisper") + s.NoError(s.Backend.SelectAccount(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password)) + s.True(whisperService.HasKeyPair(accountInfo.ChatPubKey), "identity not injected into whisper") 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() { @@ -140,15 +150,15 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() { whisperService := s.WhisperService() // 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) - address2, pubKey2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password) + accountInfo2, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account2.Password) s.NoError(err) // 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() s.EqualError(account.ErrNoAccountSelected, err.Error(), "account selected, but should not be") s.Nil(selectedWalletAccount) @@ -159,25 +169,25 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() { s.Nil(selectedChatAccount) // 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") s.EqualError(expectedErr, err.Error()) // 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() s.NoError(err) 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") // select another account, make sure that previous account is wiped out from Whisper cache - s.False(whisperService.HasKeyPair(pubKey2), "identity already present in whisper") - s.NoError(s.Backend.SelectAccount(address2, TestConfig.Account2.Password)) + s.False(whisperService.HasKeyPair(accountInfo2.ChatPubKey), "identity already present in whisper") + s.NoError(s.Backend.SelectAccount(accountInfo2.WalletAddress, accountInfo2.ChatAddress, TestConfig.Account2.Password)) selectedChatAccount2, err := s.Backend.AccountManager().SelectedChatAccount() s.NoError(err) selectedChatPubKey2 := hexutil.Encode(crypto.FromECDSAPub(&selectedChatAccount2.AccountKey.PrivateKey.PublicKey)) - s.Equal(selectedChatPubKey2, pubKey2) + s.Equal(selectedChatPubKey2, accountInfo2.ChatPubKey) 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") @@ -194,7 +204,11 @@ func (s *WhisperTestSuite) TestSelectedAccountOnRestart() { selectedWalletAccount, err = s.Backend.AccountManager().SelectedWalletAccount() s.NoError(err) 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 whisperService = s.WhisperService() @@ -233,11 +247,11 @@ func (s *WhisperTestSuite) TestSelectedChatKeyIsUsedInWhisper() { s.NoError(err) // create an account - address, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) + accountInfo, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password) s.NoError(err) // 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 selectedChatAccount, err := s.Backend.AccountManager().SelectedChatAccount() diff --git a/t/utils/utils.go b/t/utils/utils.go index 3c1422536..d017b6c68 100644 --- a/t/utils/utils.go +++ b/t/utils/utils.go @@ -19,11 +19,9 @@ import ( "testing" "time" - "github.com/status-im/status-go/logutils" - "github.com/ethereum/go-ethereum/log" + "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/params" - _ "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 { - Address string - Password string + WalletAddress string + ChatAddress string + Password string } // testConfig contains shared (among different test packages) parameters diff --git a/transactions/transactor_test.go b/transactions/transactor_test.go index 22bdb9ab1..5a9b759cd 100644 --- a/transactions/transactor_test.go +++ b/transactions/transactor_test.go @@ -21,14 +21,12 @@ import ( "github.com/ethereum/go-ethereum/rlp" gethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/golang/mock/gomock" - "github.com/stretchr/testify/suite" - "github.com/status-im/status-go/account" "github.com/status-im/status-go/params" "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/transactions/fake" + "github.com/stretchr/testify/suite" ) func TestTransactorSuite(t *testing.T) { @@ -120,7 +118,7 @@ func (s *TransactorSuite) rlpEncodeTx(args SendTxArgs, config *params.NodeConfig func (s *TransactorSuite) TestGasValues() { key, _ := crypto.GenerateKey() selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(TestConfig.Account1.Address), + Address: account.FromAddress(TestConfig.Account1.WalletAddress), AccountKey: &keystore.Key{PrivateKey: key}, } testCases := []struct { @@ -154,8 +152,8 @@ func (s *TransactorSuite) TestGasValues() { s.T().Run(testCase.name, func(t *testing.T) { s.SetupTest() args := SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Gas: testCase.gas, GasPrice: testCase.gasPrice, } @@ -170,14 +168,14 @@ func (s *TransactorSuite) TestGasValues() { func (s *TransactorSuite) TestArgsValidation() { args := SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), Data: hexutil.Bytes([]byte{0x01, 0x02}), Input: hexutil.Bytes([]byte{0x02, 0x01}), } s.False(args.Valid()) selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(TestConfig.Account1.Address), + Address: account.FromAddress(TestConfig.Account1.WalletAddress), } _, err := s.manager.SendTransaction(args, selectedAccount) s.EqualError(err, ErrInvalidSendTxArgs.Error()) @@ -185,8 +183,8 @@ func (s *TransactorSuite) TestArgsValidation() { func (s *TransactorSuite) TestAccountMismatch() { args := SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), } var err error @@ -197,7 +195,7 @@ func (s *TransactorSuite) TestAccountMismatch() { // mismatched accounts selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(TestConfig.Account2.Address), + Address: account.FromAddress(TestConfig.Account2.WalletAddress), } _, err = s.manager.SendTransaction(args, selectedAccount) s.EqualError(err, ErrInvalidTxSender.Error()) @@ -214,15 +212,15 @@ func (s *TransactorSuite) TestLocalNonce() { txCount := 3 key, _ := crypto.GenerateKey() selectedAccount := &account.SelectedExtKey{ - Address: account.FromAddress(TestConfig.Account1.Address), + Address: account.FromAddress(TestConfig.Account1.WalletAddress), AccountKey: &keystore.Key{PrivateKey: key}, } nonce := hexutil.Uint64(0) for i := 0; i < txCount; i++ { args := SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), } s.setupTransactionPoolAPI(args, nonce, hexutil.Uint64(i), selectedAccount, nil) @@ -234,8 +232,8 @@ func (s *TransactorSuite) TestLocalNonce() { nonce = hexutil.Uint64(5) args := SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), } s.setupTransactionPoolAPI(args, nonce, nonce, selectedAccount, nil) @@ -249,8 +247,8 @@ func (s *TransactorSuite) TestLocalNonce() { testErr := errors.New("test") s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), selectedAccount.Address, gethrpc.PendingBlockNumber).Return(nil, testErr) args = SendTxArgs{ - From: account.FromAddress(TestConfig.Account1.Address), - To: account.ToAddress(TestConfig.Account2.Address), + From: account.FromAddress(TestConfig.Account1.WalletAddress), + To: account.ToAddress(TestConfig.Account2.WalletAddress), } _, err = s.manager.SendTransaction(args, selectedAccount)