2019-05-07 07:05:38 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2019-07-26 14:45:10 +00:00
|
|
|
"github.com/status-im/status-go/account"
|
2019-12-11 13:59:37 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2019-08-20 15:38:40 +00:00
|
|
|
"github.com/status-im/status-go/node"
|
2019-05-07 07:05:38 +00:00
|
|
|
"github.com/status-im/status-go/params"
|
|
|
|
"github.com/status-im/status-go/signal"
|
|
|
|
"github.com/status-im/status-go/t/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
password = "abc"
|
|
|
|
)
|
|
|
|
|
|
|
|
// since `backend_test` grew too big, subscription tests are moved to its own part
|
|
|
|
|
2019-05-10 10:56:58 +00:00
|
|
|
func TestSubscriptionEthWithParamsDict(t *testing.T) {
|
|
|
|
// a simple test to check the parameter parsing for eth_* filter subscriptions
|
2019-11-23 17:57:05 +00:00
|
|
|
backend := NewGethStatusBackend()
|
2019-08-20 15:38:40 +00:00
|
|
|
// initNodeAndLogin can fail and terminate the test, in that case stopNode must be executed anyway.
|
|
|
|
defer func() {
|
|
|
|
err := backend.StopNode()
|
|
|
|
if err != node.ErrNoRunningNode {
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
}()
|
2019-05-10 10:56:58 +00:00
|
|
|
|
|
|
|
initNodeAndLogin(t, backend)
|
|
|
|
|
|
|
|
createSubscription(t, backend, fmt.Sprintf(`"eth_newFilter", [
|
|
|
|
{
|
|
|
|
"fromBlock":"earliest",
|
|
|
|
"address":["0xc55cf4b03948d7ebc8b9e8bad92643703811d162","0xdee43a267e8726efd60c2e7d5b81552dcd4fa35c","0x703d7dc0bc8e314d65436adf985dda51e09ad43b","0xe639e24346d646e927f323558e6e0031bfc93581","0x2e7cd05f437eb256f363417fd8f920e2efa77540","0x57cc9b83730e6d22b224e9dc3e370967b44a2de0"],
|
|
|
|
"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000005dc6108dc6296b052bbd33000553afe0ea576b5e",null]
|
|
|
|
}
|
|
|
|
]`))
|
|
|
|
}
|
|
|
|
|
2019-05-07 07:05:38 +00:00
|
|
|
func TestSubscriptionPendingTransaction(t *testing.T) {
|
2019-11-23 17:57:05 +00:00
|
|
|
backend := NewGethStatusBackend()
|
2019-05-07 07:05:38 +00:00
|
|
|
backend.allowAllRPC = true
|
2019-08-20 15:38:40 +00:00
|
|
|
defer func() {
|
|
|
|
err := backend.StopNode()
|
|
|
|
if err != node.ErrNoRunningNode {
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
}()
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
account, _ := initNodeAndLogin(t, backend)
|
|
|
|
|
|
|
|
signals := make(chan string)
|
|
|
|
defer func() {
|
|
|
|
signal.ResetDefaultNodeNotificationHandler()
|
|
|
|
close(signals)
|
|
|
|
}()
|
|
|
|
|
|
|
|
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
|
|
signals <- jsonEvent
|
|
|
|
})
|
|
|
|
|
|
|
|
subID := createSubscription(t, backend, `"eth_newPendingTransactionFilter", []`)
|
|
|
|
|
|
|
|
createTxFmt := `
|
|
|
|
{
|
|
|
|
"jsonrpc":"2.0",
|
|
|
|
"method":"eth_sendTransaction",
|
|
|
|
"params":[
|
|
|
|
{
|
|
|
|
"from": "%s",
|
|
|
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
|
|
|
"gas": "0x100000",
|
|
|
|
"gasPrice": "0x0",
|
|
|
|
"value": "0x0",
|
|
|
|
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
|
|
|
|
}],
|
|
|
|
"id":99
|
|
|
|
}`
|
|
|
|
|
|
|
|
txJSONResponse, err := backend.CallPrivateRPC(fmt.Sprintf(createTxFmt, account))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
createdTxID := extractResult(t, txJSONResponse)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case event := <-signals:
|
|
|
|
validateTxEvent(t, subID, event, createdTxID)
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
require.Fail(t, "timeout waiting for subscription")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionWhisperEnvelopes(t *testing.T) {
|
2019-11-23 17:57:05 +00:00
|
|
|
backend := NewGethStatusBackend()
|
2019-08-20 15:38:40 +00:00
|
|
|
defer func() {
|
|
|
|
err := backend.StopNode()
|
|
|
|
if err != node.ErrNoRunningNode {
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
}()
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
initNodeAndLogin(t, backend)
|
|
|
|
|
|
|
|
signals := make(chan string)
|
|
|
|
defer func() {
|
|
|
|
signal.ResetDefaultNodeNotificationHandler()
|
|
|
|
close(signals)
|
|
|
|
}()
|
|
|
|
|
|
|
|
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
|
|
signals <- jsonEvent
|
|
|
|
})
|
|
|
|
|
|
|
|
topic := "0x12341234"
|
|
|
|
payload := "0x12312312"
|
|
|
|
|
|
|
|
shhGenSymKeyJSONResponse, err := backend.CallPrivateRPC(`{"jsonrpc":"2.0","method":"shh_generateSymKeyFromPassword","params":["test"],"id":119}`)
|
|
|
|
require.NoError(t, err)
|
|
|
|
symKeyID := extractResult(t, shhGenSymKeyJSONResponse)
|
|
|
|
|
|
|
|
subID := createSubscription(t, backend, fmt.Sprintf(`"shh_newMessageFilter", [{ "symKeyID": "%s", "topics": ["%s"] }]`, symKeyID, topic))
|
|
|
|
|
|
|
|
sendMessageFmt := `
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_post",
|
|
|
|
"params": [{
|
|
|
|
"ttl": 7,
|
|
|
|
"symKeyID": "%s",
|
|
|
|
"topic": "%s",
|
|
|
|
"powTarget": 2.01,
|
|
|
|
"powTime": 2,
|
|
|
|
"payload": "%s"
|
|
|
|
}],
|
|
|
|
"id":11
|
|
|
|
}`
|
|
|
|
|
|
|
|
numberOfEnvelopes := 5
|
|
|
|
|
|
|
|
for i := 0; i < numberOfEnvelopes; i++ {
|
|
|
|
_, err = backend.CallPrivateRPC(fmt.Sprintf(sendMessageFmt, symKeyID, topic, payload))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2019-06-08 08:04:18 +00:00
|
|
|
var (
|
|
|
|
total int
|
|
|
|
after = time.After(2 * time.Second)
|
|
|
|
exit bool
|
|
|
|
)
|
|
|
|
for !exit {
|
|
|
|
select {
|
|
|
|
case event := <-signals:
|
|
|
|
total += validateShhEvent(t, event, subID, topic, payload)
|
|
|
|
if total == numberOfEnvelopes {
|
|
|
|
exit = true
|
|
|
|
}
|
|
|
|
case <-after:
|
|
|
|
exit = true
|
|
|
|
}
|
2019-05-07 07:05:38 +00:00
|
|
|
}
|
2019-06-08 08:04:18 +00:00
|
|
|
require.Equal(t, numberOfEnvelopes, total, "total number of envelopes must be equal to sent number of envelopes")
|
2019-05-07 07:05:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// * * * * * * * * * * utility methods below * * * * * * * * * * *
|
|
|
|
|
2019-06-08 08:04:18 +00:00
|
|
|
func validateShhEvent(t *testing.T, jsonEvent string, expectedSubID string, topic string, payload string) int {
|
2019-05-07 07:05:38 +00:00
|
|
|
result := struct {
|
|
|
|
Event signal.SubscriptionDataEvent `json:"event"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result))
|
|
|
|
|
|
|
|
require.Equal(t, signal.EventSubscriptionsData, result.Type)
|
|
|
|
require.Equal(t, expectedSubID, result.Event.FilterID)
|
|
|
|
|
|
|
|
for _, item := range result.Event.Data {
|
|
|
|
dict := item.(map[string]interface{})
|
|
|
|
require.Equal(t, dict["topic"], topic)
|
|
|
|
require.Equal(t, dict["payload"], payload)
|
|
|
|
}
|
2019-06-08 08:04:18 +00:00
|
|
|
return len(result.Event.Data)
|
2019-05-07 07:05:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func validateTxEvent(t *testing.T, expectedSubID string, jsonEvent string, txID string) {
|
|
|
|
result := struct {
|
|
|
|
Event signal.SubscriptionDataEvent `json:"event"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
expectedData := []interface{}{
|
|
|
|
txID,
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result))
|
|
|
|
|
|
|
|
require.Equal(t, signal.EventSubscriptionsData, result.Type)
|
|
|
|
require.Equal(t, expectedSubID, result.Event.FilterID)
|
|
|
|
require.Equal(t, expectedData, result.Event.Data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func extractResult(t *testing.T, jsonString string) string {
|
|
|
|
resultMap := make(map[string]interface{})
|
|
|
|
err := json.Unmarshal([]byte(jsonString), &resultMap)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
value, ok := resultMap["result"]
|
2019-05-10 10:56:58 +00:00
|
|
|
require.True(t, ok, fmt.Sprintf("unexpected response: %s", jsonString))
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
return value.(string)
|
|
|
|
}
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
func createSubscription(t *testing.T, backend StatusBackend, params string) string {
|
2019-05-07 07:05:38 +00:00
|
|
|
createSubFmt := `
|
|
|
|
{
|
2019-06-08 08:04:18 +00:00
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": 10,
|
|
|
|
"method": "eth_subscribeSignal",
|
|
|
|
"params": [%s]
|
|
|
|
|
2019-05-07 07:05:38 +00:00
|
|
|
}`
|
|
|
|
|
|
|
|
jsonResponse, err := backend.CallPrivateRPC(fmt.Sprintf(createSubFmt, params))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return extractResult(t, jsonResponse)
|
|
|
|
}
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
func initNodeAndLogin(t *testing.T, backend *GethStatusBackend) (string, string) {
|
2019-10-04 15:21:24 +00:00
|
|
|
utils.Init()
|
|
|
|
|
2019-05-07 07:05:38 +00:00
|
|
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-08-20 15:38:40 +00:00
|
|
|
require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
|
2019-05-07 07:05:38 +00:00
|
|
|
err = backend.StartNode(config)
|
|
|
|
require.NoError(t, err)
|
|
|
|
info, _, err := backend.AccountManager().CreateAccount(password)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-07-26 14:45:10 +00:00
|
|
|
loginParams := account.LoginParams{
|
2019-12-11 13:59:37 +00:00
|
|
|
MainAccount: types.HexToAddress(info.WalletAddress),
|
|
|
|
ChatAddress: types.HexToAddress(info.ChatAddress),
|
2019-07-26 14:45:10 +00:00
|
|
|
Password: password,
|
|
|
|
}
|
|
|
|
require.NoError(t, backend.AccountManager().SelectAccount(loginParams))
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
unlockFmt := `
|
|
|
|
{
|
2019-06-08 08:04:18 +00:00
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": 11,
|
|
|
|
"method": "personal_unlockAccount",
|
2019-05-07 07:05:38 +00:00
|
|
|
"params": ["%s", "%s"]
|
|
|
|
}`
|
|
|
|
|
|
|
|
unlockResult, err := backend.CallPrivateRPC(fmt.Sprintf(unlockFmt, info.WalletAddress, password))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NotContains(t, unlockResult, "err")
|
|
|
|
|
|
|
|
return info.WalletAddress, info.ChatPubKey
|
|
|
|
}
|