mirror of
https://github.com/status-im/status-go.git
synced 2025-01-28 07:27:00 +00:00
1c8d32c451
During CI tests non-deterministic failures with "no suitable peers available" happened. Reason is a not finished synchronisation after starting of node. Added and integrated an EnsureSychronization() almost solved it, but overlapped with new added EnsureNodeSync() in merged develop. Failure stayed, so exchange new algorithm in EsureNodeSync() with former one.
434 lines
10 KiB
Go
434 lines
10 KiB
Go
package whisper
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
|
"github.com/status-im/status-go/e2e"
|
|
"github.com/status-im/status-go/geth/common"
|
|
"github.com/status-im/status-go/geth/params"
|
|
"github.com/status-im/status-go/static"
|
|
. "github.com/status-im/status-go/testing"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
const (
|
|
whisperMessage1 = `test message 1 (K1 -> K2, signed+encrypted, from us)`
|
|
whisperMessage2 = `test message 3 (K1 -> "", signed broadcast)`
|
|
whisperMessage3 = `test message 4 ("" -> "", anon broadcast)`
|
|
whisperMessage4 = `test message 5 ("" -> K1, encrypted anon broadcast)`
|
|
whisperMessage5 = `test message 6 (K2 -> K1, signed+encrypted, to us)`
|
|
)
|
|
|
|
var (
|
|
baseStatusJSCode = string(static.MustAsset("testdata/jail/status.js"))
|
|
)
|
|
|
|
func TestWhisperJailTestSuite(t *testing.T) {
|
|
s := new(WhisperJailTestSuite)
|
|
s.Timeout = time.Minute * 5
|
|
suite.Run(t, s)
|
|
}
|
|
|
|
type WhisperJailTestSuite struct {
|
|
e2e.BackendTestSuite
|
|
|
|
Timeout time.Duration
|
|
WhisperAPI *whisper.PublicWhisperAPI
|
|
Jail common.JailManager
|
|
}
|
|
|
|
func (s *WhisperJailTestSuite) StartTestBackend(networkID int, opts ...e2e.TestNodeOption) {
|
|
s.BackendTestSuite.StartTestBackend(networkID, opts...)
|
|
|
|
s.WhisperAPI = whisper.NewPublicWhisperAPI(s.WhisperService())
|
|
s.Jail = s.Backend.JailManager()
|
|
s.NotNil(s.Jail)
|
|
s.Jail.BaseJS(baseStatusJSCode)
|
|
}
|
|
|
|
func (s *WhisperJailTestSuite) GetAccountKey(account struct {
|
|
Address string
|
|
Password string
|
|
}) (*keystore.Key, string, error) {
|
|
accountManager := s.Backend.AccountManager()
|
|
|
|
_, accountKey1, err := accountManager.AddressToDecryptedAccount(account.Address, account.Password)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
accountKey1Hex := gethcommon.ToHex(crypto.FromECDSAPub(&accountKey1.PrivateKey.PublicKey))
|
|
|
|
_, err = s.WhisperService().AddKeyPair(accountKey1.PrivateKey)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
if ok := s.WhisperAPI.HasKeyPair(context.Background(), accountKey1Hex); !ok {
|
|
return nil, "", errors.New("KeyPair should be injected in Whisper")
|
|
}
|
|
|
|
return accountKey1, accountKey1Hex, nil
|
|
}
|
|
|
|
// TODO(adamb) Uncomment when issue #336 is fixed.
|
|
/*
|
|
func (s *WhisperJailTestSuite) DontTestJailWhisper() {
|
|
s.StartTestBackend(params.RopstenNetworkID)
|
|
defer s.StopTestBackend()
|
|
|
|
_, accountKey1Hex, err := s.GetAccountKey(TestConfig.Account1)
|
|
s.NoError(err)
|
|
|
|
_, accountKey2Hex, err := s.GetAccountKey(TestConfig.Account2)
|
|
s.NoError(err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
code string
|
|
useFilter bool
|
|
}{
|
|
{
|
|
"test 0: ensure correct version of Whisper is used",
|
|
`
|
|
var expectedVersion = '5.0';
|
|
if (web3.version.whisper != expectedVersion) {
|
|
throw 'unexpected shh version, expected: ' + expectedVersion + ', got: ' + web3.version.whisper;
|
|
}
|
|
`,
|
|
false,
|
|
},
|
|
{
|
|
"test 1: encrypted signed message from us (From != nil && To != nil)",
|
|
`
|
|
var identity1 = '` + accountKey1Hex + `';
|
|
if (!shh.hasKeyPair(identity1)) {
|
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
|
}
|
|
|
|
var identity2 = '` + accountKey2Hex + `';
|
|
if (!shh.hasKeyPair(identity2)) {
|
|
throw 'identitity "` + accountKey2Hex + `" not found in whisper';
|
|
}
|
|
|
|
var topic = makeTopic();
|
|
var payload = '` + whisperMessage1 + `';
|
|
|
|
// start watching for messages
|
|
var filter = shh.newMessageFilter({
|
|
sig: identity1,
|
|
privateKeyID: identity2,
|
|
topics: [topic]
|
|
});
|
|
|
|
// post message
|
|
var message = {
|
|
ttl: 20,
|
|
powTarget: 0.01,
|
|
powTime: 20,
|
|
topic: topic,
|
|
sig: identity1,
|
|
pubKey: identity2,
|
|
payload: web3.toHex(payload),
|
|
};
|
|
|
|
var sent = shh.post(message)
|
|
if (!sent) {
|
|
throw 'message not sent: ' + JSON.stringify(message);
|
|
}
|
|
`,
|
|
true,
|
|
},
|
|
{
|
|
"test 2: signed (known sender) broadcast (From != nil && To == nil)",
|
|
`
|
|
var identity = '` + accountKey1Hex + `';
|
|
if (!shh.hasKeyPair(identity)) {
|
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
|
}
|
|
|
|
var topic = makeTopic();
|
|
var payload = '` + whisperMessage2 + `';
|
|
|
|
// generate symmetric key
|
|
var keyid = shh.newSymKey();
|
|
if (!shh.hasSymKey(keyid)) {
|
|
throw new Error('key not found');
|
|
}
|
|
|
|
// start watching for messages
|
|
var filter = shh.newMessageFilter({
|
|
sig: identity,
|
|
topics: [topic],
|
|
symKeyID: keyid
|
|
});
|
|
|
|
// post message
|
|
var message = {
|
|
ttl: 20,
|
|
powTarget: 0.01,
|
|
powTime: 20,
|
|
topic: topic,
|
|
sig: identity,
|
|
symKeyID: keyid,
|
|
payload: web3.toHex(payload),
|
|
};
|
|
|
|
var sent = shh.post(message)
|
|
if (!sent) {
|
|
throw 'message not sent: ' + JSON.stringify(message);
|
|
}
|
|
`,
|
|
true,
|
|
},
|
|
{
|
|
"test 3: anonymous broadcast (From == nil && To == nil)",
|
|
`
|
|
var topic = makeTopic();
|
|
var payload = '` + whisperMessage3 + `';
|
|
|
|
// generate symmetric key
|
|
var keyid = shh.newSymKey();
|
|
if (!shh.hasSymKey(keyid)) {
|
|
throw new Error('key not found');
|
|
}
|
|
|
|
// start watching for messages
|
|
var filter = shh.newMessageFilter({
|
|
topics: [topic],
|
|
symKeyID: keyid
|
|
});
|
|
|
|
// post message
|
|
var message = {
|
|
ttl: 20,
|
|
powTarget: 0.01,
|
|
powTime: 20,
|
|
topic: topic,
|
|
symKeyID: keyid,
|
|
payload: web3.toHex(payload),
|
|
};
|
|
|
|
var sent = shh.post(message)
|
|
if (!sent) {
|
|
throw 'message not sent: ' + JSON.stringify(message);
|
|
}
|
|
`,
|
|
true,
|
|
},
|
|
// @TODO(adam): quarantined as always failing. Check out TestEncryptedAnonymousMessage
|
|
// as an equivalent test in pure Go which passes. Bug in web3?
|
|
// {
|
|
// "test 4: encrypted anonymous message (From == nil && To != nil)",
|
|
// `
|
|
// var identity = '` + accountKey2Hex + `';
|
|
// if (!shh.hasKeyPair(identity)) {
|
|
// throw 'idenitity "` + accountKey2Hex + `" not found in whisper';
|
|
// }
|
|
|
|
// var topic = makeTopic();
|
|
// var payload = '` + whisperMessage4 + `';
|
|
|
|
// // start watching for messages
|
|
// var filter = shh.newMessageFilter({
|
|
// privateKeyID: identity,
|
|
// topics: [topic],
|
|
// });
|
|
|
|
// // post message
|
|
// var message = {
|
|
// ttl: 20,
|
|
// powTarget: 0.01,
|
|
// powTime: 20,
|
|
// topic: topic,
|
|
// pubKey: identity,
|
|
// payload: web3.toHex(payload),
|
|
// };
|
|
|
|
// var sent = shh.post(message)
|
|
// if (!sent) {
|
|
// throw 'message not sent: ' + JSON.stringify(message);
|
|
// }
|
|
// `,
|
|
// true,
|
|
// },
|
|
{
|
|
"test 5: encrypted signed response to us (From != nil && To != nil)",
|
|
`
|
|
var identity1 = '` + accountKey1Hex + `';
|
|
if (!shh.hasKeyPair(identity1)) {
|
|
throw 'idenitity "` + accountKey1Hex + `" not found in whisper';
|
|
}
|
|
var identity2 = '` + accountKey2Hex + `';
|
|
if (!shh.hasKeyPair(identity2)) {
|
|
throw 'idenitity "` + accountKey2Hex + `" not found in whisper';
|
|
}
|
|
var topic = makeTopic();
|
|
var payload = '` + whisperMessage5 + `';
|
|
// start watching for messages
|
|
var filter = shh.newMessageFilter({
|
|
privateKeyID: identity1,
|
|
sig: identity2,
|
|
topics: [topic],
|
|
});
|
|
|
|
// post message
|
|
var message = {
|
|
sig: identity2,
|
|
pubKey: identity1,
|
|
topic: topic,
|
|
payload: web3.toHex(payload),
|
|
ttl: 20,
|
|
powTime: 20,
|
|
powTarget: 0.01,
|
|
};
|
|
|
|
var sent = shh.post(message)
|
|
if (!sent) {
|
|
throw 'message not sent: ' + message;
|
|
}
|
|
`,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.T().Log(tc.name)
|
|
|
|
chatID := crypto.Keccak256Hash([]byte(tc.name)).Hex()
|
|
|
|
s.Jail.Parse(chatID, `
|
|
var shh = web3.shh;
|
|
// topic must be 4-byte long
|
|
var makeTopic = function () {
|
|
var topic = '0x';
|
|
for (var i = 0; i < 8; i++) {
|
|
topic += Math.floor(Math.random() * 16).toString(16);
|
|
}
|
|
return topic;
|
|
};
|
|
`)
|
|
|
|
cell, err := s.Jail.Cell(chatID)
|
|
s.NoError(err, "cannot get VM")
|
|
|
|
// Setup filters and post messages.
|
|
_, err = cell.Run(tc.code)
|
|
s.NoError(err)
|
|
|
|
if !tc.useFilter {
|
|
continue
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
timedOut := make(chan struct{})
|
|
go func() {
|
|
select {
|
|
case <-done:
|
|
case <-time.After(s.Timeout):
|
|
close(timedOut)
|
|
}
|
|
}()
|
|
|
|
poll_loop:
|
|
for {
|
|
// Use polling because:
|
|
// (1) filterId is not assigned immediately,
|
|
// (2) messages propagate with some delay.
|
|
select {
|
|
case <-done:
|
|
break poll_loop
|
|
case <-timedOut:
|
|
s.FailNow("polling for messages timed out")
|
|
case <-time.After(time.Second):
|
|
}
|
|
|
|
filter, err := cell.Get("filter")
|
|
s.NoError(err, "cannot get filter")
|
|
filterID, err := filter.Object().Get("filterId")
|
|
s.NoError(err, "cannot get filterId")
|
|
|
|
// FilterID is not assigned yet.
|
|
if filterID.IsNull() {
|
|
continue
|
|
}
|
|
|
|
payload, err := cell.Get("payload")
|
|
s.NoError(err, "cannot get payload")
|
|
|
|
messages, err := s.WhisperAPI.GetFilterMessages(filterID.String())
|
|
s.NoError(err)
|
|
for _, m := range messages {
|
|
s.Equal(payload.String(), string(m.Payload))
|
|
close(done)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
func (s *WhisperJailTestSuite) TestEncryptedAnonymousMessage() {
|
|
s.StartTestBackend(params.RopstenNetworkID)
|
|
defer s.StopTestBackend()
|
|
|
|
accountKey2, accountKey2Hex, err := s.GetAccountKey(TestConfig.Account2)
|
|
s.NoError(err)
|
|
|
|
topicSlice := make([]byte, whisper.TopicLength)
|
|
_, err = rand.Read(topicSlice)
|
|
s.NoError(err)
|
|
|
|
topic := whisper.BytesToTopic(topicSlice)
|
|
|
|
filter, err := s.WhisperAPI.NewMessageFilter(whisper.Criteria{
|
|
PrivateKeyID: accountKey2Hex,
|
|
Topics: []whisper.TopicType{topic},
|
|
})
|
|
s.NoError(err)
|
|
|
|
ok, err := s.WhisperAPI.Post(context.Background(), whisper.NewMessage{
|
|
TTL: 20,
|
|
PowTarget: 0.01,
|
|
PowTime: 20,
|
|
Topic: topic,
|
|
PublicKey: crypto.FromECDSAPub(&accountKey2.PrivateKey.PublicKey),
|
|
Payload: []byte(whisperMessage4),
|
|
})
|
|
s.NoError(err)
|
|
s.True(ok)
|
|
|
|
done := make(chan struct{})
|
|
timedOut := make(chan struct{})
|
|
go func() {
|
|
select {
|
|
case <-done:
|
|
case <-time.After(s.Timeout):
|
|
close(timedOut)
|
|
}
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-done:
|
|
return
|
|
case <-timedOut:
|
|
s.FailNow("polling for messages timed out")
|
|
case <-time.After(time.Second):
|
|
}
|
|
|
|
messages, err := s.WhisperAPI.GetFilterMessages(filter)
|
|
s.NoError(err)
|
|
for _, m := range messages {
|
|
s.Equal(whisperMessage4, string(m.Payload))
|
|
close(done)
|
|
}
|
|
}
|
|
}
|