Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed eth_sendTransaction routing to the local node #351

Merged
merged 27 commits into from
Sep 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
864938d
Fixed eth_sendTransaction routing to the local node
tiabc Sep 20, 2017
40c1ff9
Add RegisterHandler to RPC package.
divan Sep 20, 2017
fc0ffc5
Improve RPC local handlers.
divan Sep 20, 2017
ec42dca
Use RegisterHandler for eth_accounts.
divan Sep 20, 2017
eb0a20b
Improve RPC local handlers.
divan Sep 20, 2017
ac648b2
Implement EthAccountsHandler.
divan Sep 20, 2017
e0866e6
Update interfaces and mocks.
divan Sep 20, 2017
f8d00e3
create eth_sendTransaction rpc handler
adambabik Sep 21, 2017
be95351
Rename RPC Handler method for Accounts()
divan Sep 21, 2017
0d7a082
Update tests and mocks.
divan Sep 21, 2017
72983aa
Merge branch 'bugfix/eth-send-transaction-routing-#350' of github.com…
divan Sep 21, 2017
c2b3aef
Remove duplicated queue call.
divan Sep 21, 2017
f6ff00d
remove separate handler for eth_sendTransaction from jail
adambabik Sep 21, 2017
97511a8
fix setting result in rpc.Client.callMethod
adambabik Sep 21, 2017
ae467c9
extract setting result to setResultFromRPCResponse
adambabik Sep 21, 2017
6394cb1
clean up
adambabik Sep 21, 2017
2c22742
Fix routing tests
divan Sep 21, 2017
d69e65a
add context param to rpc.Handler
adambabik Sep 22, 2017
a4dc0e9
Add requested changes
divan Sep 22, 2017
fca15f4
Expand arguments for callMethod
divan Sep 22, 2017
1dd554f
fix params in SendTransactionRPCHandler; get gasPrice if missing in S…
adambabik Sep 23, 2017
7524ace
Merge branch 'develop' into bugfix/eth-send-transaction-routing-#350
adambabik Sep 25, 2017
7660de6
add TestCallRPCSendTransactionUpstream test
adambabik Sep 25, 2017
f9066f9
update binddata and fix some TestJailWhisper test cases
adambabik Sep 25, 2017
830f06d
Revert "update binddata and fix some TestJailWhisper test cases"
adambabik Sep 25, 2017
1afcdc2
fix generating token in TestJailWhisper
adambabik Sep 25, 2017
d45f4e9
update bindata to the proper web3.js
adambabik Sep 25, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 3 additions & 14 deletions geth/api/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"sync"

gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/les"
"github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/jail"
"github.com/status-im/status-go/geth/log"
Expand Down Expand Up @@ -224,19 +223,9 @@ func (m *StatusBackend) DiscardTransactions(ids []common.QueuedTxID) map[common.

// registerHandlers attaches Status callback handlers to running node
func (m *StatusBackend) registerHandlers() error {
runningNode, err := m.nodeManager.Node()
if err != nil {
return err
}

var lightEthereum *les.LightEthereum
if err := runningNode.Service(&lightEthereum); err != nil {
log.Error("Cannot get light ethereum service", "error", err)
return err
}

lightEthereum.StatusBackend.SetAccountsFilterHandler(m.accountManager.AccountsListRequestHandler())
log.Info("Registered handler", "fn", "AccountsFilterHandler")
rpcClient := m.NodeManager().RPCClient()
rpcClient.RegisterHandler("eth_accounts", m.accountManager.AccountsRPCHandler())
rpcClient.RegisterHandler("eth_sendTransaction", m.txQueueManager.SendTransactionRPCHandler)

m.txQueueManager.SetTransactionQueueHandler(m.txQueueManager.TransactionQueueHandler())
log.Info("Registered handler", "fn", "TransactionQueueHandler")
Expand Down
23 changes: 10 additions & 13 deletions geth/api/backend_accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"

"github.com/ethereum/go-ethereum/les"
"github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params"
Expand All @@ -22,14 +21,8 @@ func (s *BackendTestSuite) TestAccountsList() {
require.NoError(err)
require.NotNil(runningNode)

var lesService *les.LightEthereum
require.NoError(runningNode.Service(&lesService))
require.NotNil(lesService)

accounts := lesService.StatusBackend.AccountManager().Accounts()
for _, acc := range accounts {
fmt.Println(acc.Hex())
}
accounts, err := s.backend.AccountManager().Accounts()
require.NoError(err)

// make sure that we start with empty accounts list (nobody has logged in yet)
require.Zero(len(accounts), "accounts returned, while there should be none (we haven't logged in yet)")
Expand All @@ -39,15 +32,17 @@ func (s *BackendTestSuite) TestAccountsList() {
require.NoError(err)

// ensure that there is still no accounts returned
accounts = lesService.StatusBackend.AccountManager().Accounts()
accounts, err = s.backend.AccountManager().Accounts()
require.NoError(err)
require.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.AccountManager().SelectAccount(address, TestConfig.Account1.Password)
require.NoError(err, "account selection failed")

// at this point main account should show up
accounts = lesService.StatusBackend.AccountManager().Accounts()
accounts, err = s.backend.AccountManager().Accounts()
require.NoError(err)
require.Equal(1, len(accounts), "exactly single account is expected (main account)")
require.Equal(string(accounts[0].Hex()), "0x"+address,
fmt.Sprintf("main account is not retured as the first key: got %s, expected %s", accounts[0].Hex(), "0x"+address))
Expand All @@ -57,7 +52,8 @@ func (s *BackendTestSuite) TestAccountsList() {
require.NoError(err, "cannot create sub-account")

// now we expect to see both main account and sub-account 1
accounts = lesService.StatusBackend.AccountManager().Accounts()
accounts, err = s.backend.AccountManager().Accounts()
require.NoError(err)
require.Equal(2, len(accounts), "exactly 2 accounts are expected (main + sub-account 1)")
require.Equal(string(accounts[0].Hex()), "0x"+address, "main account is not retured as the first key")
require.Equal(string(accounts[1].Hex()), "0x"+subAccount1, "subAcount1 not returned")
Expand All @@ -68,7 +64,8 @@ func (s *BackendTestSuite) TestAccountsList() {
require.False(subAccount1 == subAccount2 || subPubKey1 == subPubKey2, "sub-account index auto-increament failed")

// finally, all 3 accounts should show up (main account, sub-accounts 1 and 2)
accounts = lesService.StatusBackend.AccountManager().Accounts()
accounts, err = s.backend.AccountManager().Accounts()
require.NoError(err)
require.Equal(3, len(accounts), "unexpected number of accounts")
require.Equal(string(accounts[0].Hex()), "0x"+address, "main account is not retured as the first key")

Expand Down
11 changes: 6 additions & 5 deletions geth/api/backend_jail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,6 @@ func (s *BackendTestSuite) TestJailWhisper() {
throw 'message not sent: ' + JSON.stringify(message);
}


var filterName = '` + whisperMessage1 + `';
var filterId = filter.filterId;
if (!filterId) {
Expand Down Expand Up @@ -576,11 +575,13 @@ func (s *BackendTestSuite) TestJailWhisper() {

jailInstance.Parse(testCaseKey, `
var shh = web3.shh;
// topic must be 4-byte long
var makeTopic = function () {
var min = 1;
var max = Math.pow(16, 8);
var randInt = Math.floor(Math.random() * (max - min + 1)) + min;
return web3.toHex(randInt);
var topic = '0x';
for (var i = 0; i < 8; i++) {
topic += Math.floor(Math.random() * 16).toString(16);
}
return topic;
};
`)

Expand Down
115 changes: 115 additions & 0 deletions geth/api/backend_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package api_test

import (
"encoding/json"
"math/rand"
"testing"
"time"

gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/les"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
"github.com/status-im/status-go/geth/api"
Expand Down Expand Up @@ -256,6 +258,119 @@ func (s *BackendTestSuite) TestCallRPC() {
}
}

func (s *BackendTestSuite) TestCallRPCSendTransaction() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this test pass at least once?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. Just copied this test from other place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can get it passed in Ropsten easily but it does want to in RinkebyNetworkID :/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change it to Ropsten.

nodeConfig, err := MakeTestNodeConfig(params.RopstenNetworkID)
s.NoError(err)

nodeStarted, err := s.backend.StartNode(nodeConfig)
s.NoError(err)
defer s.backend.StopNode()

<-nodeStarted

// Allow to sync the blockchain.
time.Sleep(TestConfig.Node.SyncSeconds * time.Second)

err = s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
s.NoError(err)

transactionCompleted := make(chan struct{})

var txHash gethcommon.Hash
node.SetDefaultNodeNotificationHandler(func(rawSignal string) {
var signal node.SignalEnvelope
err := json.Unmarshal([]byte(rawSignal), &signal)
s.NoError(err)

if signal.Type == node.EventTransactionQueued {
event := signal.Event.(map[string]interface{})
txID := event["id"].(string)
txHash, err = s.backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
s.NoError(err, "cannot complete queued transaction %s", txID)

close(transactionCompleted)
}
})

result := s.backend.CallRPC(`{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendTransaction",
"params": [{
"from": "` + TestConfig.Account1.Address + `",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x9184e72a"
}]
}`)
s.NotContains(result, "error")

select {
case <-transactionCompleted:
case <-time.After(time.Minute):
s.FailNow("sending transaction timed out")
}

s.Equal(`{"jsonrpc":"2.0","id":1,"result":"`+txHash.String()+`"}`, result)
}

func (s *BackendTestSuite) TestCallRPCSendTransactionUpstream() {
nodeConfig, err := MakeTestNodeConfig(params.RopstenNetworkID)
s.NoError(err)

nodeConfig.UpstreamConfig.Enabled = true
nodeConfig.UpstreamConfig.URL = "https://ropsten.infura.io/nKmXgiFgc2KqtoQ8BCGJ"

nodeStarted, err := s.backend.StartNode(nodeConfig)
s.NoError(err)
defer s.backend.StopNode()

<-nodeStarted

// Allow to sync the blockchain.
time.Sleep(TestConfig.Node.SyncSeconds * time.Second)

err = s.backend.AccountManager().SelectAccount(TestConfig.Account2.Address, TestConfig.Account2.Password)
s.NoError(err)

transactionCompleted := make(chan struct{})

var txHash gethcommon.Hash
node.SetDefaultNodeNotificationHandler(func(rawSignal string) {
var signal node.SignalEnvelope
err := json.Unmarshal([]byte(rawSignal), &signal)
s.NoError(err)

if signal.Type == node.EventTransactionQueued {
event := signal.Event.(map[string]interface{})
txID := event["id"].(string)
txHash, err = s.backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account2.Password)
s.NoError(err, "cannot complete queued transaction %s", txID)

close(transactionCompleted)
}
})

result := s.backend.CallRPC(`{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendTransaction",
"params": [{
"from": "` + TestConfig.Account2.Address + `",
"to": "` + TestConfig.Account1.Address + `",
"value": "0x9184e72a"
}]
}`)
s.NotContains(result, "error")

select {
case <-transactionCompleted:
case <-time.After(time.Minute):
s.FailNow("sending transaction timed out")
}

s.Equal(`{"jsonrpc":"2.0","id":1,"result":"`+txHash.String()+`"}`, result)
}

// FIXME(tiabc): There's also a test with the same name in geth/node/manager_test.go
// so this test should only check StatusBackend logic with a mocked version of the underlying NodeManager.
func (s *BackendTestSuite) TestRaceConditions() {
Expand Down
25 changes: 25 additions & 0 deletions geth/common/rpccall.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,28 @@ func (r RPCCall) ParseGasPrice() *hexutil.Big {

return (*hexutil.Big)(parsedValue)
}

// ToSendTxArgs converts RPCCall to SendTxArgs.
func (r RPCCall) ToSendTxArgs() SendTxArgs {
var err error
var fromAddr, toAddr gethcommon.Address

fromAddr, err = r.ParseFromAddress()
if err != nil {
fromAddr = gethcommon.HexToAddress("0x0")
}

toAddr, err = r.ParseToAddress()
if err != nil {
toAddr = gethcommon.HexToAddress("0x0")
}

return SendTxArgs{
To: &toAddr,
From: fromAddr,
Value: r.ParseValue(),
Data: r.ParseData(),
Gas: r.ParseGas(),
GasPrice: r.ParseGasPrice(),
}
}
9 changes: 7 additions & 2 deletions geth/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,11 @@ type AccountManager interface {
// Logout clears whisper identities
Logout() error

// AccountsListRequestHandler returns handler to process account list request
AccountsListRequestHandler() func(entities []common.Address) []common.Address
// Accounts returns handler to process account list request
Accounts() ([]common.Address, error)

// AccountsRPCHandler returns RPC wrapper for Accounts()
AccountsRPCHandler() rpc.Handler

// AddressToDecryptedAccount tries to load decrypted key for a given account.
// The running node, has a keystore directory which is loaded on start. Key file
Expand Down Expand Up @@ -224,6 +227,8 @@ type TxQueueManager interface {
// TODO(adam): might be not needed
SetTransactionReturnHandler(fn EnqueuedTxReturnHandler)

SendTransactionRPCHandler(ctx context.Context, args ...interface{}) (interface{}, error)

// TransactionReturnHandler returns handler that processes responses from internal tx manager
TransactionReturnHandler() func(queuedTx *QueuedTx, err error)

Expand Down
27 changes: 20 additions & 7 deletions geth/common/types_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.