diff --git a/cmd/status/library.go b/cmd/status/library.go index 48a4c698f..030df9836 100644 --- a/cmd/status/library.go +++ b/cmd/status/library.go @@ -117,28 +117,6 @@ func Logout() *C.char { return C.CString(string(outBytes)) } -//export UnlockAccount -func UnlockAccount(address, password *C.char, seconds int) *C.char { - - // This is equivalent to unlocking an account from the command line, - // just modified to unlock the account for the currently running geth node - // based on the provided arguments - err := geth.UnlockAccount(C.GoString(address), C.GoString(password), seconds) - - errString := "" - if err != nil { - fmt.Fprintln(os.Stderr, err) - errString = err.Error() - } - - out := geth.JSONError{ - Error: errString, - } - outBytes, _ := json.Marshal(&out) - - return C.CString(string(outBytes)) -} - //export CompleteTransaction func CompleteTransaction(id, password *C.char) *C.char { txHash, err := geth.CompleteTransaction(C.GoString(id), C.GoString(password)) diff --git a/cmd/status/utils.go b/cmd/status/utils.go index cec78715c..7921dae08 100644 --- a/cmd/status/utils.go +++ b/cmd/status/utils.go @@ -3,6 +3,7 @@ package main import "C" import ( "encoding/json" + "io/ioutil" "math/big" "os" "path/filepath" @@ -10,7 +11,9 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/les/status" "github.com/ethereum/go-ethereum/rpc" "github.com/status-im/status-go/geth" @@ -23,6 +26,7 @@ const ( testAddressPassword = "asdf" newAccountPassword = "badpassword" testAddress1 = "0xf82da7547534045b4e00442bc89e16186cf8c272" + testStatusJsFile = "../../jail/testdata/status.js" ) func testExportedAPI(t *testing.T, done chan struct{}) { @@ -32,14 +36,46 @@ func testExportedAPI(t *testing.T, done chan struct{}) { name string fn func(t *testing.T) bool }{ + { + "create main and child accounts", + testCreateChildAccount, + }, + { + "recover account", + testRecoverAccount, + }, + { + "account select/login", + testAccountSelect, + }, + { + "account logout", + testAccountLogout, + }, + { + "complete single queued transaction", + testCompleteTransaction, + }, { "test complete multiple queued transactions", testCompleteMultipleQueuedTransactions, }, + { + "discard single queued transaction", + testDiscardTransaction, + }, { "test discard multiple queued transactions", testDiscardMultipleQueuedTransactions, }, + { + "test jail initialization", + testJailInit, + }, + { + "test jailed calls", + testJailFunctionCall, + }, } for _, test := range tests { @@ -51,6 +87,468 @@ func testExportedAPI(t *testing.T, done chan struct{}) { done <- struct{}{} } +func testCreateChildAccount(t *testing.T) bool { + geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests) + + accountManager, err := geth.GetNodeManager().AccountManager() + if err != nil { + t.Error(err) + return false + } + + // create an account + createAccountResponse := geth.AccountInfo{} + rawResponse := CreateAccount(C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createAccountResponse); err != nil { + t.Errorf("cannot decode CreateAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createAccountResponse.Error != "" { + 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) + + account, err := utils.MakeAddress(accountManager, address) + if err != nil { + t.Errorf("can not get account from address: %v", err) + return false + } + + // obtain decrypted key, and make sure that extended key (which will be used as root for sub-accounts) is present + account, key, err := accountManager.AccountDecryptedKey(account, newAccountPassword) + if err != nil { + t.Errorf("can not obtain decrypted account key: %v", err) + return false + } + + if key.ExtendedKey == nil { + t.Error("CKD#2 has not been generated for new account") + return false + } + + // try creating sub-account, w/o selecting main account i.e. w/o login to main account + createSubAccountResponse := geth.AccountInfo{} + rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil { + t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createSubAccountResponse.Error != geth.ErrNoAccountSelected.Error() { + t.Errorf("expected error is not returned (tried to create sub-account w/o login): %v", createSubAccountResponse.Error) + return false + } + + err = geth.SelectAccount(address, newAccountPassword) + if err != nil { + t.Errorf("Test failed: could not select account: %v", err) + return false + } + + // try to create sub-account with wrong password + createSubAccountResponse = geth.AccountInfo{} + rawResponse = CreateChildAccount(C.CString(""), C.CString("wrong password")) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse); err != nil { + t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createSubAccountResponse.Error != "cannot retreive a valid key for a given account: could not decrypt key with given passphrase" { + t.Errorf("expected error is not returned (tried to create sub-account with wrong password): %v", createSubAccountResponse.Error) + return false + } + + // create sub-account (from implicit parent) + createSubAccountResponse1 := geth.AccountInfo{} + rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse1); err != nil { + t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createSubAccountResponse1.Error != "" { + t.Errorf("cannot create sub-account: %v", createSubAccountResponse1.Error) + return false + } + + // make sure that sub-account index automatically progresses + createSubAccountResponse2 := geth.AccountInfo{} + rawResponse = CreateChildAccount(C.CString(""), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse2); err != nil { + t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createSubAccountResponse2.Error != "" { + t.Errorf("cannot create sub-account: %v", createSubAccountResponse2.Error) + } + + if createSubAccountResponse1.Address == createSubAccountResponse2.Address || createSubAccountResponse1.PubKey == createSubAccountResponse2.PubKey { + t.Error("sub-account index auto-increament failed") + return false + } + + // create sub-account (from explicit parent) + createSubAccountResponse3 := geth.AccountInfo{} + rawResponse = CreateChildAccount(C.CString(createSubAccountResponse2.Address), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &createSubAccountResponse3); err != nil { + t.Errorf("cannot decode CreateChildAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if createSubAccountResponse3.Error != "" { + t.Errorf("cannot create sub-account: %v", createSubAccountResponse3.Error) + } + + subAccount1, subAccount2, subAccount3 := createSubAccountResponse1.Address, createSubAccountResponse2.Address, createSubAccountResponse3.Address + subPubKey1, subPubKey2, subPubKey3 := createSubAccountResponse1.PubKey, createSubAccountResponse2.PubKey, createSubAccountResponse3.PubKey + + if subAccount1 == subAccount3 || subPubKey1 == subPubKey3 || subAccount2 == subAccount3 || subPubKey2 == subPubKey3 { + t.Error("sub-account index auto-increament failed") + return false + } + + return true +} + +func testRecoverAccount(t *testing.T) bool { + accountManager, _ := geth.GetNodeManager().AccountManager() + + // create an account + address, pubKey, mnemonic, err := geth.CreateAccount(newAccountPassword) + 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) + + // try recovering using password + mnemonic + recoverAccountResponse := geth.AccountInfo{} + rawResponse := RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if recoverAccountResponse.Error != "" { + 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") + } + + // now test recovering, but make sure that account/key file is removed i.e. simulate recovering on a new device + account, err := utils.MakeAddress(accountManager, address) + if err != nil { + t.Errorf("can not get account from address: %v", err) + } + + account, key, err := accountManager.AccountDecryptedKey(account, newAccountPassword) + if err != nil { + t.Errorf("can not obtain decrypted account key: %v", err) + return false + } + extChild2String := key.ExtendedKey.String() + + if err := accountManager.DeleteAccount(account, newAccountPassword); err != nil { + t.Errorf("cannot remove account: %v", err) + } + + recoverAccountResponse = geth.AccountInfo{} + rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%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 + } + 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)") + } + + // make sure that extended key exists and is imported ok too + account, key, err = accountManager.AccountDecryptedKey(account, newAccountPassword) + 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 = geth.AccountInfo{} + rawResponse = RecoverAccount(C.CString(newAccountPassword), C.CString(mnemonic)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &recoverAccountResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%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 + } + 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)") + } + + // time to login with recovered data + whisperService, err := geth.GetNodeManager().WhisperService() + if err != nil { + t.Errorf("whisper service not running: %v", err) + } + + // make sure that identity is not (yet injected) + if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) { + t.Error("identity already present in whisper") + } + err = geth.SelectAccount(addressCheck, newAccountPassword) + if err != nil { + t.Errorf("Test failed: could not select account: %v", err) + return false + } + if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKeyCheck))) { + t.Errorf("identity not injected into whisper: %v", err) + } + + return true +} + +func testAccountSelect(t *testing.T) bool { + // test to see if the account was injected in whisper + whisperService, err := geth.GetNodeManager().WhisperService() + if err != nil { + t.Errorf("whisper service not running: %v", err) + } + + // create an account + address1, pubKey1, _, err := geth.CreateAccount(newAccountPassword) + if err != nil { + t.Errorf("could not create account: %v", err) + return false + } + t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1) + + address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword) + if err != nil { + t.Error("Test failed: could not create account") + return false + } + t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2) + + // make sure that identity is not (yet injected) + if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) { + t.Error("identity already present in whisper") + } + + // try selecting with wrong password + loginResponse := geth.JSONError{} + rawResponse := Login(C.CString(address1), C.CString("wrongPassword")) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%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 = geth.JSONError{} + rawResponse = Login(C.CString(address1), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if loginResponse.Error != "" { + t.Errorf("Test failed: could not select account: %v", err) + return false + } + if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) { + 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.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) { + t.Error("identity already present in whisper") + } + + loginResponse = geth.JSONError{} + rawResponse = Login(C.CString(address2), C.CString(newAccountPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &loginResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err) + return false + } + + if loginResponse.Error != "" { + t.Errorf("Test failed: could not select account: %v", loginResponse.Error) + return false + } + if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey2))) { + t.Errorf("identity not injected into whisper: %v", err) + } + if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) { + t.Error("identity should be removed, but it is still present in whisper") + } + + return true +} + +func testAccountLogout(t *testing.T) bool { + whisperService, err := geth.GetNodeManager().WhisperService() + if err != nil { + t.Errorf("whisper service not running: %v", err) + return false + } + + // create an account + address, pubKey, _, err := geth.CreateAccount(newAccountPassword) + 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.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) { + t.Error("identity already present in whisper") + return false + } + + // select/login + err = geth.SelectAccount(address, newAccountPassword) + if err != nil { + t.Errorf("Test failed: could not select account: %v", err) + return false + } + if !whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) { + t.Error("identity not injected into whisper") + return false + } + + logoutResponse := geth.JSONError{} + rawResponse := Logout() + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &logoutResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%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 + if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey))) { + t.Error("identity not cleared from whisper") + return false + } + + return true +} + +func testCompleteTransaction(t *testing.T) bool { + // obtain reference to status backend + lightEthereum, err := geth.GetNodeManager().LightEthereumService() + if err != nil { + t.Errorf("Test failed: LES service is not running: %v", err) + return false + } + backend := lightEthereum.StatusBackend + + // reset queue + backend.TransactionQueue().Reset() + + // make sure you panic if transaction complete doesn't return + queuedTxCompleted := make(chan struct{}, 1) + abortPanic := make(chan struct{}, 1) + geth.PanicAfter(10*time.Second, abortPanic, "testCompleteTransaction") + + // replace transaction notification handler + var txHash = "" + geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) { + var envelope geth.GethEvent + if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil { + t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent) + return + } + if envelope.Type == geth.EventTransactionQueued { + event := envelope.Event.(map[string]interface{}) + t.Logf("transaction queued (will be completed in 5 secs): {id: %s}\n", event["id"].(string)) + time.Sleep(5 * time.Second) + + completeTxResponse := geth.CompleteTransactionResult{} + rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(testAddressPassword)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err) + } + + if completeTxResponse.Error != "" { + t.Errorf("cannot complete queued transation[%v]: %v", event["id"], completeTxResponse.Error) + } + + txHash = completeTxResponse.Hash + + t.Logf("transaction complete: https://testnet.etherscan.io/tx/%s", txHash) + abortPanic <- struct{}{} // so that timeout is aborted + queuedTxCompleted <- struct{}{} + } + }) + + // this call blocks, up until Complete Transaction is called + txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{ + From: geth.FromAddress(testAddress), + To: geth.ToAddress(testAddress1), + Value: rpc.NewHexNumber(big.NewInt(1000000000000)), + }) + if err != nil { + t.Errorf("Test failed: cannot send transaction: %v", err) + } + + <-queuedTxCompleted // make sure that complete transaction handler completes its magic, before we proceed + + if txHash != txHashCheck.Hex() { + t.Errorf("Transaction hash returned from SendTransaction is invalid: expected %s, got %s", txHashCheck.Hex(), txHash) + return false + } + + if reflect.DeepEqual(txHashCheck, common.Hash{}) { + t.Error("Test failed: transaction was never queued or completed") + return false + } + + if backend.TransactionQueue().Count() != 0 { + t.Error("tx queue must be empty at this point") + return false + } + + return true +} + func testCompleteMultipleQueuedTransactions(t *testing.T) bool { // obtain reference to status backend lightEthereum, err := geth.GetNodeManager().LightEthereumService() @@ -180,6 +678,120 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { return true } +func testDiscardTransaction(t *testing.T) bool { + // obtain reference to status backend + lightEthereum, err := geth.GetNodeManager().LightEthereumService() + if err != nil { + t.Errorf("Test failed: LES service is not running: %v", err) + return false + } + backend := lightEthereum.StatusBackend + + // reset queue + backend.TransactionQueue().Reset() + + // make sure you panic if transaction complete doesn't return + completeQueuedTransaction := make(chan struct{}, 1) + geth.PanicAfter(20*time.Second, completeQueuedTransaction, "TestDiscardQueuedTransactions") + + // replace transaction notification handler + var txId string + txFailedEventCalled := false + geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) { + var envelope geth.GethEvent + if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil { + t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent) + return + } + if envelope.Type == geth.EventTransactionQueued { + event := envelope.Event.(map[string]interface{}) + txId = event["id"].(string) + t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txId) + + if !backend.TransactionQueue().Has(status.QueuedTxId(txId)) { + t.Errorf("txqueue should still have test tx: %s", txId) + return + } + + // discard + discardResponse := geth.DiscardTransactionResult{} + rawResponse := DiscardTransaction(C.CString(txId)) + + if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &discardResponse); err != nil { + t.Errorf("cannot decode RecoverAccount reponse (%s): %v", C.GoString(rawResponse), err) + } + + if discardResponse.Error != "" { + t.Errorf("cannot discard tx: %v", discardResponse.Error) + return + } + + // try completing discarded transaction + _, err = geth.CompleteTransaction(txId, testAddressPassword) + if err.Error() != "transaction hash not found" { + t.Error("expects tx not found, but call to CompleteTransaction succeeded") + return + } + + time.Sleep(1 * time.Second) // make sure that tx complete signal propagates + if backend.TransactionQueue().Has(status.QueuedTxId(txId)) { + t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txId) + return + } + + completeQueuedTransaction <- struct{}{} // so that timeout is aborted + } + + if envelope.Type == geth.EventTransactionFailed { + event := envelope.Event.(map[string]interface{}) + t.Logf("transaction return event received: {id: %s}\n", event["id"].(string)) + + receivedErrMessage := event["error_message"].(string) + expectedErrMessage := status.ErrQueuedTxDiscarded.Error() + if receivedErrMessage != expectedErrMessage { + t.Errorf("unexpected error message received: got %v", receivedErrMessage) + return + } + + receivedErrCode := event["error_code"].(string) + if receivedErrCode != geth.SendTransactionDiscardedErrorCode { + t.Errorf("unexpected error code received: got %v", receivedErrCode) + return + } + + txFailedEventCalled = true + } + }) + + // this call blocks, and should return when DiscardQueuedTransaction() is called + txHashCheck, err := backend.SendTransaction(nil, status.SendTxArgs{ + From: geth.FromAddress(testAddress), + To: geth.ToAddress(testAddress1), + Value: rpc.NewHexNumber(big.NewInt(1000000000000)), + }) + if err != status.ErrQueuedTxDiscarded { + t.Errorf("expected error not thrown: %v", err) + return false + } + + if !reflect.DeepEqual(txHashCheck, common.Hash{}) { + t.Error("transaction returned hash, while it shouldn't") + return false + } + + if backend.TransactionQueue().Count() != 0 { + t.Error("tx queue must be empty at this point") + return false + } + + if !txFailedEventCalled { + t.Error("expected tx failure signal is not received") + return false + } + + return true +} + func testDiscardMultipleQueuedTransactions(t *testing.T) bool { // obtain reference to status backend lightEthereum, err := geth.GetNodeManager().LightEthereumService() @@ -343,6 +955,67 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { return true } +func testJailInit(t *testing.T) bool { + initCode := ` + var _status_catalog = { + foo: 'bar' + }; + ` + InitJail(C.CString(initCode)) + + extraCode := ` + var extraFunc = function (x) { + return x * x; + }; + ` + rawResponse := Parse(C.CString("CHAT_ID_INIT_TEST"), C.CString(extraCode)) + parsedResponse := C.GoString(rawResponse) + + expectedResponse := `{"result": {"foo":"bar"}}` + + if !reflect.DeepEqual(expectedResponse, parsedResponse) { + t.Error("expected output not returned from jail.Parse()") + return false + } + + t.Logf("jail inited and parsed: %s", parsedResponse) + + return true +} + +func testJailFunctionCall(t *testing.T) bool { + InitJail(C.CString("")) + + // load Status JS and add test command to it + statusJS := geth.LoadFromFile(testStatusJsFile) + `; + _status_catalog.commands["testCommand"] = function (params) { + return params.val * params.val; + };` + Parse(C.CString("CHAT_ID_CALL_TEST"), C.CString(statusJS)) + + // call with wrong chat id + rawResponse := Call(C.CString("CHAT_IDNON_EXISTENT"), C.CString(""), C.CString("")) + parsedResponse := C.GoString(rawResponse) + expectedError := `{"error":"Cell[CHAT_IDNON_EXISTENT] doesn't exist."}` + if parsedResponse != expectedError { + t.Errorf("expected error is not returned: expected %s, got %s", expectedError, parsedResponse) + return false + } + + // call extraFunc() + rawResponse = Call(C.CString("CHAT_ID_CALL_TEST"), C.CString(`["commands", "testCommand"]`), C.CString(`{"val": 12}`)) + parsedResponse = C.GoString(rawResponse) + expectedResponse := `{"result": 144}` + if parsedResponse != expectedResponse { + t.Errorf("expected response is not returned: expected %s, got %s", expectedResponse, parsedResponse) + return false + } + + t.Logf("jailed method called: %s", parsedResponse) + + return true +} + func startTestNode(t *testing.T) <-chan struct{} { syncRequired := false if _, err := os.Stat(filepath.Join(testDataDir, "testnet")); os.IsNotExist(err) { @@ -360,6 +1033,21 @@ func startTestNode(t *testing.T) <-chan struct{} { if envelope.Type == geth.EventTransactionQueued { } if envelope.Type == geth.EventNodeStarted { + // manually add static nodes (LES auto-discovery is not stable yet) + configFile, err := ioutil.ReadFile(filepath.Join("../../data", "static-nodes.json")) + if err != nil { + return + } + var enodes []string + if err = json.Unmarshal(configFile, &enodes); err != nil { + return + } + + for _, enode := range enodes { + AddPeer(C.CString(enode)) + } + + // sync if syncRequired { t.Logf("Sync is required, it will take %d seconds", testNodeSyncSeconds) time.Sleep(testNodeSyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done @@ -372,13 +1060,15 @@ func startTestNode(t *testing.T) <-chan struct{} { } }) - response := StartNode(C.CString(testDataDir)) - err := geth.JSONError{} + go func() { + response := StartNode(C.CString(testDataDir)) + err := geth.JSONError{} - json.Unmarshal([]byte(C.GoString(response)), &err) - if err.Error != "" { - t.Error("cannot start node") - } + json.Unmarshal([]byte(C.GoString(response)), &err) + if err.Error != "" { + t.Error("cannot start node") + } + }() return waitForNodeStart } diff --git a/geth/accounts_test.go b/geth/accounts_test.go index 71c32638e..4f269d60c 100644 --- a/geth/accounts_test.go +++ b/geth/accounts_test.go @@ -2,15 +2,12 @@ package geth_test import ( "errors" - "fmt" "reflect" "testing" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" "github.com/status-im/status-go/geth" ) @@ -145,7 +142,7 @@ func TestCreateChildAccount(t *testing.T) { t.Errorf("could not create account: %v", err) return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) + t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) account, err := utils.MakeAddress(accountManager, address) if err != nil { @@ -228,7 +225,7 @@ func TestRecoverAccount(t *testing.T) { t.Errorf("could not create account: %v", err) return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) + t.Logf("Account created: {address: %s, key: %s, mnemonic:%s}", address, pubKey, mnemonic) // try recovering using password + mnemonic addressCheck, pubKeyCheck, err := geth.RecoverAccount(newAccountPassword, mnemonic) @@ -326,15 +323,14 @@ func TestAccountSelect(t *testing.T) { t.Errorf("could not create account: %v", err) return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address1, pubKey1) + t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1) address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword) if err != nil { - fmt.Println(err.Error()) t.Error("Test failed: could not create account") return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address2, pubKey2) + t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2) // make sure that identity is not (yet injected) if whisperService.HasIdentity(crypto.ToECDSAPub(common.FromHex(pubKey1))) { diff --git a/geth/node_test.go b/geth/node_test.go index 62a59cae9..c25f71cb3 100644 --- a/geth/node_test.go +++ b/geth/node_test.go @@ -45,7 +45,6 @@ func TestMain(m *testing.M) { err := geth.PrepareTestNode() if err != nil { panic(err) - return } <-signalRecieved // block and wait for either panic or successful signal diff --git a/geth/whisper_test.go b/geth/whisper_test.go index 5e17e722b..358735867 100644 --- a/geth/whisper_test.go +++ b/geth/whisper_test.go @@ -7,8 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/whisper" "github.com/status-im/status-go/geth" ) @@ -43,7 +41,7 @@ func TestWhisperMessaging(t *testing.T) { t.Error("Test failed: could not create account") return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address1, pubKey1) + t.Logf("Account created: {address: %s, key: %s}", address1, pubKey1) address2, pubKey2, _, err := geth.CreateAccount(newAccountPassword) if err != nil { @@ -51,7 +49,7 @@ func TestWhisperMessaging(t *testing.T) { t.Error("Test failed: could not create account") return } - glog.V(logger.Info).Infof("Account created: {address: %s, key: %s}", address2, pubKey2) + t.Logf("Account created: {address: %s, key: %s}", address2, pubKey2) // start watchers var receivedMessages = map[string]bool{ @@ -65,7 +63,7 @@ func TestWhisperMessaging(t *testing.T) { //From: crypto.ToECDSAPub(common.FromHex(pubKey1)), //To: crypto.ToECDSAPub(common.FromHex(pubKey2)), Fn: func(msg *whisper.Message) { - //glog.V(logger.Info).Infof("Whisper message received: %s", msg.Payload) + //t.Logf("Whisper message received: %s", msg.Payload) receivedMessages[string(msg.Payload)] = true }, })