2018-03-29 09:20:55 +00:00
|
|
|
// +build e2e_test
|
|
|
|
|
|
|
|
// This is a file with e2e tests for C bindings written in library.go.
|
|
|
|
// As a CGO file, it can't have `_test.go` suffix as it's not allowed by Go.
|
|
|
|
// At the same time, we don't want this file to be included in the binaries.
|
|
|
|
// This is why `e2e_test` tag was introduced. Without it, this file is excluded
|
|
|
|
// from the build. Providing this tag will include this file into the build
|
|
|
|
// and that's what is done while running e2e tests for `lib/` package.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import "C"
|
|
|
|
import (
|
2019-01-24 15:44:46 +00:00
|
|
|
"encoding/hex"
|
2018-03-29 09:20:55 +00:00
|
|
|
"encoding/json"
|
2019-07-26 14:45:10 +00:00
|
|
|
"fmt"
|
2018-03-29 09:20:55 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"math/big"
|
|
|
|
"os"
|
2018-09-13 16:31:29 +00:00
|
|
|
"path"
|
2018-03-29 09:20:55 +00:00
|
|
|
"path/filepath"
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
2018-03-29 09:20:55 +00:00
|
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
2019-01-24 15:44:46 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2018-06-08 11:29:50 +00:00
|
|
|
"github.com/status-im/status-go/account"
|
2018-05-03 07:35:58 +00:00
|
|
|
"github.com/status-im/status-go/signal"
|
2018-03-29 09:20:55 +00:00
|
|
|
. "github.com/status-im/status-go/t/utils" //nolint: golint
|
2018-06-08 11:29:50 +00:00
|
|
|
"github.com/status-im/status-go/transactions"
|
2019-01-18 09:01:14 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-03-29 09:20:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const initJS = `
|
|
|
|
var _status_catalog = {
|
|
|
|
foo: 'bar'
|
|
|
|
};`
|
|
|
|
|
2018-04-10 10:02:54 +00:00
|
|
|
var (
|
2018-08-16 11:37:53 +00:00
|
|
|
zeroHash = gethcommon.Hash{}
|
2018-04-10 10:02:54 +00:00
|
|
|
testChainDir string
|
|
|
|
nodeConfigJSON string
|
|
|
|
)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2019-07-26 14:45:10 +00:00
|
|
|
func buildLoginParamsJSON(chatAddress, password string) *C.char {
|
|
|
|
return C.CString(fmt.Sprintf(`{
|
|
|
|
"chatAddress": "%s",
|
|
|
|
"password": "%s",
|
|
|
|
"mainAccount": "%s"
|
|
|
|
}`, chatAddress, password, chatAddress))
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildLoginParams(mainAccountAddress, chatAddress, password string) account.LoginParams {
|
|
|
|
return account.LoginParams{
|
|
|
|
ChatAddress: gethcommon.HexToAddress(chatAddress),
|
|
|
|
Password: password,
|
|
|
|
MainAccount: gethcommon.HexToAddress(mainAccountAddress),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-29 09:20:55 +00:00
|
|
|
func init() {
|
|
|
|
testChainDir = filepath.Join(TestDataDir, TestNetworkNames[GetNetworkID()])
|
|
|
|
|
|
|
|
nodeConfigJSON = `{
|
|
|
|
"NetworkId": ` + strconv.Itoa(GetNetworkID()) + `,
|
|
|
|
"DataDir": "` + testChainDir + `",
|
2018-09-13 16:31:29 +00:00
|
|
|
"KeyStoreDir": "` + filepath.Join(testChainDir, "keystore") + `",
|
2018-03-29 09:20:55 +00:00
|
|
|
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
2018-09-13 16:31:29 +00:00
|
|
|
"LogLevel": "INFO",
|
|
|
|
"NoDiscovery": true,
|
|
|
|
"LightEthConfig": {
|
|
|
|
"Enabled": true
|
|
|
|
},
|
|
|
|
"WhisperConfig": {
|
|
|
|
"Enabled": true,
|
|
|
|
"DataDir": "` + path.Join(testChainDir, "wnode") + `",
|
|
|
|
"EnableNTPSync": false
|
2019-01-17 12:56:22 +00:00
|
|
|
},
|
|
|
|
"ShhextConfig": {
|
|
|
|
"BackupDisabledDataDir": "` + testChainDir + `"
|
2018-09-13 16:31:29 +00:00
|
|
|
}
|
2018-03-29 09:20:55 +00:00
|
|
|
}`
|
|
|
|
}
|
|
|
|
|
|
|
|
// nolint: deadcode
|
|
|
|
func testExportedAPI(t *testing.T, done chan struct{}) {
|
|
|
|
<-startTestNode(t)
|
|
|
|
defer func() {
|
|
|
|
done <- struct{}{}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// prepare accounts
|
|
|
|
testKeyDir := filepath.Join(testChainDir, "keystore")
|
2018-04-04 17:39:38 +00:00
|
|
|
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
2018-04-04 17:39:38 +00:00
|
|
|
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(tiabc): All of that is done because usage of cgo is not supported in tests.
|
|
|
|
// Probably, there should be a cleaner way, for example, test cgo bindings in e2e tests
|
|
|
|
// separately from other internal tests.
|
|
|
|
// FIXME(@jekamas): ATTENTION! this tests depends on each other!
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
fn func(t *testing.T) bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"stop/resume node",
|
|
|
|
testStopResumeNode,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"call RPC on in-proc handler",
|
|
|
|
testCallRPC,
|
|
|
|
},
|
2018-04-16 08:01:37 +00:00
|
|
|
{
|
|
|
|
"call private API using RPC",
|
|
|
|
testCallRPCWithPrivateAPI,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"call private API using private RPC client",
|
|
|
|
testCallPrivateRPCWithPrivateAPI,
|
|
|
|
},
|
2018-03-29 09:20:55 +00:00
|
|
|
{
|
|
|
|
"verify account password",
|
|
|
|
testVerifyAccountPassword,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"recover account",
|
|
|
|
testRecoverAccount,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"account select/login",
|
|
|
|
testAccountSelect,
|
|
|
|
},
|
2019-01-24 15:44:46 +00:00
|
|
|
{
|
|
|
|
"login with keycard",
|
|
|
|
testLoginWithKeycard,
|
|
|
|
},
|
2018-03-29 09:20:55 +00:00
|
|
|
{
|
|
|
|
"account logout",
|
|
|
|
testAccountLogout,
|
|
|
|
},
|
|
|
|
{
|
2018-08-16 11:37:53 +00:00
|
|
|
"send transaction",
|
|
|
|
testSendTransaction,
|
2018-03-29 09:20:55 +00:00
|
|
|
},
|
|
|
|
{
|
2018-08-16 11:37:53 +00:00
|
|
|
"send transaction with invalid password",
|
|
|
|
testSendTransactionInvalidPassword,
|
2018-03-29 09:20:55 +00:00
|
|
|
},
|
|
|
|
{
|
2018-08-16 11:37:53 +00:00
|
|
|
"failed single transaction",
|
|
|
|
testFailedTransaction,
|
2018-03-29 09:20:55 +00:00
|
|
|
},
|
2019-07-24 18:59:15 +00:00
|
|
|
{
|
2019-07-26 09:33:38 +00:00
|
|
|
"MultiAccount - Generate/Derive/StoreDerived/Load/Reset",
|
|
|
|
testMultiAccountGenerateDeriveStoreLoadReset,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"MultiAccount - ImportMnemonic/Derive",
|
|
|
|
testMultiAccountImportMnemonicAndDerive,
|
2019-07-24 18:59:15 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"MultiAccount - GenerateAndDerive",
|
|
|
|
testMultiAccountGenerateAndDerive,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"MultiAccount - Import/Store",
|
|
|
|
testMultiAccountImportStore,
|
|
|
|
},
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Logf("=== RUN %s", test.name)
|
|
|
|
if ok := test.fn(t); !ok {
|
|
|
|
t.Logf("=== FAILED %s", test.name)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testVerifyAccountPassword(t *testing.T) bool {
|
|
|
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "accounts")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
|
|
|
|
2018-04-04 17:39:38 +00:00
|
|
|
if err = ImportTestAccount(tmpDir, GetAccount1PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-04-04 17:39:38 +00:00
|
|
|
if err = ImportTestAccount(tmpDir, GetAccount2PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// rename account file (to see that file's internals reviewed, when locating account key)
|
|
|
|
accountFilePathOriginal := filepath.Join(tmpDir, GetAccount1PKFile())
|
2019-01-18 09:01:14 +00:00
|
|
|
accountFilePath := filepath.Join(tmpDir, "foo"+TestConfig.Account1.WalletAddress+"bar.pk")
|
2018-03-29 09:20:55 +00:00
|
|
|
if err := os.Rename(accountFilePathOriginal, accountFilePath); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
response := APIResponse{}
|
|
|
|
rawResponse := VerifyAccountPassword(
|
|
|
|
C.CString(tmpDir),
|
2019-01-18 09:01:14 +00:00
|
|
|
C.CString(TestConfig.Account1.WalletAddress),
|
2018-03-29 09:20:55 +00:00
|
|
|
C.CString(TestConfig.Account1.Password))
|
|
|
|
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
|
|
|
|
t.Errorf("cannot decode response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if response.Error != "" {
|
|
|
|
t.Errorf("unexpected error: %s", response.Error)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
//@TODO(adam): quarantined this test until it uses a different directory.
|
|
|
|
//nolint: deadcode
|
|
|
|
func testResetChainData(t *testing.T) bool {
|
|
|
|
t.Skip()
|
|
|
|
|
|
|
|
resetChainDataResponse := APIResponse{}
|
|
|
|
rawResponse := ResetChainData()
|
|
|
|
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &resetChainDataResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode ResetChainData response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if resetChainDataResponse.Error != "" {
|
|
|
|
t.Errorf("unexpected error: %s", resetChainDataResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-06-19 07:49:24 +00:00
|
|
|
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
|
2018-08-16 11:37:53 +00:00
|
|
|
testSendTransaction(t)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStopResumeNode(t *testing.T) bool { //nolint: gocyclo
|
|
|
|
// to make sure that we start with empty account (which might have gotten populated during previous tests)
|
2018-06-19 07:49:24 +00:00
|
|
|
if err := statusBackend.Logout(); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-19 07:49:24 +00:00
|
|
|
whisperService, err := statusBackend.StatusNode().WhisperService()
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an account
|
2019-01-18 09:01:14 +00:00
|
|
|
account1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("could not create account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Logf("account created: {address: %s, key: %s}", account1.WalletAddress, account1.WalletPubKey)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// make sure that identity is not (yet injected)
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(account1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
}
|
|
|
|
|
|
|
|
// select account
|
|
|
|
loginResponse := APIResponse{}
|
2019-07-26 14:45:10 +00:00
|
|
|
rawResponse := Login(buildLoginParamsJSON(account1.WalletAddress, TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if loginResponse.Error != "" {
|
|
|
|
t.Errorf("could not select account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(account1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Errorf("identity not injected into whisper: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// stop and resume node, then make sure that selected account is still selected
|
|
|
|
// nolint: dupl
|
|
|
|
stopNodeFn := func() bool {
|
|
|
|
response := APIResponse{}
|
|
|
|
// FIXME(tiabc): Implement https://github.com/status-im/status-go/issues/254 to avoid
|
|
|
|
// 9-sec timeout below after stopping the node.
|
|
|
|
rawResponse = StopNode()
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
|
|
|
|
t.Errorf("cannot decode StopNode response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if response.Error != "" {
|
|
|
|
t.Errorf("unexpected error: %s", response.Error)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// nolint: dupl
|
|
|
|
resumeNodeFn := func() bool {
|
|
|
|
response := APIResponse{}
|
|
|
|
// FIXME(tiabc): Implement https://github.com/status-im/status-go/issues/254 to avoid
|
|
|
|
// 10-sec timeout below after resuming the node.
|
|
|
|
rawResponse = StartNode(C.CString(nodeConfigJSON))
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &response); err != nil {
|
|
|
|
t.Errorf("cannot decode StartNode response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if response.Error != "" {
|
|
|
|
t.Errorf("unexpected error: %s", response.Error)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if !stopNodeFn() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(9 * time.Second) // allow to stop
|
|
|
|
|
|
|
|
if !resumeNodeFn() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(10 * time.Second) // allow to start (instead of using blocking version of start, of filter event)
|
|
|
|
|
|
|
|
// now, verify that we still have account logged in
|
2018-06-19 07:49:24 +00:00
|
|
|
whisperService, err = statusBackend.StatusNode().WhisperService()
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(account1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Errorf("identity evicted from whisper on node restart: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// additionally, let's complete transaction (just to make sure that node lives through pause/resume w/o issues)
|
2018-08-16 11:37:53 +00:00
|
|
|
testSendTransaction(t)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCallRPC(t *testing.T) bool {
|
|
|
|
expected := `{"jsonrpc":"2.0","id":64,"result":"0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"}`
|
|
|
|
rawResponse := CallRPC(C.CString(`{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}`))
|
|
|
|
received := C.GoString(rawResponse)
|
|
|
|
if expected != received {
|
|
|
|
t.Errorf("unexpected response: expected: %v, got: %v", expected, received)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-04-16 08:01:37 +00:00
|
|
|
func testCallRPCWithPrivateAPI(t *testing.T) bool {
|
|
|
|
expected := `{"jsonrpc":"2.0","id":64,"error":{"code":-32601,"message":"The method admin_nodeInfo does not exist/is not available"}}`
|
|
|
|
rawResponse := CallRPC(C.CString(`{"jsonrpc":"2.0","method":"admin_nodeInfo","params":[],"id":64}`))
|
|
|
|
received := C.GoString(rawResponse)
|
|
|
|
if expected != received {
|
|
|
|
t.Errorf("unexpected response: expected: %v, got: %v", expected, received)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCallPrivateRPCWithPrivateAPI(t *testing.T) bool {
|
|
|
|
rawResponse := CallPrivateRPC(C.CString(`{"jsonrpc":"2.0","method":"admin_nodeInfo","params":[],"id":64}`))
|
|
|
|
received := C.GoString(rawResponse)
|
|
|
|
if strings.Contains(received, "error") {
|
|
|
|
t.Errorf("unexpected response containing error: %v", received)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-03-29 09:20:55 +00:00
|
|
|
func testRecoverAccount(t *testing.T) bool { //nolint: gocyclo
|
2019-08-01 09:27:06 +00:00
|
|
|
keyStore, _ := statusBackend.StatusNode().AccountKeyStore()
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// create an account
|
2019-01-18 09:01:14 +00:00
|
|
|
accountInfo, mnemonic, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("could not create account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", accountInfo.WalletAddress, accountInfo.WalletPubKey, mnemonic)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// try recovering using password + mnemonic
|
|
|
|
recoverAccountResponse := AccountInfo{}
|
|
|
|
rawResponse := RecoverAccount(C.CString(TestConfig.Account1.Password), C.CString(mnemonic))
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if recoverAccountResponse.Error != "" {
|
|
|
|
t.Errorf("recover account failed: %v", recoverAccountResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
|
|
|
|
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")
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device
|
2019-01-18 09:01:14 +00:00
|
|
|
account, err := account.ParseAccountString(accountInfo.WalletAddress)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("can not get account from address: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
account, key, err := keyStore.AccountDecryptedKey(account, TestConfig.Account1.Password)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
extChild2String := key.ExtendedKey.String()
|
|
|
|
|
|
|
|
if err = keyStore.Delete(account, TestConfig.Account1.Password); err != nil {
|
|
|
|
t.Errorf("cannot remove account: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
recoverAccountResponse = AccountInfo{}
|
|
|
|
rawResponse = RecoverAccount(C.CString(TestConfig.Account1.Password), C.CString(mnemonic))
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if recoverAccountResponse.Error != "" {
|
|
|
|
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
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)")
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that extended key exists and is imported ok too
|
|
|
|
_, key, err = keyStore.AccountDecryptedKey(account, TestConfig.Account1.Password)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("can not obtain decrypted account key: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if extChild2String != key.ExtendedKey.String() {
|
|
|
|
t.Errorf("CKD#2 key mismatch, expected: %s, got: %s", extChild2String, key.ExtendedKey.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that calling import several times, just returns from cache (no error is expected)
|
|
|
|
recoverAccountResponse = AccountInfo{}
|
|
|
|
rawResponse = RecoverAccount(C.CString(TestConfig.Account1.Password), C.CString(mnemonic))
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if recoverAccountResponse.Error != "" {
|
|
|
|
t.Errorf("recover account failed (for non-cached account): %v", recoverAccountResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
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)")
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// time to login with recovered data
|
2018-06-19 07:49:24 +00:00
|
|
|
whisperService, err := statusBackend.StatusNode().WhisperService()
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that identity is not (yet injected)
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(chatPubKeyCheck) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
}
|
2019-07-26 14:45:10 +00:00
|
|
|
err = statusBackend.SelectAccount(buildLoginParams(walletAddressCheck, chatAddressCheck, TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Test failed: could not select account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(chatPubKeyCheck) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Errorf("identity not injected into whisper: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccountSelect(t *testing.T) bool { //nolint: gocyclo
|
|
|
|
// test to see if the account was injected in whisper
|
2018-06-19 07:49:24 +00:00
|
|
|
whisperService, err := statusBackend.StatusNode().WhisperService()
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an account
|
2019-01-18 09:01:14 +00:00
|
|
|
accountInfo1, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("could not create account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Logf("Account created: {address: %s, key: %s}", accountInfo1.WalletAddress, accountInfo1.WalletPubKey)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2019-01-18 09:01:14 +00:00
|
|
|
accountInfo2, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error("Test failed: could not create account")
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Logf("Account created: {address: %s, key: %s}", accountInfo2.WalletAddress, accountInfo2.WalletPubKey)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// make sure that identity is not (yet injected)
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
}
|
|
|
|
|
|
|
|
// try selecting with wrong password
|
|
|
|
loginResponse := APIResponse{}
|
2019-07-26 14:45:10 +00:00
|
|
|
rawResponse := Login(buildLoginParamsJSON(accountInfo1.WalletAddress, "wrongPassword"))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if loginResponse.Error == "" {
|
|
|
|
t.Error("select account is expected to throw error: wrong password used")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
loginResponse = APIResponse{}
|
2019-07-26 14:45:10 +00:00
|
|
|
rawResponse = Login(buildLoginParamsJSON(accountInfo1.WalletAddress, TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if loginResponse.Error != "" {
|
|
|
|
t.Errorf("Test failed: could not select account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Errorf("identity not injected into whisper: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// select another account, make sure that previous account is wiped out from Whisper cache
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(accountInfo2.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
}
|
|
|
|
|
|
|
|
loginResponse = APIResponse{}
|
2019-07-26 14:45:10 +00:00
|
|
|
rawResponse = Login(buildLoginParamsJSON(accountInfo2.WalletAddress, TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if loginResponse.Error != "" {
|
|
|
|
t.Errorf("Test failed: could not select account: %v", loginResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(accountInfo2.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Errorf("identity not injected into whisper: %v", err)
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(accountInfo1.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity should be removed, but it is still present in whisper")
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-01-24 15:44:46 +00:00
|
|
|
func testLoginWithKeycard(t *testing.T) bool { //nolint: gocyclo
|
|
|
|
chatPrivKey, err := crypto.GenerateKey()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error generating chat key")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
chatPrivKeyHex := hex.EncodeToString(crypto.FromECDSA(chatPrivKey))
|
|
|
|
|
|
|
|
encryptionPrivKey, err := crypto.GenerateKey()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error generating encryption key")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
encryptionPrivKeyHex := hex.EncodeToString(crypto.FromECDSA(encryptionPrivKey))
|
|
|
|
|
|
|
|
whisperService, err := statusBackend.StatusNode().WhisperService()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chatPubKeyHex := hexutil.Encode(crypto.FromECDSAPub(&chatPrivKey.PublicKey))
|
|
|
|
if whisperService.HasKeyPair(chatPubKeyHex) {
|
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
loginResponse := APIResponse{}
|
|
|
|
rawResponse := LoginWithKeycard(C.CString(chatPrivKeyHex), C.CString(encryptionPrivKeyHex))
|
|
|
|
|
|
|
|
if err = json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode LoginWithKeycard response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if loginResponse.Error != "" {
|
|
|
|
t.Errorf("Test failed: could not login with keycard: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if !whisperService.HasKeyPair(chatPubKeyHex) {
|
|
|
|
t.Error("identity not present in whisper after logging in with keycard")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-03-29 09:20:55 +00:00
|
|
|
func testAccountLogout(t *testing.T) bool {
|
2018-06-19 07:49:24 +00:00
|
|
|
whisperService, err := statusBackend.StatusNode().WhisperService()
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("whisper service not running: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// create an account
|
2019-01-18 09:01:14 +00:00
|
|
|
accountInfo, _, err := statusBackend.AccountManager().CreateAccount(TestConfig.Account1.Password)
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("could not create account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that identity doesn't exist (yet) in Whisper
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(accountInfo.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity already present in whisper")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// select/login
|
2019-07-26 14:45:10 +00:00
|
|
|
err = statusBackend.SelectAccount(buildLoginParams(accountInfo.WalletAddress, accountInfo.ChatAddress, TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Test failed: could not select account: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
2019-01-18 09:01:14 +00:00
|
|
|
if !whisperService.HasKeyPair(accountInfo.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity not injected into whisper")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
logoutResponse := APIResponse{}
|
|
|
|
rawResponse := Logout()
|
|
|
|
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &logoutResponse); err != nil {
|
|
|
|
t.Errorf("cannot decode RecoverAccount response (%s): %v", C.GoString(rawResponse), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if logoutResponse.Error != "" {
|
|
|
|
t.Errorf("cannot logout: %v", logoutResponse.Error)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// now, logout and check if identity is removed indeed
|
2019-01-18 09:01:14 +00:00
|
|
|
if whisperService.HasKeyPair(accountInfo.ChatPubKey) {
|
2018-03-29 09:20:55 +00:00
|
|
|
t.Error("identity not cleared from whisper")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
type jsonrpcAnyResponse struct {
|
|
|
|
Result json.RawMessage `json:"result"`
|
|
|
|
jsonrpcErrorResponse
|
|
|
|
}
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
func testSendTransaction(t *testing.T) bool {
|
2018-06-19 07:49:24 +00:00
|
|
|
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// log into account from which transactions will be sent
|
2019-07-26 14:45:10 +00:00
|
|
|
if err := statusBackend.SelectAccount(buildLoginParams(TestConfig.Account1.WalletAddress, TestConfig.Account1.ChatAddress, TestConfig.Account1.Password)); err != nil {
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
args, err := json.Marshal(transactions.SendTxArgs{
|
2019-01-18 09:01:14 +00:00
|
|
|
From: account.FromAddress(TestConfig.Account1.WalletAddress),
|
|
|
|
To: account.ToAddress(TestConfig.Account2.WalletAddress),
|
2018-03-29 09:20:55 +00:00
|
|
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
|
|
|
})
|
|
|
|
if err != nil {
|
2018-08-16 11:37:53 +00:00
|
|
|
t.Errorf("failed to marshal errors: %v", err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
rawResult := SendTransaction(C.CString(string(args)), C.CString(TestConfig.Account1.Password))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
var result jsonrpcAnyResponse
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResult)), &result); err != nil {
|
|
|
|
t.Errorf("failed to unmarshal rawResult '%s': %v", C.GoString(rawResult), err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
if result.Error.Message != "" {
|
|
|
|
t.Errorf("failed to send transaction: %v", result.Error)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
hash := gethcommon.BytesToHash(result.Result)
|
|
|
|
if reflect.DeepEqual(hash, gethcommon.Hash{}) {
|
|
|
|
t.Errorf("response hash empty: %s", hash.Hex())
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
func testSendTransactionInvalidPassword(t *testing.T) bool {
|
|
|
|
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
// log into account from which transactions will be sent
|
2019-07-26 14:45:10 +00:00
|
|
|
if err := statusBackend.SelectAccount(buildLoginParams(
|
2019-01-18 09:01:14 +00:00
|
|
|
TestConfig.Account1.WalletAddress,
|
|
|
|
TestConfig.Account1.ChatAddress,
|
2018-08-16 11:37:53 +00:00
|
|
|
TestConfig.Account1.Password,
|
2019-07-26 14:45:10 +00:00
|
|
|
)); err != nil {
|
2019-01-18 09:01:14 +00:00
|
|
|
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account1.WalletAddress, err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
args, err := json.Marshal(transactions.SendTxArgs{
|
2019-01-18 09:01:14 +00:00
|
|
|
From: account.FromAddress(TestConfig.Account1.WalletAddress),
|
|
|
|
To: account.ToAddress(TestConfig.Account2.WalletAddress),
|
2018-08-16 11:37:53 +00:00
|
|
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
2018-03-29 09:20:55 +00:00
|
|
|
})
|
2018-08-16 11:37:53 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to marshal errors: %v", err)
|
|
|
|
return false
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
rawResult := SendTransaction(C.CString(string(args)), C.CString("invalid password"))
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
var result jsonrpcAnyResponse
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResult)), &result); err != nil {
|
|
|
|
t.Errorf("failed to unmarshal rawResult '%s': %v", C.GoString(rawResult), err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
if result.Error.Message != keystore.ErrDecrypt.Error() {
|
|
|
|
t.Errorf("invalid result: %q", result)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
func testFailedTransaction(t *testing.T) bool {
|
|
|
|
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
|
2018-03-29 09:20:55 +00:00
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
// log into wrong account in order to get selectedAccount error
|
2019-07-26 14:45:10 +00:00
|
|
|
if err := statusBackend.SelectAccount(buildLoginParams(TestConfig.Account2.WalletAddress, TestConfig.Account2.ChatAddress, TestConfig.Account2.Password)); err != nil {
|
|
|
|
t.Errorf("cannot select account: %v. Error %q", TestConfig.Account2.WalletAddress, err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
args, err := json.Marshal(transactions.SendTxArgs{
|
2019-01-18 09:01:14 +00:00
|
|
|
From: account.FromAddress(TestConfig.Account1.WalletAddress),
|
|
|
|
To: account.ToAddress(TestConfig.Account2.WalletAddress),
|
2018-03-29 09:20:55 +00:00
|
|
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
|
|
|
})
|
2018-08-16 11:37:53 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to marshal errors: %v", err)
|
2018-05-29 11:24:23 +00:00
|
|
|
return false
|
|
|
|
}
|
2018-08-16 11:37:53 +00:00
|
|
|
rawResult := SendTransaction(C.CString(string(args)), C.CString(TestConfig.Account1.Password))
|
2018-05-29 11:24:23 +00:00
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
var result jsonrpcAnyResponse
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(rawResult)), &result); err != nil {
|
|
|
|
t.Errorf("failed to unmarshal rawResult '%s': %v", C.GoString(rawResult), err)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
if result.Error.Message != transactions.ErrInvalidTxSender.Error() {
|
|
|
|
t.Errorf("expected error to be ErrInvalidTxSender, got %s", result.Error.Message)
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-08-16 11:37:53 +00:00
|
|
|
if result.Result != nil {
|
|
|
|
t.Errorf("expected result to be nil")
|
2018-03-29 09:20:55 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-05-29 11:24:23 +00:00
|
|
|
return true
|
2018-03-29 09:20:55 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func startTestNode(t *testing.T) <-chan struct{} {
|
|
|
|
testDir := filepath.Join(TestDataDir, TestNetworkNames[GetNetworkID()])
|
|
|
|
|
|
|
|
syncRequired := false
|
|
|
|
if _, err := os.Stat(testDir); os.IsNotExist(err) {
|
|
|
|
syncRequired = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// inject test accounts
|
|
|
|
testKeyDir := filepath.Join(testDir, "keystore")
|
2018-04-04 17:39:38 +00:00
|
|
|
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
2018-04-04 17:39:38 +00:00
|
|
|
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
2018-03-29 09:20:55 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
waitForNodeStart := make(chan struct{}, 1)
|
|
|
|
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
|
|
t.Log(jsonEvent)
|
|
|
|
var envelope signal.Envelope
|
|
|
|
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
|
|
|
|
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if envelope.Type == signal.EventNodeCrashed {
|
|
|
|
signal.TriggerDefaultNodeNotificationHandler(jsonEvent)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-03 07:35:58 +00:00
|
|
|
if envelope.Type == signal.EventSignRequestAdded {
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|
|
|
|
if envelope.Type == signal.EventNodeStarted {
|
|
|
|
t.Log("Node started, but we wait till it be ready")
|
|
|
|
}
|
|
|
|
if envelope.Type == signal.EventNodeReady {
|
|
|
|
// sync
|
|
|
|
if syncRequired {
|
|
|
|
t.Logf("Sync is required")
|
2018-06-19 07:49:24 +00:00
|
|
|
EnsureNodeSync(statusBackend.StatusNode().EnsureSync)
|
2018-03-29 09:20:55 +00:00
|
|
|
} else {
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
}
|
|
|
|
|
|
|
|
// now we can proceed with tests
|
|
|
|
waitForNodeStart <- struct{}{}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
response := StartNode(C.CString(nodeConfigJSON))
|
|
|
|
responseErr := APIResponse{}
|
|
|
|
|
|
|
|
if err := json.Unmarshal([]byte(C.GoString(response)), &responseErr); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if responseErr.Error != "" {
|
|
|
|
panic("cannot start node: " + responseErr.Error)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return waitForNodeStart
|
|
|
|
}
|
|
|
|
|
|
|
|
//nolint: deadcode
|
2019-01-17 12:56:22 +00:00
|
|
|
func testValidateNodeConfig(t *testing.T, config string, fn func(*testing.T, APIDetailedResponse)) {
|
2018-03-29 09:20:55 +00:00
|
|
|
result := ValidateNodeConfig(C.CString(config))
|
|
|
|
|
|
|
|
var resp APIDetailedResponse
|
|
|
|
|
|
|
|
err := json.Unmarshal([]byte(C.GoString(result)), &resp)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-01-17 12:56:22 +00:00
|
|
|
fn(t, resp)
|
2018-03-29 09:20:55 +00:00
|
|
|
}
|