status-go/waku/waku_test.go

1152 lines
29 KiB
Go

// Copyright 2019 The Waku Library Authors.
//
// The Waku library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Waku library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty off
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Waku library. If not, see <http://www.gnu.org/licenses/>.
//
// This software uses the go-ethereum library, which is licensed
// under the GNU Lesser General Public Library, version 3 or any later.
package waku
import (
"bytes"
"crypto/ecdsa"
"crypto/sha256"
mrand "math/rand"
"testing"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku/common"
v0 "github.com/status-im/status-go/waku/v0"
v1 "github.com/status-im/status-go/waku/v1"
)
var seed int64
// InitSingleTest should be called in the beginning of every
// test, which uses RNG, in order to make the tests
// reproducibility independent of their sequence.
func InitSingleTest() {
seed = time.Now().Unix()
mrand.Seed(seed)
}
func TestBasic(t *testing.T) {
w := New(nil, nil)
p := w.Protocols()
waku0 := p[0]
waku1 := p[1]
if waku0.Name != v0.Name {
t.Fatalf("failed Peer Name: %v.", waku0.Name)
}
if uint64(waku0.Version) != v0.Version {
t.Fatalf("failed Peer Version: %v.", waku0.Version)
}
if waku0.Length != v0.NumberOfMessageCodes {
t.Fatalf("failed Peer Length: %v.", waku0.Length)
}
if waku0.Run == nil {
t.Fatalf("failed waku.Run.")
}
if waku1.Name != v1.Name {
t.Fatalf("failed Peer Name: %v.", waku1.Name)
}
if uint64(waku1.Version) != v1.Version {
t.Fatalf("failed Peer Version: %v.", waku1.Version)
}
if waku1.Length != v1.NumberOfMessageCodes {
t.Fatalf("failed Peer Length: %v.", waku1.Length)
}
if waku1.Run == nil {
t.Fatalf("failed waku.Run.")
}
if w.GetFilter("non-existent") != nil {
t.Fatalf("failed GetFilter.")
}
peerID := make([]byte, 64)
mrand.Read(peerID) // nolint: gosec
peer, _ := w.getPeer(peerID)
if peer != nil {
t.Fatal("found peer for random key.")
}
if err := w.AllowP2PMessagesFromPeer(peerID); err == nil {
t.Fatalf("failed MarkPeerTrusted.")
}
exist := w.HasSymKey("non-existing")
if exist {
t.Fatalf("failed HasSymKey.")
}
key, err := w.GetSymKey("non-existing")
if err == nil {
t.Fatalf("failed GetSymKey(non-existing): false positive.")
}
if key != nil {
t.Fatalf("failed GetSymKey: false positive.")
}
mail := w.Envelopes()
if len(mail) != 0 {
t.Fatalf("failed w.Envelopes().")
}
derived := pbkdf2.Key(peerID, nil, 65356, common.AESKeyLength, sha256.New)
if !common.ValidateDataIntegrity(derived, common.AESKeyLength) {
t.Fatalf("failed validateSymmetricKey with param = %v.", derived)
}
if common.ContainsOnlyZeros(derived) {
t.Fatalf("failed containsOnlyZeros with param = %v.", derived)
}
buf := []byte{0xFF, 0xE5, 0x80, 0x2, 0}
le := common.BytesToUintLittleEndian(buf)
be := common.BytesToUintBigEndian(buf)
if le != uint64(0x280e5ff) {
t.Fatalf("failed bytesToIntLittleEndian: %d.", le)
}
if be != uint64(0xffe5800200) {
t.Fatalf("failed BytesToIntBigEndian: %d.", be)
}
id, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
}
pk, err := w.GetPrivateKey(id)
if err != nil {
t.Fatalf("failed to retrieve new key pair: %s.", err)
}
if !validatePrivateKey(pk) {
t.Fatalf("failed validatePrivateKey: %v.", pk)
}
if !common.ValidatePublicKey(&pk.PublicKey) {
t.Fatalf("failed ValidatePublicKey: %v.", pk)
}
}
func TestAsymmetricKeyImport(t *testing.T) {
var (
w = New(nil, nil)
privateKeys []*ecdsa.PrivateKey
)
for i := 0; i < 50; i++ {
id, err := w.NewKeyPair()
if err != nil {
t.Fatalf("could not generate key: %v", err)
}
pk, err := w.GetPrivateKey(id)
if err != nil {
t.Fatalf("could not export private key: %v", err)
}
privateKeys = append(privateKeys, pk)
if !w.DeleteKeyPair(id) {
t.Fatalf("could not delete private key")
}
}
for _, pk := range privateKeys {
if _, err := w.AddKeyPair(pk); err != nil {
t.Fatalf("could not import private key: %v", err)
}
}
}
func TestWakuIdentityManagement(t *testing.T) {
w := New(nil, nil)
id1, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
}
id2, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
}
pk1, err := w.GetPrivateKey(id1)
if err != nil {
t.Fatalf("failed to retrieve the key pair: %s.", err)
}
pk2, err := w.GetPrivateKey(id2)
if err != nil {
t.Fatalf("failed to retrieve the key pair: %s.", err)
}
if !w.HasKeyPair(id1) {
t.Fatalf("failed HasIdentity(pk1).")
}
if !w.HasKeyPair(id2) {
t.Fatalf("failed HasIdentity(pk2).")
}
if pk1 == nil {
t.Fatalf("failed GetIdentity(pk1).")
}
if pk2 == nil {
t.Fatalf("failed GetIdentity(pk2).")
}
if !validatePrivateKey(pk1) {
t.Fatalf("pk1 is invalid.")
}
if !validatePrivateKey(pk2) {
t.Fatalf("pk2 is invalid.")
}
// Delete one identity
done := w.DeleteKeyPair(id1)
if !done {
t.Fatalf("failed to delete id1.")
}
pk1, err = w.GetPrivateKey(id1)
if err == nil {
t.Fatalf("retrieve the key pair: false positive.")
}
pk2, err = w.GetPrivateKey(id2)
if err != nil {
t.Fatalf("failed to retrieve the key pair: %s.", err)
}
if w.HasKeyPair(id1) {
t.Fatalf("failed DeleteIdentity(pub1): still exist.")
}
if !w.HasKeyPair(id2) {
t.Fatalf("failed DeleteIdentity(pub1): pub2 does not exist.")
}
if pk1 != nil {
t.Fatalf("failed DeleteIdentity(pub1): first key still exist.")
}
if pk2 == nil {
t.Fatalf("failed DeleteIdentity(pub1): second key does not exist.")
}
// Delete again non-existing identity
done = w.DeleteKeyPair(id1)
if done {
t.Fatalf("delete id1: false positive.")
}
pk1, err = w.GetPrivateKey(id1)
if err == nil {
t.Fatalf("retrieve the key pair: false positive.")
}
pk2, err = w.GetPrivateKey(id2)
if err != nil {
t.Fatalf("failed to retrieve the key pair: %s.", err)
}
if w.HasKeyPair(id1) {
t.Fatalf("failed delete non-existing identity: exist.")
}
if !w.HasKeyPair(id2) {
t.Fatalf("failed delete non-existing identity: pub2 does not exist.")
}
if pk1 != nil {
t.Fatalf("failed delete non-existing identity: first key exist.")
}
if pk2 == nil {
t.Fatalf("failed delete non-existing identity: second key does not exist.")
}
// Delete second identity
done = w.DeleteKeyPair(id2)
if !done {
t.Fatalf("failed to delete id2.")
}
pk1, err = w.GetPrivateKey(id1)
if err == nil {
t.Fatalf("retrieve the key pair: false positive.")
}
pk2, err = w.GetPrivateKey(id2)
if err == nil {
t.Fatalf("retrieve the key pair: false positive.")
}
if w.HasKeyPair(id1) {
t.Fatalf("failed delete second identity: first identity exist.")
}
if w.HasKeyPair(id2) {
t.Fatalf("failed delete second identity: still exist.")
}
if pk1 != nil {
t.Fatalf("failed delete second identity: first key exist.")
}
if pk2 != nil {
t.Fatalf("failed delete second identity: second key exist.")
}
}
func TestSymKeyManagement(t *testing.T) {
InitSingleTest()
var err error
var k1, k2 []byte
w := New(nil, nil)
id2 := "arbitrary-string-2"
id1, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
}
k1, err = w.GetSymKey(id1)
if err != nil {
t.Fatalf("failed GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed GetSymKey(id2): false positive.")
}
if !w.HasSymKey(id1) {
t.Fatalf("failed HasSymKey(id1).")
}
if w.HasSymKey(id2) {
t.Fatalf("failed HasSymKey(id2): false positive.")
}
if k1 == nil {
t.Fatalf("first key does not exist.")
}
if k2 != nil {
t.Fatalf("second key still exist.")
}
// add existing id, nothing should change
randomKey := make([]byte, common.AESKeyLength)
mrand.Read(randomKey) // nolint: gosec
id1, err = w.AddSymKeyDirect(randomKey)
if err != nil {
t.Fatalf("failed AddSymKey with seed %d: %s.", seed, err)
}
k1, err = w.GetSymKey(id1)
if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed w.GetSymKey(id2): false positive.")
}
if !w.HasSymKey(id1) {
t.Fatalf("failed w.HasSymKey(id1).")
}
if w.HasSymKey(id2) {
t.Fatalf("failed w.HasSymKey(id2): false positive.")
}
if k1 == nil {
t.Fatalf("first key does not exist.")
}
if !bytes.Equal(k1, randomKey) {
t.Fatalf("k1 != randomKey.")
}
if k2 != nil {
t.Fatalf("second key already exist.")
}
id2, err = w.AddSymKeyDirect(randomKey)
if err != nil {
t.Fatalf("failed AddSymKey(id2) with seed %d: %s.", seed, err)
}
k1, err = w.GetSymKey(id1)
if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if !w.HasSymKey(id1) {
t.Fatalf("HasSymKey(id1) failed.")
}
if !w.HasSymKey(id2) {
t.Fatalf("HasSymKey(id2) failed.")
}
if k1 == nil {
t.Fatalf("k1 does not exist.")
}
if k2 == nil {
t.Fatalf("k2 does not exist.")
}
if !bytes.Equal(k1, k2) {
t.Fatalf("k1 != k2.")
}
if !bytes.Equal(k1, randomKey) {
t.Fatalf("k1 != randomKey.")
}
if len(k1) != common.AESKeyLength {
t.Fatalf("wrong length of k1.")
}
if len(k2) != common.AESKeyLength {
t.Fatalf("wrong length of k2.")
}
w.DeleteSymKey(id1)
k1, err = w.GetSymKey(id1)
if err == nil {
t.Fatalf("failed w.GetSymKey(id1): false positive.")
}
if k1 != nil {
t.Fatalf("failed GetSymKey(id1): false positive.")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if w.HasSymKey(id1) {
t.Fatalf("failed to delete first key: still exist.")
}
if !w.HasSymKey(id2) {
t.Fatalf("failed to delete first key: second key does not exist.")
}
if k2 == nil {
t.Fatalf("failed to delete first key: second key is nil.")
}
w.DeleteSymKey(id1)
w.DeleteSymKey(id2)
k1, err = w.GetSymKey(id1)
if err == nil {
t.Fatalf("failed w.GetSymKey(id1): false positive.")
}
k2, err = w.GetSymKey(id2)
if err == nil {
t.Fatalf("failed w.GetSymKey(id2): false positive.")
}
if k1 != nil || k2 != nil {
t.Fatalf("k1 or k2 is not nil")
}
if w.HasSymKey(id1) {
t.Fatalf("failed to delete second key: first key exist.")
}
if w.HasSymKey(id2) {
t.Fatalf("failed to delete second key: still exist.")
}
randomKey = make([]byte, common.AESKeyLength+1)
mrand.Read(randomKey) // nolint: gosec
_, err = w.AddSymKeyDirect(randomKey)
if err == nil {
t.Fatalf("added the key with wrong size, seed %d.", seed)
}
const password = "arbitrary data here"
id1, err = w.AddSymKeyFromPassword(password)
if err != nil {
t.Fatalf("failed AddSymKeyFromPassword(id1) with seed %d: %s.", seed, err)
}
id2, err = w.AddSymKeyFromPassword(password)
if err != nil {
t.Fatalf("failed AddSymKeyFromPassword(id2) with seed %d: %s.", seed, err)
}
k1, err = w.GetSymKey(id1)
if err != nil {
t.Fatalf("failed w.GetSymKey(id1).")
}
k2, err = w.GetSymKey(id2)
if err != nil {
t.Fatalf("failed w.GetSymKey(id2).")
}
if !w.HasSymKey(id1) {
t.Fatalf("HasSymKey(id1) failed.")
}
if !w.HasSymKey(id2) {
t.Fatalf("HasSymKey(id2) failed.")
}
if !common.ValidateDataIntegrity(k2, common.AESKeyLength) {
t.Fatalf("key validation failed.")
}
if !bytes.Equal(k1, k2) {
t.Fatalf("k1 != k2.")
}
}
func TestExpiry(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
if err := w.SetMinimumPoW(0.0000001, false); err != nil {
t.Fatal("failed to set min pow")
}
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
if err := w.Start(); err != nil {
t.Fatal("failed to start waku")
}
defer func() { handleError(t, w.Stop()) }()
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
params.TTL = 1
messagesCount := 5
// Send a few messages one after another. Due to low PoW and expiration buckets
// with one second resolution, it covers a case when there are multiple items
// in a single expiration bucket.
for i := 0; i < messagesCount; i++ {
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err != nil {
t.Fatalf("failed to send envelope with seed %d: %s.", seed, err)
}
}
// wait till received or timeout
var received, expired bool
for j := 0; j < 20; j++ {
time.Sleep(100 * time.Millisecond)
if len(w.Envelopes()) == messagesCount {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// wait till expired or timeout
for j := 0; j < 20; j++ {
time.Sleep(100 * time.Millisecond)
if len(w.Envelopes()) == 0 {
expired = true
break
}
}
if !expired {
t.Fatalf("expire failed, seed: %d.", seed)
}
}
func TestCustomization(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
defer func() { handleError(t, w.SetMaxMessageSize(common.DefaultMaxMessageSize)) }()
if err := w.Start(); err != nil {
t.Fatal("failed to start node")
}
defer func() { handleError(t, w.Stop()) }()
const smallPoW = 0.00001
f, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
params.KeySym = f.KeySym
params.Topic = common.BytesToTopic(f.Topics[2])
params.PoW = smallPoW
params.TTL = 3600 * 24 // one day
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err == nil {
t.Fatalf("successfully sent envelope with PoW %.06f, false positive (seed %d).", env.PoW(), seed)
}
_ = w.SetMinimumPoW(smallPoW/2, true)
err = w.Send(env)
if err != nil {
t.Fatalf("failed to send envelope with seed %d: %s.", seed, err)
}
params.TTL++
msg, err = common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err = msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
_ = w.SetMaxMessageSize(uint32(env.Size() - 1))
err = w.Send(env)
if err == nil {
t.Fatalf("successfully sent oversized envelope (seed %d): false positive.", seed)
}
_ = w.SetMaxMessageSize(common.DefaultMaxMessageSize)
err = w.Send(env)
if err != nil {
t.Fatalf("failed to send second envelope with seed %d: %s.", seed, err)
}
// wait till received or timeout
var received bool
for j := 0; j < 20; j++ {
time.Sleep(100 * time.Millisecond)
if len(w.Envelopes()) > 1 {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// check w.messages()
_, err = w.Subscribe(f)
if err != nil {
t.Fatalf("failed subscribe with seed %d: %s.", seed, err)
}
time.Sleep(5 * time.Millisecond)
mail := f.Retrieve()
if len(mail) > 0 {
t.Fatalf("received premature mail")
}
}
func TestSymmetricSendCycle(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
defer func() { handleError(t, w.SetMaxMessageSize(common.DefaultMaxMessageSize)) }()
if err := w.Start(); err != nil {
t.Fatal("failed to start node")
}
defer func() { handleError(t, w.Stop()) }()
filter1, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter1.PoW = common.DefaultMinimumPoW
// Copy the first filter since some of its fields
// are randomly generated.
filter2 := &common.Filter{
KeySym: filter1.KeySym,
Topics: filter1.Topics,
PoW: filter1.PoW,
AllowP2P: filter1.AllowP2P,
Messages: common.NewMemoryMessageStore(),
}
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter1.Src = &params.Src.PublicKey
filter2.Src = &params.Src.PublicKey
params.KeySym = filter1.KeySym
params.Topic = common.BytesToTopic(filter1.Topics[2])
params.PoW = filter1.PoW
params.WorkTime = 10
params.TTL = 50
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter1)
if err != nil {
t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter2)
if err != nil {
t.Fatalf("failed subscribe 2 with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err != nil {
t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err)
}
// wait till received or timeout
var received bool
for j := 0; j < 200; j++ {
time.Sleep(10 * time.Millisecond)
if len(w.Envelopes()) > 0 {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// check w.messages()
time.Sleep(5 * time.Millisecond)
mail1 := filter1.Retrieve()
mail2 := filter2.Retrieve()
if len(mail2) == 0 {
t.Fatalf("did not receive any email for filter 2")
}
if len(mail1) == 0 {
t.Fatalf("did not receive any email for filter 1")
}
}
func TestSymmetricSendCycleWithTopicInterest(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
defer func() { handleError(t, w.SetMaxMessageSize(common.DefaultMaxMessageSize)) }()
if err := w.Start(); err != nil {
t.Fatal("could not start node")
}
defer func() { handleError(t, w.Stop()) }()
filter1, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter1.PoW = common.DefaultMinimumPoW
// Copy the first filter since some of its fields
// are randomly generated.
filter2 := &common.Filter{
KeySym: filter1.KeySym,
Topics: filter1.Topics,
PoW: filter1.PoW,
AllowP2P: filter1.AllowP2P,
Messages: common.NewMemoryMessageStore(),
}
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter1.Src = &params.Src.PublicKey
filter2.Src = &params.Src.PublicKey
params.KeySym = filter1.KeySym
params.Topic = common.BytesToTopic(filter1.Topics[2])
params.PoW = filter1.PoW
params.WorkTime = 10
params.TTL = 50
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter1)
if err != nil {
t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter2)
if err != nil {
t.Fatalf("failed subscribe 2 with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err != nil {
t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err)
}
// wait till received or timeout
var received bool
for j := 0; j < 200; j++ {
time.Sleep(10 * time.Millisecond)
if len(w.Envelopes()) > 0 {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// check w.messages()
time.Sleep(5 * time.Millisecond)
mail1 := filter1.Retrieve()
mail2 := filter2.Retrieve()
if len(mail2) == 0 {
t.Fatalf("did not receive any email for filter 2")
}
if len(mail1) == 0 {
t.Fatalf("did not receive any email for filter 1")
}
}
func TestSymmetricSendWithoutAKey(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
if err := w.Start(); err != nil {
t.Errorf("failed to start waku: '%s'", err)
}
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
defer func() { handleError(t, w.SetMaxMessageSize(common.DefaultMaxMessageSize)) }()
defer func() { handleError(t, w.Stop()) }()
filter, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter.PoW = common.DefaultMinimumPoW
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter.Src = nil
params.KeySym = filter.KeySym
params.Topic = common.BytesToTopic(filter.Topics[2])
params.PoW = filter.PoW
params.WorkTime = 10
params.TTL = 50
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter)
if err != nil {
t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err != nil {
t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err)
}
// wait till received or timeout
var received bool
for j := 0; j < 200; j++ {
time.Sleep(10 * time.Millisecond)
if len(w.Envelopes()) > 0 {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// check w.messages()
time.Sleep(5 * time.Millisecond)
mail := filter.Retrieve()
if len(mail) == 0 {
t.Fatalf("did not receive message in spite of not setting a public key")
}
}
func TestSymmetricSendKeyMismatch(t *testing.T) {
InitSingleTest()
w := New(nil, nil)
if err := w.Start(); err != nil {
t.Errorf("failed to start waku: '%s'", err)
}
defer func() { handleError(t, w.SetMinimumPoW(common.DefaultMinimumPoW, false)) }()
defer func() { handleError(t, w.SetMaxMessageSize(common.DefaultMaxMessageSize)) }()
defer func() { handleError(t, w.Stop()) }()
filter, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
filter.PoW = common.DefaultMinimumPoW
params, err := generateMessageParams()
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
params.KeySym = filter.KeySym
params.Topic = common.BytesToTopic(filter.Topics[2])
params.PoW = filter.PoW
params.WorkTime = 10
params.TTL = 50
msg, err := common.NewSentMessage(params)
if err != nil {
t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
}
env, err := msg.Wrap(params, time.Now())
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter)
if err != nil {
t.Fatalf("failed subscribe 1 with seed %d: %s.", seed, err)
}
err = w.Send(env)
if err != nil {
t.Fatalf("Failed sending envelope with PoW %.06f (seed %d): %s", env.PoW(), seed, err)
}
// wait till received or timeout
var received bool
for j := 0; j < 200; j++ {
time.Sleep(10 * time.Millisecond)
if len(w.Envelopes()) > 0 {
received = true
break
}
}
if !received {
t.Fatalf("did not receive the sent envelope, seed: %d.", seed)
}
// check w.messages()
time.Sleep(5 * time.Millisecond)
mail := filter.Retrieve()
if len(mail) > 0 {
t.Fatalf("received a message when keys weren't matching")
}
}
func TestFullNode(t *testing.T) {
config := &Config{FullNode: true}
w := New(config, nil)
require.True(t, w.FullNode(), "full node should be true")
require.True(t, common.IsFullNode(w.BloomFilter()), "bloom filter should be full")
require.True(t, common.IsFullNode(w.BloomFilterTolerance()), "bloom filter tolerance should be full")
require.Nil(t, w.TopicInterest(), "topic interest should be nil")
// Set a topic
require.NoError(t, w.SetTopicInterest([]common.TopicType{common.BytesToTopic([]byte("a"))}))
// Make sure everything is the same
require.True(t, w.FullNode(), "full node should be true")
require.True(t, common.IsFullNode(w.BloomFilter()), "bloom filter should be full")
require.True(t, common.IsFullNode(w.BloomFilterTolerance()), "bloom filter tolerance should be full")
require.Nil(t, w.TopicInterest(), "topic interest should be nil")
// unset full node
w.SetFullNode(false)
require.False(t, w.FullNode(), "full node should be false")
require.NotNil(t, w.TopicInterest(), "topic interest should not be nil")
}
func TestBloom(t *testing.T) {
topic := common.TopicType{0, 0, 255, 6}
b := topic.ToBloom()
x := make([]byte, common.BloomFilterSize)
x[0] = byte(1)
x[32] = byte(1)
x[common.BloomFilterSize-1] = byte(128)
if !common.BloomFilterMatch(x, b) || !common.BloomFilterMatch(b, x) {
t.Fatalf("bloom filter does not match the mask")
}
_, err := mrand.Read(b) // nolint: gosec
if err != nil {
t.Fatalf("math rand error")
}
_, err = mrand.Read(x) // nolint: gosec
if err != nil {
t.Fatalf("math rand error")
}
if !common.BloomFilterMatch(b, b) {
t.Fatalf("bloom filter does not match self")
}
x = addBloom(x, b)
if !common.BloomFilterMatch(x, b) {
t.Fatalf("bloom filter does not match combined bloom")
}
if !common.IsFullNode(nil) {
t.Fatalf("common.IsFullNode did not recognize nil as full node")
}
x[17] = 254
if common.IsFullNode(x) {
t.Fatalf("common.IsFullNode false positive")
}
for i := 0; i < common.BloomFilterSize; i++ {
b[i] = byte(255)
}
if !common.IsFullNode(b) {
t.Fatalf("common.IsFullNode false negative")
}
if common.BloomFilterMatch(x, b) {
t.Fatalf("bloomFilterMatch false positive")
}
if !common.BloomFilterMatch(b, x) {
t.Fatalf("bloomFilterMatch false negative")
}
w := New(nil, nil)
f := w.BloomFilter()
if f != nil {
t.Fatalf("wrong bloom on creation")
}
err = w.SetBloomFilter(x)
if err != nil {
t.Fatalf("failed to set bloom filter: %s", err)
}
f = w.BloomFilter()
if !common.BloomFilterMatch(f, x) || !common.BloomFilterMatch(x, f) {
t.Fatalf("retireved wrong bloom filter")
}
}
func TestTopicInterest(t *testing.T) {
w := New(nil, nil)
topicInterest := w.TopicInterest()
if topicInterest != nil {
t.Fatalf("wrong topic on creation")
}
filter1, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter1)
if err != nil {
t.Fatalf("failed subscribe with seed %d: %s.", seed, err)
}
topicInterest = w.TopicInterest()
if len(topicInterest) != len(filter1.Topics) {
t.Fatalf("wrong number of topics created")
}
filter2, err := generateFilter(t, true)
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
_, err = w.Subscribe(filter2)
if err != nil {
t.Fatalf("failed subscribe with seed %d: %s.", seed, err)
}
topicInterest = w.TopicInterest()
if len(topicInterest) != len(filter1.Topics)+len(filter2.Topics) {
t.Fatalf("wrong number of topics created")
}
}
func TestOnNewEnvelopesSoftBlacklist(t *testing.T) {
w1 := New(nil, nil)
envelope := &common.Envelope{}
stats := &common.StatsTracker{}
p2pPeer := p2p.NewPeer(enode.ID{0x4}, "test", []p2p.Cap{})
peer := v1.NewPeer(w1, p2pPeer, nil, nil, stats)
// Pre-condition, we need to make sure this envelope returns an EnvelopeError
envelopeError, err := w1.OnNewEnvelopes([]*common.Envelope{envelope}, peer)
require.NoError(t, err)
// Make sure this envelope returns an error
require.NotNil(t, envelopeError)
// build black listed waku
cfg := &Config{
SoftBlacklistedPeerIDs: []string{types.EncodeHex(peer.ID())},
}
w2 := New(cfg, nil)
envelopeError, err = w2.OnNewEnvelopes([]*common.Envelope{envelope}, peer)
require.NoError(t, err)
// Since it's blacklisted, it will just drop envelopes, keep the connection open
require.Nil(t, envelopeError)
}
func handleError(t *testing.T, err error) {
if err != nil {
t.Logf("deferred function error: '%s'", err)
}
}
func generateFilter(t *testing.T, symmetric bool) (*common.Filter, error) {
var f common.Filter
f.Messages = common.NewMemoryMessageStore()
const topicNum = 8
f.Topics = make([][]byte, topicNum)
for i := 0; i < topicNum; i++ {
f.Topics[i] = make([]byte, 4)
mrand.Read(f.Topics[i]) // nolint: gosec
f.Topics[i][0] = 0x01
}
key, err := crypto.GenerateKey()
if err != nil {
t.Fatalf("generateFilter 1 failed with seed %d.", seed)
return nil, err
}
f.Src = &key.PublicKey
if symmetric {
f.KeySym = make([]byte, common.AESKeyLength)
mrand.Read(f.KeySym) // nolint: gosec
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
} else {
f.KeyAsym, err = crypto.GenerateKey()
if err != nil {
t.Fatalf("generateFilter 2 failed with seed %d.", seed)
return nil, err
}
}
// AcceptP2P & PoW are not set
return &f, nil
}