forked from mirror/go-ethereum
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
4.8 KiB
206 lines
4.8 KiB
package whisper
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
)
|
|
|
|
type testNode struct {
|
|
server *p2p.Server
|
|
client *Whisper
|
|
}
|
|
|
|
func startNodes(n int) ([]*testNode, error) {
|
|
// Start up the cluster of nodes
|
|
cluster := make([]*testNode, 0, n)
|
|
for i := 0; i < n; i++ {
|
|
shh := New()
|
|
|
|
// Generate the node identity
|
|
key, err := crypto.GenerateKey()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
name := common.MakeName(fmt.Sprintf("whisper-go-test-%d", i), "1.0")
|
|
|
|
// Create an Ethereum server to communicate through
|
|
server := &p2p.Server{
|
|
PrivateKey: key,
|
|
MaxPeers: 10,
|
|
Name: name,
|
|
Protocols: []p2p.Protocol{shh.Protocol()},
|
|
ListenAddr: fmt.Sprintf(":%d", 30300+i),
|
|
NAT: nat.Any(),
|
|
}
|
|
if err := server.Start(); err != nil {
|
|
return nil, err
|
|
}
|
|
// Peer online, store and iterate
|
|
cluster = append(cluster, &testNode{
|
|
server: server,
|
|
client: shh,
|
|
})
|
|
}
|
|
// Manually wire together the cluster nodes
|
|
root := cluster[0].server.Self()
|
|
for _, node := range cluster[1:] {
|
|
node.server.SuggestPeer(root)
|
|
}
|
|
return cluster, nil
|
|
}
|
|
|
|
func stopNodes(cluster []*testNode) {
|
|
for _, node := range cluster {
|
|
node.server.Stop()
|
|
}
|
|
}
|
|
|
|
func TestSelfMessage(t *testing.T) {
|
|
// Start the single node cluster
|
|
cluster, err := startNodes(1)
|
|
if err != nil {
|
|
t.Fatalf("failed to boot test cluster: %v", err)
|
|
}
|
|
defer stopNodes(cluster)
|
|
|
|
client := cluster[0].client
|
|
|
|
// Start watching for self messages, signal any arrivals
|
|
self := client.NewIdentity()
|
|
done := make(chan struct{})
|
|
|
|
client.Watch(Filter{
|
|
To: &self.PublicKey,
|
|
Fn: func(msg *Message) {
|
|
close(done)
|
|
},
|
|
})
|
|
// Send a dummy message to oneself
|
|
msg := NewMessage([]byte("self whisper"))
|
|
envelope, err := msg.Wrap(DefaultProofOfWork, Options{
|
|
From: self,
|
|
To: &self.PublicKey,
|
|
TTL: DefaultTimeToLive,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to wrap message: %v", err)
|
|
}
|
|
// Dump the message into the system and wait for it to pop back out
|
|
if err := client.Send(envelope); err != nil {
|
|
t.Fatalf("failed to send self-message: %v", err)
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
t.Fatalf("self-message receive timeout")
|
|
}
|
|
}
|
|
|
|
func TestDirectMessage(t *testing.T) {
|
|
// Start the sender-recipient cluster
|
|
cluster, err := startNodes(2)
|
|
if err != nil {
|
|
t.Fatalf("failed to boot test cluster: %v", err)
|
|
}
|
|
defer stopNodes(cluster)
|
|
|
|
sender := cluster[0].client
|
|
senderId := sender.NewIdentity()
|
|
|
|
recipient := cluster[1].client
|
|
recipientId := recipient.NewIdentity()
|
|
|
|
// Watch for arriving messages on the recipient
|
|
done := make(chan struct{})
|
|
recipient.Watch(Filter{
|
|
To: &recipientId.PublicKey,
|
|
Fn: func(msg *Message) {
|
|
close(done)
|
|
},
|
|
})
|
|
// Send a dummy message from the sender
|
|
msg := NewMessage([]byte("direct whisper"))
|
|
envelope, err := msg.Wrap(DefaultProofOfWork, Options{
|
|
From: senderId,
|
|
To: &recipientId.PublicKey,
|
|
TTL: DefaultTimeToLive,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to wrap message: %v", err)
|
|
}
|
|
if err := sender.Send(envelope); err != nil {
|
|
t.Fatalf("failed to send direct message: %v", err)
|
|
}
|
|
// Wait for an arrival or a timeout
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
t.Fatalf("direct message receive timeout")
|
|
}
|
|
}
|
|
|
|
func TestAnonymousBroadcast(t *testing.T) {
|
|
testBroadcast(true, t)
|
|
}
|
|
|
|
func TestIdentifiedBroadcast(t *testing.T) {
|
|
testBroadcast(false, t)
|
|
}
|
|
|
|
func testBroadcast(anonymous bool, t *testing.T) {
|
|
// Start the single sender multi recipient cluster
|
|
cluster, err := startNodes(3)
|
|
if err != nil {
|
|
t.Fatalf("failed to boot test cluster: %v", err)
|
|
}
|
|
defer stopNodes(cluster)
|
|
|
|
sender := cluster[0].client
|
|
targets := make([]*Whisper, len(cluster)-1)
|
|
for i, node := range cluster[1:] {
|
|
targets[i] = node.client
|
|
if !anonymous {
|
|
targets[i].NewIdentity()
|
|
}
|
|
}
|
|
// Watch for arriving messages on the recipients
|
|
dones := make([]chan struct{}, len(targets))
|
|
for i := 0; i < len(targets); i++ {
|
|
done := make(chan struct{}) // need for the closure
|
|
dones[i] = done
|
|
|
|
targets[i].Watch(Filter{
|
|
Topics: NewTopicsFromStrings("broadcast topic"),
|
|
Fn: func(msg *Message) {
|
|
close(done)
|
|
},
|
|
})
|
|
}
|
|
// Send a dummy message from the sender
|
|
msg := NewMessage([]byte("broadcast whisper"))
|
|
envelope, err := msg.Wrap(DefaultProofOfWork, Options{
|
|
Topics: NewTopicsFromStrings("broadcast topic"),
|
|
TTL: DefaultTimeToLive,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to wrap message: %v", err)
|
|
}
|
|
if err := sender.Send(envelope); err != nil {
|
|
t.Fatalf("failed to send broadcast message: %v", err)
|
|
}
|
|
// Wait for an arrival on each recipient, or timeouts
|
|
timeout := time.After(time.Second)
|
|
for _, done := range dones {
|
|
select {
|
|
case <-done:
|
|
case <-timeout:
|
|
t.Fatalf("broadcast message receive timeout")
|
|
}
|
|
}
|
|
}
|
|
|