2017-12-07 16:37:43 +03:00
|
|
|
package whisper
|
|
|
|
|
|
|
|
import (
|
2018-06-15 17:12:31 +02:00
|
|
|
"encoding/hex"
|
2017-12-07 16:37:43 +03:00
|
|
|
"encoding/json"
|
2018-02-08 20:52:47 +08:00
|
|
|
"path/filepath"
|
2017-12-07 16:37:43 +03:00
|
|
|
"strconv"
|
2018-06-15 17:12:31 +02:00
|
|
|
"strings"
|
2017-12-07 16:37:43 +03:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
"os"
|
|
|
|
|
2018-06-15 17:12:31 +02:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2017-12-07 16:37:43 +03:00
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
2018-03-02 10:25:30 +01:00
|
|
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
2018-06-08 13:29:50 +02:00
|
|
|
"github.com/status-im/status-go/api"
|
|
|
|
"github.com/status-im/status-go/rpc"
|
2018-02-08 20:52:47 +08:00
|
|
|
. "github.com/status-im/status-go/t/utils"
|
2017-12-07 16:37:43 +03:00
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
)
|
|
|
|
|
2018-06-12 18:50:25 +02:00
|
|
|
const mailboxPassword = "status-offline-inbox"
|
|
|
|
|
2017-12-07 16:37:43 +03:00
|
|
|
type WhisperMailboxSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWhisperMailboxTestSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(WhisperMailboxSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *WhisperMailboxSuite) TestRequestMessageFromMailboxAsync() {
|
2018-04-16 14:36:09 +02:00
|
|
|
var err error
|
2018-03-26 20:05:24 +03:00
|
|
|
// Start mailbox and status node.
|
2017-12-07 16:37:43 +03:00
|
|
|
mailboxBackend, stop := s.startMailboxBackend()
|
|
|
|
defer stop()
|
2018-04-16 14:36:09 +02:00
|
|
|
s.Require().True(mailboxBackend.IsNodeRunning())
|
|
|
|
mailboxNode := mailboxBackend.StatusNode().GethNode()
|
2017-12-07 16:37:43 +03:00
|
|
|
mailboxEnode := mailboxNode.Server().NodeInfo().Enode
|
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
sender, stop := s.startBackend("sender")
|
2017-12-07 16:37:43 +03:00
|
|
|
defer stop()
|
2018-04-16 14:36:09 +02:00
|
|
|
s.Require().True(sender.IsNodeRunning())
|
|
|
|
node := sender.StatusNode().GethNode()
|
2017-12-07 16:37:43 +03:00
|
|
|
|
|
|
|
s.Require().NotEqual(mailboxEnode, node.Server().NodeInfo().Enode)
|
|
|
|
|
2018-04-05 11:45:26 +02:00
|
|
|
err = sender.StatusNode().AddPeer(mailboxEnode)
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
2018-03-26 20:05:24 +03:00
|
|
|
// Wait async processes on adding peer.
|
2018-06-13 16:46:47 +02:00
|
|
|
time.Sleep(500 * time.Millisecond)
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-04-05 11:45:26 +02:00
|
|
|
senderWhisperService, err := sender.StatusNode().WhisperService()
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Mark mailbox node trusted.
|
2017-12-12 14:00:17 +03:00
|
|
|
parsedNode, err := discover.ParseNode(mailboxNode.Server().NodeInfo().Enode)
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
2017-12-12 14:00:17 +03:00
|
|
|
mailboxPeer := parsedNode.ID[:]
|
|
|
|
mailboxPeerStr := parsedNode.ID.String()
|
2017-12-26 15:21:07 +03:00
|
|
|
err = senderWhisperService.AllowP2PMessagesFromPeer(mailboxPeer)
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Generate mailbox symkey.
|
2018-06-12 18:50:25 +02:00
|
|
|
password := mailboxPassword
|
2017-12-26 15:21:07 +03:00
|
|
|
MailServerKeyID, err := senderWhisperService.AddSymKeyFromPassword(password)
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2018-06-06 15:16:17 +02:00
|
|
|
rpcClient := sender.StatusNode().RPCClient()
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NotNil(rpcClient)
|
|
|
|
|
2018-06-15 19:25:10 +02:00
|
|
|
mailboxWhisperService, err := mailboxBackend.StatusNode().WhisperService()
|
|
|
|
s.Require().NoError(err)
|
2018-06-13 16:46:47 +02:00
|
|
|
s.Require().NotNil(mailboxWhisperService)
|
|
|
|
mailboxTracer := newTracer()
|
|
|
|
mailboxWhisperService.RegisterEnvelopeTracer(mailboxTracer)
|
|
|
|
|
|
|
|
tracer := newTracer()
|
|
|
|
senderWhisperService.RegisterEnvelopeTracer(tracer)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Create topic.
|
2018-03-02 10:25:30 +01:00
|
|
|
topic := whisper.BytesToTopic([]byte("topic name"))
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Add key pair to whisper.
|
2017-12-26 15:21:07 +03:00
|
|
|
keyID, err := senderWhisperService.NewKeyPair()
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
2017-12-26 15:21:07 +03:00
|
|
|
key, err := senderWhisperService.GetPrivateKey(keyID)
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
pubkey := hexutil.Bytes(crypto.FromECDSAPub(&key.PublicKey))
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Create message filter.
|
2017-12-26 15:21:07 +03:00
|
|
|
messageFilterID := s.createPrivateChatMessageFilter(rpcClient, keyID, topic.String())
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// There are no messages at filter.
|
2018-01-24 03:25:28 -05:00
|
|
|
messages := s.getMessagesByMessageFilterID(rpcClient, messageFilterID)
|
2018-06-13 16:46:47 +02:00
|
|
|
s.Require().Empty(messages)
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-27 18:35:58 +03:00
|
|
|
// Post message matching with filter (key and topic).
|
2018-06-15 19:25:10 +02:00
|
|
|
messageHash := s.postMessageToPrivate(rpcClient, pubkey.String(), topic.String(), hexutil.Encode([]byte("Hello world!")))
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Get message to make sure that it will come from the mailbox later.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(rpcClient, messageFilterID, mailboxTracer, messageHash)
|
2018-02-05 14:40:27 +01:00
|
|
|
s.Require().Equal(1, len(messages))
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Act.
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-06-15 17:12:31 +02:00
|
|
|
events := make(chan whisper.EnvelopeEvent)
|
|
|
|
senderWhisperService.SubscribeEnvelopeEvents(events)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Request messages (including the previous one, expired) from mailbox.
|
2018-06-15 17:12:31 +02:00
|
|
|
result := s.requestHistoricMessages(senderWhisperService, rpcClient, mailboxPeerStr, MailServerKeyID, topic.String())
|
|
|
|
requestID := common.BytesToHash(result)
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// And we receive message, it comes from mailbox.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(rpcClient, messageFilterID, tracer, messageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Check that there are no messages.
|
2018-01-24 03:25:28 -05:00
|
|
|
messages = s.getMessagesByMessageFilterID(rpcClient, messageFilterID)
|
2018-06-13 16:46:47 +02:00
|
|
|
s.Require().Empty(messages)
|
2018-06-15 17:12:31 +02:00
|
|
|
|
|
|
|
select {
|
|
|
|
case e := <-events:
|
|
|
|
s.Equal(whisper.EventMailServerRequestCompleted, e.Event)
|
|
|
|
s.Equal(requestID, e.Hash)
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
s.Fail("timed out while waiting for request completed event")
|
|
|
|
}
|
2017-12-26 15:21:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
|
2018-04-16 14:36:09 +02:00
|
|
|
var err error
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Start mailbox, alice, bob, charlie node.
|
2017-12-26 15:21:07 +03:00
|
|
|
mailboxBackend, stop := s.startMailboxBackend()
|
|
|
|
defer stop()
|
|
|
|
|
|
|
|
aliceBackend, stop := s.startBackend("alice")
|
|
|
|
defer stop()
|
|
|
|
|
|
|
|
bobBackend, stop := s.startBackend("bob")
|
|
|
|
defer stop()
|
|
|
|
|
|
|
|
charlieBackend, stop := s.startBackend("charlie")
|
|
|
|
defer stop()
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Add mailbox to static peers.
|
2018-04-16 14:36:09 +02:00
|
|
|
s.Require().True(mailboxBackend.IsNodeRunning())
|
|
|
|
mailboxNode := mailboxBackend.StatusNode().GethNode()
|
2017-12-26 15:21:07 +03:00
|
|
|
mailboxEnode := mailboxNode.Server().NodeInfo().Enode
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-04-05 11:45:26 +02:00
|
|
|
err = aliceBackend.StatusNode().AddPeer(mailboxEnode)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NoError(err)
|
2018-04-05 11:45:26 +02:00
|
|
|
err = bobBackend.StatusNode().AddPeer(mailboxEnode)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NoError(err)
|
2018-04-05 11:45:26 +02:00
|
|
|
err = charlieBackend.StatusNode().AddPeer(mailboxEnode)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NoError(err)
|
2018-03-26 20:05:24 +03:00
|
|
|
// Wait async processes on adding peer.
|
2018-06-13 16:46:47 +02:00
|
|
|
time.Sleep(500 * time.Millisecond)
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Get whisper service.
|
2018-04-05 11:45:26 +02:00
|
|
|
aliceWhisperService, err := aliceBackend.StatusNode().WhisperService()
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NoError(err)
|
2018-04-05 11:45:26 +02:00
|
|
|
bobWhisperService, err := bobBackend.StatusNode().WhisperService()
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NoError(err)
|
2018-04-05 11:45:26 +02:00
|
|
|
charlieWhisperService, err := charlieBackend.StatusNode().WhisperService()
|
2017-12-12 14:00:17 +03:00
|
|
|
s.Require().NoError(err)
|
2018-03-26 20:05:24 +03:00
|
|
|
// Get rpc client.
|
2018-06-06 15:16:17 +02:00
|
|
|
aliceRPCClient := aliceBackend.StatusNode().RPCClient()
|
|
|
|
bobRPCClient := bobBackend.StatusNode().RPCClient()
|
|
|
|
charlieRPCClient := charlieBackend.StatusNode().RPCClient()
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-06-13 16:46:47 +02:00
|
|
|
aliceTracer := newTracer()
|
|
|
|
aliceWhisperService.RegisterEnvelopeTracer(aliceTracer)
|
|
|
|
bobTracer := newTracer()
|
|
|
|
bobWhisperService.RegisterEnvelopeTracer(bobTracer)
|
|
|
|
charlieTracer := newTracer()
|
|
|
|
charlieWhisperService.RegisterEnvelopeTracer(charlieTracer)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob and charlie add the mailserver key.
|
2018-06-12 18:50:25 +02:00
|
|
|
password := mailboxPassword
|
2017-12-26 15:21:07 +03:00
|
|
|
bobMailServerKeyID, err := bobWhisperService.AddSymKeyFromPassword(password)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
charlieMailServerKeyID, err := charlieWhisperService.AddSymKeyFromPassword(password)
|
2017-12-12 14:00:17 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Generate a group chat symkey and topic.
|
2017-12-26 15:21:07 +03:00
|
|
|
groupChatKeyID, err := aliceWhisperService.GenerateSymKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
groupChatKey, err := aliceWhisperService.GetSymKey(groupChatKeyID)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 20:05:24 +03:00
|
|
|
// Generate a group chat topic.
|
2018-03-02 10:25:30 +01:00
|
|
|
groupChatTopic := whisper.BytesToTopic([]byte("groupChatTopic"))
|
2018-04-24 18:50:26 +03:00
|
|
|
// sender must be subscribed to message topic it sends
|
|
|
|
s.NotNil(s.createGroupChatMessageFilter(aliceRPCClient, groupChatKeyID, groupChatTopic.String()))
|
2017-12-26 15:21:07 +03:00
|
|
|
groupChatPayload := newGroupChatParams(groupChatKey, groupChatTopic)
|
|
|
|
payloadStr, err := groupChatPayload.Encode()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Add Bob and Charlie's key pairs to receive the symmetric key for the group chat from Alice.
|
2017-12-26 15:21:07 +03:00
|
|
|
bobKeyID, err := bobWhisperService.NewKeyPair()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
bobKey, err := bobWhisperService.GetPrivateKey(bobKeyID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
bobPubkey := hexutil.Bytes(crypto.FromECDSAPub(&bobKey.PublicKey))
|
2018-03-02 10:25:30 +01:00
|
|
|
bobAliceKeySendTopic := whisper.BytesToTopic([]byte("bobAliceKeySendTopic "))
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
charlieKeyID, err := charlieWhisperService.NewKeyPair()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
charlieKey, err := charlieWhisperService.GetPrivateKey(charlieKeyID)
|
2017-12-12 14:00:17 +03:00
|
|
|
s.Require().NoError(err)
|
2017-12-26 15:21:07 +03:00
|
|
|
charliePubkey := hexutil.Bytes(crypto.FromECDSAPub(&charlieKey.PublicKey))
|
2018-03-02 10:25:30 +01:00
|
|
|
charlieAliceKeySendTopic := whisper.BytesToTopic([]byte("charlieAliceKeySendTopic "))
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2018-05-04 08:57:34 +03:00
|
|
|
// Alice must add peers topics into her own bloom filter.
|
|
|
|
aliceKeyID, err := aliceWhisperService.NewKeyPair()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.createPrivateChatMessageFilter(aliceRPCClient, aliceKeyID, bobAliceKeySendTopic.String())
|
|
|
|
s.createPrivateChatMessageFilter(aliceRPCClient, aliceKeyID, charlieAliceKeySendTopic.String())
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob and charlie create message filter.
|
2018-01-24 03:25:28 -05:00
|
|
|
bobMessageFilterID := s.createPrivateChatMessageFilter(bobRPCClient, bobKeyID, bobAliceKeySendTopic.String())
|
|
|
|
charlieMessageFilterID := s.createPrivateChatMessageFilter(charlieRPCClient, charlieKeyID, charlieAliceKeySendTopic.String())
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Alice send message with symkey and topic to Bob and Charlie.
|
2018-06-15 19:25:10 +02:00
|
|
|
aliceToBobMessageHash := s.postMessageToPrivate(aliceRPCClient, bobPubkey.String(), bobAliceKeySendTopic.String(), payloadStr)
|
|
|
|
aliceToCharlieMessageHash := s.postMessageToPrivate(aliceRPCClient, charliePubkey.String(), charlieAliceKeySendTopic.String(), payloadStr)
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob receive group chat data and add it to his node.
|
|
|
|
// Bob get group chat details.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages := s.getMessagesByMessageFilterIDWithTracer(bobRPCClient, bobMessageFilterID, bobTracer, aliceToBobMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
bobGroupChatData := groupChatParams{}
|
2018-02-12 06:16:06 -05:00
|
|
|
err = bobGroupChatData.Decode(messages[0]["payload"].(string))
|
|
|
|
s.Require().NoError(err)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.EqualValues(groupChatPayload, bobGroupChatData)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob add symkey to his node.
|
2018-01-24 03:25:28 -05:00
|
|
|
bobGroupChatSymkeyID := s.addSymKey(bobRPCClient, bobGroupChatData.Key)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NotEmpty(bobGroupChatSymkeyID)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob create message filter to node by group chat topic.
|
2018-01-24 03:25:28 -05:00
|
|
|
bobGroupChatMessageFilterID := s.createGroupChatMessageFilter(bobRPCClient, bobGroupChatSymkeyID, bobGroupChatData.Topic)
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Charlie receive group chat data and add it to his node.
|
|
|
|
// Charlie get group chat details.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(charlieRPCClient, charlieMessageFilterID, charlieTracer, aliceToCharlieMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
charlieGroupChatData := groupChatParams{}
|
2018-02-12 06:16:06 -05:00
|
|
|
err = charlieGroupChatData.Decode(messages[0]["payload"].(string))
|
|
|
|
s.Require().NoError(err)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.EqualValues(groupChatPayload, charlieGroupChatData)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Charlie add symkey to his node.
|
2018-01-24 03:25:28 -05:00
|
|
|
charlieGroupChatSymkeyID := s.addSymKey(charlieRPCClient, charlieGroupChatData.Key)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NotEmpty(charlieGroupChatSymkeyID)
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Charlie create message filter to node by group chat topic.
|
2018-01-24 03:25:28 -05:00
|
|
|
charlieGroupChatMessageFilterID := s.createGroupChatMessageFilter(charlieRPCClient, charlieGroupChatSymkeyID, charlieGroupChatData.Topic)
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Alice send message to group chat.
|
2017-12-26 15:21:07 +03:00
|
|
|
helloWorldMessage := hexutil.Encode([]byte("Hello world!"))
|
2018-06-15 19:25:10 +02:00
|
|
|
groupChatMessageHash := s.postMessageToGroup(aliceRPCClient, groupChatKeyID, groupChatTopic.String(), helloWorldMessage)
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob receive group chat message.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(bobRPCClient, bobGroupChatMessageFilterID, bobTracer, groupChatMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
s.Require().Equal(helloWorldMessage, messages[0]["payload"].(string))
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Charlie receive group chat message.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(charlieRPCClient, charlieGroupChatMessageFilterID, charlieTracer, groupChatMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
s.Require().Equal(helloWorldMessage, messages[0]["payload"].(string))
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Check that we don't receive messages each one time.
|
2018-01-24 03:25:28 -05:00
|
|
|
messages = s.getMessagesByMessageFilterID(bobRPCClient, bobGroupChatMessageFilterID)
|
2018-06-13 16:46:47 +02:00
|
|
|
s.Require().Empty(messages)
|
2018-01-24 03:25:28 -05:00
|
|
|
messages = s.getMessagesByMessageFilterID(charlieRPCClient, charlieGroupChatMessageFilterID)
|
2018-06-13 16:46:47 +02:00
|
|
|
s.Require().Empty(messages)
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Request each one messages from mailbox using enode.
|
2018-05-04 11:23:38 +03:00
|
|
|
s.requestHistoricMessages(bobWhisperService, bobRPCClient, mailboxEnode, bobMailServerKeyID, groupChatTopic.String())
|
|
|
|
s.requestHistoricMessages(charlieWhisperService, charlieRPCClient, mailboxEnode, charlieMailServerKeyID, groupChatTopic.String())
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Bob receive p2p message from group chat filter.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(bobRPCClient, bobGroupChatMessageFilterID, bobTracer, groupChatMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
s.Require().Equal(helloWorldMessage, messages[0]["payload"].(string))
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Charlie receive p2p message from group chat filter.
|
2018-06-15 19:25:10 +02:00
|
|
|
messages = s.getMessagesByMessageFilterIDWithTracer(charlieRPCClient, charlieGroupChatMessageFilterID, charlieTracer, groupChatMessageHash)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().Equal(1, len(messages))
|
|
|
|
s.Require().Equal(helloWorldMessage, messages[0]["payload"].(string))
|
|
|
|
}
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-03-02 10:25:30 +01:00
|
|
|
func newGroupChatParams(symkey []byte, topic whisper.TopicType) groupChatParams {
|
2017-12-26 15:21:07 +03:00
|
|
|
groupChatKeyStr := hexutil.Bytes(symkey).String()
|
|
|
|
return groupChatParams{
|
|
|
|
Key: groupChatKeyStr,
|
|
|
|
Topic: topic.String(),
|
|
|
|
}
|
|
|
|
}
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
type groupChatParams struct {
|
|
|
|
Key string
|
|
|
|
Topic string
|
|
|
|
}
|
2017-12-12 14:00:17 +03:00
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
func (d *groupChatParams) Decode(i string) error {
|
|
|
|
b, err := hexutil.Decode(i)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return json.Unmarshal(b, &d)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *groupChatParams) Encode() (string, error) {
|
|
|
|
payload, err := json.Marshal(d)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return hexutil.Bytes(payload).String(), nil
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Start status node.
|
2017-12-26 15:21:07 +03:00
|
|
|
func (s *WhisperMailboxSuite) startBackend(name string) (*api.StatusBackend, func()) {
|
2018-02-08 20:52:47 +08:00
|
|
|
datadir := filepath.Join(RootDir, ".ethereumtest/mailbox", name)
|
2017-12-07 16:37:43 +03:00
|
|
|
backend := api.NewStatusBackend()
|
2018-03-02 10:25:30 +01:00
|
|
|
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
2017-12-26 15:21:07 +03:00
|
|
|
nodeConfig.DataDir = datadir
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().False(backend.IsNodeRunning())
|
2018-02-27 11:39:30 +01:00
|
|
|
|
2018-03-26 19:01:26 +03:00
|
|
|
nodeConfig.WhisperConfig.LightClient = true
|
|
|
|
|
2018-02-27 11:39:30 +01:00
|
|
|
if addr, err := GetRemoteURL(); err == nil {
|
|
|
|
nodeConfig.UpstreamConfig.Enabled = true
|
|
|
|
nodeConfig.UpstreamConfig.URL = addr
|
|
|
|
}
|
|
|
|
|
2018-02-09 15:37:56 +02:00
|
|
|
s.Require().NoError(backend.StartNode(nodeConfig))
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().True(backend.IsNodeRunning())
|
|
|
|
|
|
|
|
return backend, func() {
|
|
|
|
s.True(backend.IsNodeRunning())
|
2018-02-09 15:37:56 +02:00
|
|
|
s.NoError(backend.StopNode())
|
2017-12-07 16:37:43 +03:00
|
|
|
s.False(backend.IsNodeRunning())
|
2018-02-12 06:16:06 -05:00
|
|
|
err = os.RemoveAll(datadir)
|
|
|
|
s.Require().NoError(err)
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-12-26 15:21:07 +03:00
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// Start mailbox node.
|
2017-12-07 16:37:43 +03:00
|
|
|
func (s *WhisperMailboxSuite) startMailboxBackend() (*api.StatusBackend, func()) {
|
|
|
|
mailboxBackend := api.NewStatusBackend()
|
2018-03-02 10:25:30 +01:00
|
|
|
mailboxConfig, err := MakeTestNodeConfig(GetNetworkID())
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().NoError(err)
|
2018-02-08 20:52:47 +08:00
|
|
|
datadir := filepath.Join(RootDir, ".ethereumtest/mailbox/mailserver")
|
2017-12-07 16:37:43 +03:00
|
|
|
|
|
|
|
mailboxConfig.LightEthConfig.Enabled = false
|
|
|
|
mailboxConfig.WhisperConfig.Enabled = true
|
2018-02-08 20:52:47 +08:00
|
|
|
mailboxConfig.KeyStoreDir = datadir
|
2017-12-07 16:37:43 +03:00
|
|
|
mailboxConfig.WhisperConfig.EnableMailServer = true
|
2018-02-08 20:52:47 +08:00
|
|
|
mailboxConfig.WhisperConfig.PasswordFile = filepath.Join(RootDir, "/static/keys/wnodepassword")
|
|
|
|
mailboxConfig.WhisperConfig.DataDir = filepath.Join(datadir, "data")
|
2017-12-26 15:21:07 +03:00
|
|
|
mailboxConfig.DataDir = datadir
|
2017-12-07 16:37:43 +03:00
|
|
|
|
2018-02-21 13:18:32 +01:00
|
|
|
s.Require().False(mailboxBackend.IsNodeRunning())
|
2018-02-09 15:37:56 +02:00
|
|
|
s.Require().NoError(mailboxBackend.StartNode(mailboxConfig))
|
2017-12-07 16:37:43 +03:00
|
|
|
s.Require().True(mailboxBackend.IsNodeRunning())
|
|
|
|
return mailboxBackend, func() {
|
|
|
|
s.True(mailboxBackend.IsNodeRunning())
|
2018-02-09 15:37:56 +02:00
|
|
|
s.NoError(mailboxBackend.StopNode())
|
2017-12-07 16:37:43 +03:00
|
|
|
s.False(mailboxBackend.IsNodeRunning())
|
2018-02-12 06:16:06 -05:00
|
|
|
err = os.RemoveAll(datadir)
|
|
|
|
s.Require().NoError(err)
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// createPrivateChatMessageFilter create message filter with asymmetric encryption.
|
2017-12-26 15:21:07 +03:00
|
|
|
func (s *WhisperMailboxSuite) createPrivateChatMessageFilter(rpcCli *rpc.Client, privateKeyID string, topic string) string {
|
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_newMessageFilter", "params": [
|
|
|
|
{"privateKeyID": "` + privateKeyID + `", "topics": [ "` + topic + `"], "allowP2P":true}
|
|
|
|
],
|
|
|
|
"id": 1
|
|
|
|
}`)
|
|
|
|
|
|
|
|
msgFilterResp := returnedIDResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &msgFilterResp)
|
|
|
|
messageFilterID := msgFilterResp.Result
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(msgFilterResp.Error)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NotEqual("", messageFilterID, resp)
|
|
|
|
return messageFilterID
|
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// createGroupChatMessageFilter create message filter with symmetric encryption.
|
2017-12-26 15:21:07 +03:00
|
|
|
func (s *WhisperMailboxSuite) createGroupChatMessageFilter(rpcCli *rpc.Client, symkeyID string, topic string) string {
|
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_newMessageFilter", "params": [
|
|
|
|
{"symKeyID": "` + symkeyID + `", "topics": [ "` + topic + `"], "allowP2P":true}
|
|
|
|
],
|
|
|
|
"id": 1
|
|
|
|
}`)
|
|
|
|
|
|
|
|
msgFilterResp := returnedIDResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &msgFilterResp)
|
|
|
|
messageFilterID := msgFilterResp.Result
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(msgFilterResp.Error)
|
2017-12-26 15:21:07 +03:00
|
|
|
s.Require().NotEqual("", messageFilterID, resp)
|
|
|
|
return messageFilterID
|
|
|
|
}
|
|
|
|
|
2018-06-15 19:25:10 +02:00
|
|
|
func (s *WhisperMailboxSuite) postMessageToPrivate(rpcCli *rpc.Client, bobPubkey string, topic string, payload string) string {
|
2017-12-26 15:21:07 +03:00
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_post",
|
|
|
|
"params": [
|
|
|
|
{
|
|
|
|
"pubKey": "` + bobPubkey + `",
|
|
|
|
"topic": "` + topic + `",
|
|
|
|
"payload": "` + payload + `",
|
|
|
|
"powTarget": 0.001,
|
|
|
|
"powTime": 2
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"id": 1}`)
|
|
|
|
postResp := baseRPCResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &postResp)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(postResp.Error)
|
2018-06-15 19:25:10 +02:00
|
|
|
|
|
|
|
return postResp.Result.(string)
|
2017-12-26 15:21:07 +03:00
|
|
|
}
|
|
|
|
|
2018-06-15 19:25:10 +02:00
|
|
|
func (s *WhisperMailboxSuite) postMessageToGroup(rpcCli *rpc.Client, groupChatKeyID string, topic string, payload string) string {
|
2017-12-26 15:21:07 +03:00
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_post",
|
|
|
|
"params": [
|
|
|
|
{
|
|
|
|
"symKeyID": "` + groupChatKeyID + `",
|
|
|
|
"topic": "` + topic + `",
|
|
|
|
"payload": "` + payload + `",
|
|
|
|
"powTarget": 0.001,
|
|
|
|
"powTime": 2
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"id": 1}`)
|
|
|
|
postResp := baseRPCResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &postResp)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(postResp.Error)
|
2018-06-15 19:25:10 +02:00
|
|
|
|
|
|
|
return postResp.Result.(string)
|
2017-12-26 15:21:07 +03:00
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// getMessagesByMessageFilterID gets received messages by messageFilterID.
|
2018-01-24 03:25:28 -05:00
|
|
|
func (s *WhisperMailboxSuite) getMessagesByMessageFilterID(rpcCli *rpc.Client, messageFilterID string) []map[string]interface{} {
|
2017-12-26 15:21:07 +03:00
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "shh_getFilterMessages",
|
|
|
|
"params": ["` + messageFilterID + `"],
|
|
|
|
"id": 1}`)
|
|
|
|
messages := getFilterMessagesResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &messages)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(messages.Error)
|
2017-12-26 15:21:07 +03:00
|
|
|
return messages.Result
|
|
|
|
}
|
|
|
|
|
2018-06-15 19:25:10 +02:00
|
|
|
func (s *WhisperMailboxSuite) getMessagesByMessageFilterIDWithTracer(rpcCli *rpc.Client, messageFilterID string, tracer *envelopeTracer, messageHash string) (messages []map[string]interface{}) {
|
2018-06-13 16:46:47 +02:00
|
|
|
select {
|
2018-06-15 19:25:10 +02:00
|
|
|
case envelope := <-tracer.envelopChan:
|
|
|
|
s.Require().Equal(envelope.Hash, messageHash)
|
2018-06-13 16:46:47 +02:00
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
s.Fail("Timed out waiting for new messages after 5 seconds")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to retrieve messages up to 3 times, 1 second apart
|
|
|
|
// TODO: There is a lag between the time when the envelope is traced by EventTracer
|
|
|
|
// and when it is decoded and actually available. Ideally this would be event-driven as well
|
|
|
|
// I.e. instead of signing up for EnvelopeTracer, we'd sign up for an event happening later
|
|
|
|
// which tells us that a call to shh_getFilterMessages will return some messages
|
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
messages = s.getMessagesByMessageFilterID(rpcCli, messageFilterID)
|
|
|
|
if len(messages) > 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// addSymKey added symkey to node and return symkeyID.
|
2017-12-26 15:21:07 +03:00
|
|
|
func (s *WhisperMailboxSuite) addSymKey(rpcCli *rpc.Client, symkey string) string {
|
|
|
|
resp := rpcCli.CallRaw(`{"jsonrpc":"2.0","method":"shh_addSymKey",
|
|
|
|
"params":["` + symkey + `"],
|
|
|
|
"id":1}`)
|
|
|
|
symkeyAddResp := returnedIDResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &symkeyAddResp)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(symkeyAddResp.Error)
|
2017-12-26 15:21:07 +03:00
|
|
|
symkeyID := symkeyAddResp.Result
|
|
|
|
s.Require().NotEmpty(symkeyID)
|
|
|
|
return symkeyID
|
|
|
|
}
|
|
|
|
|
2018-03-26 20:05:24 +03:00
|
|
|
// requestHistoricMessages asks a mailnode to resend messages.
|
2018-06-15 17:12:31 +02:00
|
|
|
func (s *WhisperMailboxSuite) requestHistoricMessages(w *whisper.Whisper, rpcCli *rpc.Client, mailboxEnode, mailServerKeyID, topic string) []byte {
|
2018-06-13 16:46:47 +02:00
|
|
|
currentTime := w.GetCurrentTime()
|
|
|
|
from := currentTime.Add(-12 * time.Hour)
|
|
|
|
to := currentTime
|
2017-12-26 15:21:07 +03:00
|
|
|
resp := rpcCli.CallRaw(`{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": 2,
|
2018-04-26 07:56:19 +02:00
|
|
|
"method": "shhext_requestMessages",
|
2017-12-26 15:21:07 +03:00
|
|
|
"params": [{
|
|
|
|
"mailServerPeer":"` + mailboxEnode + `",
|
|
|
|
"topic":"` + topic + `",
|
|
|
|
"symKeyID":"` + mailServerKeyID + `",
|
2018-05-17 13:21:04 +02:00
|
|
|
"from":` + strconv.FormatInt(from.Unix(), 10) + `,
|
2018-06-13 16:46:47 +02:00
|
|
|
"to":` + strconv.FormatInt(to.Unix(), 10) + `
|
2017-12-26 15:21:07 +03:00
|
|
|
}]
|
|
|
|
}`)
|
|
|
|
reqMessagesResp := baseRPCResponse{}
|
|
|
|
err := json.Unmarshal([]byte(resp), &reqMessagesResp)
|
|
|
|
s.Require().NoError(err)
|
2018-03-26 19:01:26 +03:00
|
|
|
s.Require().Nil(reqMessagesResp.Error)
|
2018-06-15 17:12:31 +02:00
|
|
|
|
|
|
|
switch hash := reqMessagesResp.Result.(type) {
|
|
|
|
case string:
|
|
|
|
s.Require().True(strings.HasPrefix(hash, "0x"))
|
|
|
|
b, err := hex.DecodeString(hash[2:])
|
|
|
|
s.Require().NoError(err)
|
|
|
|
return b
|
|
|
|
default:
|
|
|
|
s.Failf("failed reading shh_newMessageFilter result", "expected a hash, got: %+v", reqMessagesResp.Result)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2017-12-26 15:21:07 +03:00
|
|
|
}
|
|
|
|
|
2017-12-07 16:37:43 +03:00
|
|
|
type getFilterMessagesResponse struct {
|
|
|
|
Result []map[string]interface{}
|
2018-03-26 19:01:26 +03:00
|
|
|
Error interface{}
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
|
|
|
|
2017-12-26 15:21:07 +03:00
|
|
|
type returnedIDResponse struct {
|
2017-12-07 16:37:43 +03:00
|
|
|
Result string
|
2018-03-26 19:01:26 +03:00
|
|
|
Error interface{}
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
2017-12-12 14:00:17 +03:00
|
|
|
type baseRPCResponse struct {
|
|
|
|
Result interface{}
|
2018-03-26 19:01:26 +03:00
|
|
|
Error interface{}
|
2017-12-07 16:37:43 +03:00
|
|
|
}
|
2018-06-13 16:46:47 +02:00
|
|
|
|
|
|
|
// envelopeTracer traces incoming envelopes. We leverage it to know when a peer has received an envelope
|
|
|
|
// so we rely less on timeouts for the tests
|
|
|
|
type envelopeTracer struct {
|
|
|
|
envelopChan chan *whisper.EnvelopeMeta
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTracer() *envelopeTracer {
|
|
|
|
return &envelopeTracer{make(chan *whisper.EnvelopeMeta, 1)}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trace is called for every incoming envelope.
|
|
|
|
func (t *envelopeTracer) Trace(envelope *whisper.EnvelopeMeta) {
|
|
|
|
// Do not block notifier
|
|
|
|
go func() { t.envelopChan <- envelope }()
|
|
|
|
}
|