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
// 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
}

View File

@ -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,
@ -168,8 +177,10 @@ type ManagerTestSuite struct {
type testAccount struct {
password string
address string
pubKey string
walletAddress string
walletPubKey string
chatAddress string
chatPubKey string
mnemonic string
}
@ -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()
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 {

View File

@ -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

View File

@ -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
}
}

View File

@ -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)

View File

@ -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,8 +255,12 @@ func CreateAccount(password *C.char) *C.char {
}
out := AccountInfo{
Address: address,
PubKey: pubKey,
Address: info.WalletAddress,
PubKey: info.WalletPubKey,
WalletAddress: info.WalletAddress,
WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: mnemonic,
Error: errString,
}
@ -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,8 +300,12 @@ func RecoverAccount(password, mnemonic *C.char) *C.char {
}
out := AccountInfo{
Address: address,
PubKey: pubKey,
Address: info.WalletAddress,
PubKey: info.WalletPubKey,
WalletAddress: info.WalletAddress,
WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: C.GoString(mnemonic),
Error: errString,
}
@ -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)
}

View File

@ -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 {

View File

@ -64,8 +64,12 @@ func (e APIError) Error() string {
// AccountInfo represents account's info.
type AccountInfo struct {
Address string `json:"address"`
PubKey string `json:"pubkey"`
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"`
}

View File

@ -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 (

View File

@ -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

View File

@ -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
}
@ -56,16 +56,29 @@ type SignupRequest struct {
type SignupResponse struct {
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
}

View File

@ -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",
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: "",
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)
}

View File

@ -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.

View File

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

View File

@ -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"
}
}

View File

@ -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,

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)")
// 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)
}

View File

@ -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")
}

View File

@ -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)

View File

@ -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,
})
}

View File

@ -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)

View File

@ -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()

View File

@ -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,7 +305,8 @@ func MakeTestNodeConfigWithDataDir(name, dataDir string, networkID uint64) (*par
}
type account struct {
Address string
WalletAddress string
ChatAddress string
Password string
}

View File

@ -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)