aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/pss/pss_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/pss/pss_test.go')
-rw-r--r--swarm/pss/pss_test.go2092
1 files changed, 0 insertions, 2092 deletions
diff --git a/swarm/pss/pss_test.go b/swarm/pss/pss_test.go
deleted file mode 100644
index 9884ffbe9..000000000
--- a/swarm/pss/pss_test.go
+++ /dev/null
@@ -1,2092 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum 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 go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package pss
-
-import (
- "bytes"
- "context"
- "crypto/ecdsa"
- "encoding/binary"
- "encoding/hex"
- "encoding/json"
- "flag"
- "fmt"
- "io/ioutil"
- "math/rand"
- "os"
- "strconv"
- "strings"
- "sync"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/protocols"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/go-ethereum/swarm/network"
- "github.com/ethereum/go-ethereum/swarm/pot"
- "github.com/ethereum/go-ethereum/swarm/state"
- whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
-)
-
-var (
- initOnce = sync.Once{}
- loglevel = flag.Int("loglevel", 2, "logging verbosity")
- longrunning = flag.Bool("longrunning", false, "do run long-running tests")
- w *whisper.Whisper
- wapi *whisper.PublicWhisperAPI
- psslogmain log.Logger
- pssprotocols map[string]*protoCtrl
- useHandshake bool
- noopHandlerFunc = func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error {
- return nil
- }
-)
-
-func init() {
- flag.Parse()
- rand.Seed(time.Now().Unix())
-
- adapters.RegisterServices(newServices(false))
- initTest()
-}
-
-func initTest() {
- initOnce.Do(
- func() {
- psslogmain = log.New("psslog", "*")
- hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true))
- hf := log.LvlFilterHandler(log.Lvl(*loglevel), hs)
- h := log.CallerFileHandler(hf)
- log.Root().SetHandler(h)
-
- w = whisper.New(&whisper.DefaultConfig)
- wapi = whisper.NewPublicWhisperAPI(w)
-
- pssprotocols = make(map[string]*protoCtrl)
- },
- )
-}
-
-// test that topic conversion functions give predictable results
-func TestTopic(t *testing.T) {
-
- api := &API{}
-
- topicstr := strings.Join([]string{PingProtocol.Name, strconv.Itoa(int(PingProtocol.Version))}, ":")
-
- // bytestotopic is the authoritative topic conversion source
- topicobj := BytesToTopic([]byte(topicstr))
-
- // string to topic and bytes to topic must match
- topicapiobj, _ := api.StringToTopic(topicstr)
- if topicobj != topicapiobj {
- t.Fatalf("bytes and string topic conversion mismatch; %s != %s", topicobj, topicapiobj)
- }
-
- // string representation of topichex
- topichex := topicobj.String()
-
- // protocoltopic wrapper on pingtopic should be same as topicstring
- // check that it matches
- pingtopichex := PingTopic.String()
- if topichex != pingtopichex {
- t.Fatalf("protocol topic conversion mismatch; %s != %s", topichex, pingtopichex)
- }
-
- // json marshal of topic
- topicjsonout, err := topicobj.MarshalJSON()
- if err != nil {
- t.Fatal(err)
- }
- if string(topicjsonout)[1:len(topicjsonout)-1] != topichex {
- t.Fatalf("topic json marshal mismatch; %s != \"%s\"", topicjsonout, topichex)
- }
-
- // json unmarshal of topic
- var topicjsonin Topic
- topicjsonin.UnmarshalJSON(topicjsonout)
- if topicjsonin != topicobj {
- t.Fatalf("topic json unmarshal mismatch: %x != %x", topicjsonin, topicobj)
- }
-}
-
-// test bit packing of message control flags
-func TestMsgParams(t *testing.T) {
- var ctrl byte
- ctrl |= pssControlRaw
- p := newMsgParamsFromBytes([]byte{ctrl})
- m := newPssMsg(p)
- if !m.isRaw() || m.isSym() {
- t.Fatal("expected raw=true and sym=false")
- }
- ctrl |= pssControlSym
- p = newMsgParamsFromBytes([]byte{ctrl})
- m = newPssMsg(p)
- if !m.isRaw() || !m.isSym() {
- t.Fatal("expected raw=true and sym=true")
- }
- ctrl &= 0xff &^ pssControlRaw
- p = newMsgParamsFromBytes([]byte{ctrl})
- m = newPssMsg(p)
- if m.isRaw() || !m.isSym() {
- t.Fatal("expected raw=false and sym=true")
- }
-}
-
-// test if we can insert into cache, match items with cache and cache expiry
-func TestCache(t *testing.T) {
- var err error
- to, _ := hex.DecodeString("08090a0b0c0d0e0f1011121314150001020304050607161718191a1b1c1d1e1f")
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- privkey, err := w.GetPrivateKey(keys)
- if err != nil {
- t.Fatal(err)
- }
- ps := newTestPss(privkey, nil, nil)
- defer ps.Stop()
- pp := NewPssParams().WithPrivateKey(privkey)
- data := []byte("foo")
- datatwo := []byte("bar")
- datathree := []byte("baz")
- wparams := &whisper.MessageParams{
- TTL: defaultWhisperTTL,
- Src: privkey,
- Dst: &privkey.PublicKey,
- Topic: whisper.TopicType(PingTopic),
- WorkTime: defaultWhisperWorkTime,
- PoW: defaultWhisperPoW,
- Payload: data,
- }
- woutmsg, err := whisper.NewSentMessage(wparams)
- env, err := woutmsg.Wrap(wparams)
- msg := &PssMsg{
- Payload: env,
- To: to,
- }
- wparams.Payload = datatwo
- woutmsg, err = whisper.NewSentMessage(wparams)
- envtwo, err := woutmsg.Wrap(wparams)
- msgtwo := &PssMsg{
- Payload: envtwo,
- To: to,
- }
- wparams.Payload = datathree
- woutmsg, err = whisper.NewSentMessage(wparams)
- envthree, err := woutmsg.Wrap(wparams)
- msgthree := &PssMsg{
- Payload: envthree,
- To: to,
- }
-
- digest := ps.digest(msg)
- if err != nil {
- t.Fatalf("could not store cache msgone: %v", err)
- }
- digesttwo := ps.digest(msgtwo)
- if err != nil {
- t.Fatalf("could not store cache msgtwo: %v", err)
- }
- digestthree := ps.digest(msgthree)
- if err != nil {
- t.Fatalf("could not store cache msgthree: %v", err)
- }
-
- if digest == digesttwo {
- t.Fatalf("different msgs return same hash: %d", digesttwo)
- }
-
- // check the cache
- err = ps.addFwdCache(msg)
- if err != nil {
- t.Fatalf("write to pss expire cache failed: %v", err)
- }
-
- if !ps.checkFwdCache(msg) {
- t.Fatalf("message %v should have EXPIRE record in cache but checkCache returned false", msg)
- }
-
- if ps.checkFwdCache(msgtwo) {
- t.Fatalf("message %v should NOT have EXPIRE record in cache but checkCache returned true", msgtwo)
- }
-
- time.Sleep(pp.CacheTTL + 1*time.Second)
- err = ps.addFwdCache(msgthree)
- if err != nil {
- t.Fatalf("write to pss expire cache failed: %v", err)
- }
-
- if ps.checkFwdCache(msg) {
- t.Fatalf("message %v should have expired from cache but checkCache returned true", msg)
- }
-
- if _, ok := ps.fwdCache[digestthree]; !ok {
- t.Fatalf("unexpired message should be in the cache: %v", digestthree)
- }
-
- if _, ok := ps.fwdCache[digesttwo]; ok {
- t.Fatalf("expired message should have been cleared from the cache: %v", digesttwo)
- }
-}
-
-// matching of address hints; whether a message could be or is for the node
-func TestAddressMatch(t *testing.T) {
-
- localaddr := network.RandomAddr().Over()
- copy(localaddr[:8], []byte("deadbeef"))
- remoteaddr := []byte("feedbeef")
- kadparams := network.NewKadParams()
- kad := network.NewKademlia(localaddr, kadparams)
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- if err != nil {
- t.Fatalf("Could not generate private key: %v", err)
- }
- privkey, err := w.GetPrivateKey(keys)
- pssp := NewPssParams().WithPrivateKey(privkey)
- ps, err := NewPss(kad, pssp)
- if err != nil {
- t.Fatal(err.Error())
- }
-
- pssmsg := &PssMsg{
- To: remoteaddr,
- }
-
- // differ from first byte
- if ps.isSelfRecipient(pssmsg) {
- t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr)
- }
- if ps.isSelfPossibleRecipient(pssmsg, false) {
- t.Fatalf("isSelfPossibleRecipient true but %x != %x", remoteaddr[:8], localaddr[:8])
- }
-
- // 8 first bytes same
- copy(remoteaddr[:4], localaddr[:4])
- if ps.isSelfRecipient(pssmsg) {
- t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr)
- }
- if !ps.isSelfPossibleRecipient(pssmsg, false) {
- t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8])
- }
-
- // all bytes same
- pssmsg.To = localaddr
- if !ps.isSelfRecipient(pssmsg) {
- t.Fatalf("isSelfRecipient false but %x == %x", remoteaddr, localaddr)
- }
- if !ps.isSelfPossibleRecipient(pssmsg, false) {
- t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8])
- }
-
-}
-
-// test that message is handled by sender if a prox handler exists and sender is in prox of message
-func TestProxShortCircuit(t *testing.T) {
-
- // sender node address
- localAddr := network.RandomAddr().Over()
- localPotAddr := pot.NewAddressFromBytes(localAddr)
-
- // set up kademlia
- kadParams := network.NewKadParams()
- kad := network.NewKademlia(localAddr, kadParams)
- peerCount := kad.MinBinSize + 1
-
- // set up pss
- privKey, err := crypto.GenerateKey()
- pssp := NewPssParams().WithPrivateKey(privKey)
- ps, err := NewPss(kad, pssp)
- if err != nil {
- t.Fatal(err.Error())
- }
-
- // create kademlia peers, so we have peers both inside and outside minproxlimit
- var peers []*network.Peer
- proxMessageAddress := pot.RandomAddressAt(localPotAddr, peerCount).Bytes()
- distantMessageAddress := pot.RandomAddressAt(localPotAddr, 0).Bytes()
-
- for i := 0; i < peerCount; i++ {
- rw := &p2p.MsgPipeRW{}
- ptpPeer := p2p.NewPeer(enode.ID{}, "wanna be with me? [ ] yes [ ] no", []p2p.Cap{})
- protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{})
- peerAddr := pot.RandomAddressAt(localPotAddr, i)
- bzzPeer := &network.BzzPeer{
- Peer: protoPeer,
- BzzAddr: &network.BzzAddr{
- OAddr: peerAddr.Bytes(),
- UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])),
- },
- }
- peer := network.NewPeer(bzzPeer, kad)
- kad.On(peer)
- peers = append(peers, peer)
- }
-
- // register it marking prox capability
- delivered := make(chan struct{})
- rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error {
- log.Trace("in allowraw handler")
- delivered <- struct{}{}
- return nil
- }
- topic := BytesToTopic([]byte{0x2a})
- hndlrProxDereg := ps.Register(&topic, &handler{
- f: rawHandlerFunc,
- caps: &handlerCaps{
- raw: true,
- prox: true,
- },
- })
- defer hndlrProxDereg()
-
- // send message too far away for sender to be in prox
- // reception of this message should time out
- errC := make(chan error)
- go func() {
- err := ps.SendRaw(distantMessageAddress, topic, []byte("foo"))
- if err != nil {
- errC <- err
- }
- }()
-
- ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
- defer cancel()
- select {
- case <-delivered:
- t.Fatal("raw distant message delivered")
- case err := <-errC:
- t.Fatal(err)
- case <-ctx.Done():
- }
-
- // send message that should be within sender prox
- // this message should be delivered
- go func() {
- err := ps.SendRaw(proxMessageAddress, topic, []byte("bar"))
- if err != nil {
- errC <- err
- }
- }()
-
- ctx, cancel = context.WithTimeout(context.TODO(), time.Second)
- defer cancel()
- select {
- case <-delivered:
- case err := <-errC:
- t.Fatal(err)
- case <-ctx.Done():
- t.Fatal("raw timeout")
- }
-
- // try the same prox message with sym and asym send
- proxAddrPss := PssAddress(proxMessageAddress)
- symKeyId, err := ps.GenerateSymmetricKey(topic, proxAddrPss, true)
- go func() {
- err := ps.SendSym(symKeyId, topic, []byte("baz"))
- if err != nil {
- errC <- err
- }
- }()
- ctx, cancel = context.WithTimeout(context.TODO(), time.Second)
- defer cancel()
- select {
- case <-delivered:
- case err := <-errC:
- t.Fatal(err)
- case <-ctx.Done():
- t.Fatal("sym timeout")
- }
-
- err = ps.SetPeerPublicKey(&privKey.PublicKey, topic, proxAddrPss)
- if err != nil {
- t.Fatal(err)
- }
- pubKeyId := hexutil.Encode(crypto.FromECDSAPub(&privKey.PublicKey))
- go func() {
- err := ps.SendAsym(pubKeyId, topic, []byte("xyzzy"))
- if err != nil {
- errC <- err
- }
- }()
- ctx, cancel = context.WithTimeout(context.TODO(), time.Second)
- defer cancel()
- select {
- case <-delivered:
- case err := <-errC:
- t.Fatal(err)
- case <-ctx.Done():
- t.Fatal("asym timeout")
- }
-}
-
-// verify that node can be set as recipient regardless of explicit message address match if minimum one handler of a topic is explicitly set to allow it
-// note that in these tests we use the raw capability on handlers for convenience
-func TestAddressMatchProx(t *testing.T) {
-
- // recipient node address
- localAddr := network.RandomAddr().Over()
- localPotAddr := pot.NewAddressFromBytes(localAddr)
-
- // set up kademlia
- kadparams := network.NewKadParams()
- kad := network.NewKademlia(localAddr, kadparams)
- nnPeerCount := kad.MinBinSize
- peerCount := nnPeerCount + 2
-
- // set up pss
- privKey, err := crypto.GenerateKey()
- pssp := NewPssParams().WithPrivateKey(privKey)
- ps, err := NewPss(kad, pssp)
- if err != nil {
- t.Fatal(err.Error())
- }
-
- // create kademlia peers, so we have peers both inside and outside minproxlimit
- var peers []*network.Peer
- for i := 0; i < peerCount; i++ {
- rw := &p2p.MsgPipeRW{}
- ptpPeer := p2p.NewPeer(enode.ID{}, "362436 call me anytime", []p2p.Cap{})
- protoPeer := protocols.NewPeer(ptpPeer, rw, &protocols.Spec{})
- peerAddr := pot.RandomAddressAt(localPotAddr, i)
- bzzPeer := &network.BzzPeer{
- Peer: protoPeer,
- BzzAddr: &network.BzzAddr{
- OAddr: peerAddr.Bytes(),
- UAddr: []byte(fmt.Sprintf("%x", peerAddr[:])),
- },
- }
- peer := network.NewPeer(bzzPeer, kad)
- kad.On(peer)
- peers = append(peers, peer)
- }
-
- // TODO: create a test in the network package to make a table with n peers where n-m are proxpeers
- // meanwhile test regression for kademlia since we are compiling the test parameters from different packages
- var proxes int
- var conns int
- depth := kad.NeighbourhoodDepth()
- kad.EachConn(nil, peerCount, func(p *network.Peer, po int) bool {
- conns++
- if po >= depth {
- proxes++
- }
- return true
- })
- if proxes != nnPeerCount {
- t.Fatalf("expected %d proxpeers, have %d", nnPeerCount, proxes)
- } else if conns != peerCount {
- t.Fatalf("expected %d peers total, have %d", peerCount, proxes)
- }
-
- // remote address distances from localAddr to try and the expected outcomes if we use prox handler
- remoteDistances := []int{
- 255,
- nnPeerCount + 1,
- nnPeerCount,
- nnPeerCount - 1,
- 0,
- }
- expects := []bool{
- true,
- true,
- true,
- false,
- false,
- }
-
- // first the unit test on the method that calculates possible receipient using prox
- for i, distance := range remoteDistances {
- pssMsg := newPssMsg(&msgParams{})
- pssMsg.To = make([]byte, len(localAddr))
- copy(pssMsg.To, localAddr)
- var byteIdx = distance / 8
- pssMsg.To[byteIdx] ^= 1 << uint(7-(distance%8))
- log.Trace(fmt.Sprintf("addrmatch %v", bytes.Equal(pssMsg.To, localAddr)))
- if ps.isSelfPossibleRecipient(pssMsg, true) != expects[i] {
- t.Fatalf("expected distance %d to be %v", distance, expects[i])
- }
- }
-
- // we move up to higher level and test the actual message handler
- // for each distance check if we are possible recipient when prox variant is used is set
-
- // this handler will increment a counter for every message that gets passed to the handler
- var receives int
- rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error {
- log.Trace("in allowraw handler")
- receives++
- return nil
- }
-
- // register it marking prox capability
- topic := BytesToTopic([]byte{0x2a})
- hndlrProxDereg := ps.Register(&topic, &handler{
- f: rawHandlerFunc,
- caps: &handlerCaps{
- raw: true,
- prox: true,
- },
- })
-
- // test the distances
- var prevReceive int
- for i, distance := range remoteDistances {
- remotePotAddr := pot.RandomAddressAt(localPotAddr, distance)
- remoteAddr := remotePotAddr.Bytes()
-
- var data [32]byte
- rand.Read(data[:])
- pssMsg := newPssMsg(&msgParams{raw: true})
- pssMsg.To = remoteAddr
- pssMsg.Expire = uint32(time.Now().Unix() + 4200)
- pssMsg.Payload = &whisper.Envelope{
- Topic: whisper.TopicType(topic),
- Data: data[:],
- }
-
- log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr)
- ps.handlePssMsg(context.TODO(), pssMsg)
- if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) {
- t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i])
- }
- prevReceive = receives
- }
-
- // now add a non prox-capable handler and test
- ps.Register(&topic, &handler{
- f: rawHandlerFunc,
- caps: &handlerCaps{
- raw: true,
- },
- })
- receives = 0
- prevReceive = 0
- for i, distance := range remoteDistances {
- remotePotAddr := pot.RandomAddressAt(localPotAddr, distance)
- remoteAddr := remotePotAddr.Bytes()
-
- var data [32]byte
- rand.Read(data[:])
- pssMsg := newPssMsg(&msgParams{raw: true})
- pssMsg.To = remoteAddr
- pssMsg.Expire = uint32(time.Now().Unix() + 4200)
- pssMsg.Payload = &whisper.Envelope{
- Topic: whisper.TopicType(topic),
- Data: data[:],
- }
-
- log.Trace("withprox addrs", "local", localAddr, "remote", remoteAddr)
- ps.handlePssMsg(context.TODO(), pssMsg)
- if (!expects[i] && prevReceive != receives) || (expects[i] && prevReceive == receives) {
- t.Fatalf("expected distance %d recipient %v when prox is set for handler", distance, expects[i])
- }
- prevReceive = receives
- }
-
- // now deregister the prox capable handler, now none of the messages will be handled
- hndlrProxDereg()
- receives = 0
-
- for _, distance := range remoteDistances {
- remotePotAddr := pot.RandomAddressAt(localPotAddr, distance)
- remoteAddr := remotePotAddr.Bytes()
-
- pssMsg := newPssMsg(&msgParams{raw: true})
- pssMsg.To = remoteAddr
- pssMsg.Expire = uint32(time.Now().Unix() + 4200)
- pssMsg.Payload = &whisper.Envelope{
- Topic: whisper.TopicType(topic),
- Data: []byte(remotePotAddr.String()),
- }
-
- log.Trace("noprox addrs", "local", localAddr, "remote", remoteAddr)
- ps.handlePssMsg(context.TODO(), pssMsg)
- if receives != 0 {
- t.Fatalf("expected distance %d to not be recipient when prox is not set for handler", distance)
- }
-
- }
-}
-
-// verify that message queueing happens when it should, and that expired and corrupt messages are dropped
-func TestMessageProcessing(t *testing.T) {
-
- t.Skip("Disabled due to probable faulty logic for outbox expectations")
- // setup
- privkey, err := crypto.GenerateKey()
- if err != nil {
- t.Fatal(err.Error())
- }
-
- addr := make([]byte, 32)
- addr[0] = 0x01
- ps := newTestPss(privkey, network.NewKademlia(addr, network.NewKadParams()), NewPssParams())
- defer ps.Stop()
-
- // message should pass
- msg := newPssMsg(&msgParams{})
- msg.To = addr
- msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix())
- msg.Payload = &whisper.Envelope{
- Topic: [4]byte{},
- Data: []byte{0x66, 0x6f, 0x6f},
- }
- if err := ps.handlePssMsg(context.TODO(), msg); err != nil {
- t.Fatal(err.Error())
- }
- tmr := time.NewTimer(time.Millisecond * 100)
- var outmsg *PssMsg
- select {
- case outmsg = <-ps.outbox:
- case <-tmr.C:
- default:
- }
- if outmsg != nil {
- t.Fatalf("expected outbox empty after full address on msg, but had message %s", msg)
- }
-
- // message should pass and queue due to partial length
- msg.To = addr[0:1]
- msg.Payload.Data = []byte{0x78, 0x79, 0x80, 0x80, 0x79}
- if err := ps.handlePssMsg(context.TODO(), msg); err != nil {
- t.Fatal(err.Error())
- }
- tmr.Reset(time.Millisecond * 100)
- outmsg = nil
- select {
- case outmsg = <-ps.outbox:
- case <-tmr.C:
- }
- if outmsg == nil {
- t.Fatal("expected message in outbox on encrypt fail, but empty")
- }
- outmsg = nil
- select {
- case outmsg = <-ps.outbox:
- default:
- }
- if outmsg != nil {
- t.Fatalf("expected only one queued message but also had message %v", msg)
- }
-
- // full address mismatch should put message in queue
- msg.To[0] = 0xff
- if err := ps.handlePssMsg(context.TODO(), msg); err != nil {
- t.Fatal(err.Error())
- }
- tmr.Reset(time.Millisecond * 10)
- outmsg = nil
- select {
- case outmsg = <-ps.outbox:
- case <-tmr.C:
- }
- if outmsg == nil {
- t.Fatal("expected message in outbox on address mismatch, but empty")
- }
- outmsg = nil
- select {
- case outmsg = <-ps.outbox:
- default:
- }
- if outmsg != nil {
- t.Fatalf("expected only one queued message but also had message %v", msg)
- }
-
- // expired message should be dropped
- msg.Expire = uint32(time.Now().Add(-time.Second).Unix())
- if err := ps.handlePssMsg(context.TODO(), msg); err != nil {
- t.Fatal(err.Error())
- }
- tmr.Reset(time.Millisecond * 10)
- outmsg = nil
- select {
- case outmsg = <-ps.outbox:
- case <-tmr.C:
- default:
- }
- if outmsg != nil {
- t.Fatalf("expected empty queue but have message %v", msg)
- }
-
- // invalid message should return error
- fckedupmsg := &struct {
- pssMsg *PssMsg
- }{
- pssMsg: &PssMsg{},
- }
- if err := ps.handlePssMsg(context.TODO(), fckedupmsg); err == nil {
- t.Fatalf("expected error from processMsg but error nil")
- }
-
- // outbox full should return error
- msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix())
- for i := 0; i < defaultOutboxCapacity; i++ {
- ps.outbox <- msg
- }
- msg.Payload.Data = []byte{0x62, 0x61, 0x72}
- err = ps.handlePssMsg(context.TODO(), msg)
- if err == nil {
- t.Fatal("expected error when mailbox full, but was nil")
- }
-}
-
-// set and generate pubkeys and symkeys
-func TestKeys(t *testing.T) {
- // make our key and init pss with it
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- ourkeys, err := wapi.NewKeyPair(ctx)
- if err != nil {
- t.Fatalf("create 'our' key fail")
- }
- ctx, cancel2 := context.WithTimeout(context.Background(), time.Second)
- defer cancel2()
- theirkeys, err := wapi.NewKeyPair(ctx)
- if err != nil {
- t.Fatalf("create 'their' key fail")
- }
- ourprivkey, err := w.GetPrivateKey(ourkeys)
- if err != nil {
- t.Fatalf("failed to retrieve 'our' private key")
- }
- theirprivkey, err := w.GetPrivateKey(theirkeys)
- if err != nil {
- t.Fatalf("failed to retrieve 'their' private key")
- }
- ps := newTestPss(ourprivkey, nil, nil)
- defer ps.Stop()
-
- // set up peer with mock address, mapped to mocked publicaddress and with mocked symkey
- addr := make(PssAddress, 32)
- copy(addr, network.RandomAddr().Over())
- outkey := network.RandomAddr().Over()
- topicobj := BytesToTopic([]byte("foo:42"))
- ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, addr)
- outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, addr, false)
- if err != nil {
- t.Fatalf("failed to set 'our' outgoing symmetric key")
- }
-
- // make a symmetric key that we will send to peer for encrypting messages to us
- inkeyid, err := ps.GenerateSymmetricKey(topicobj, addr, true)
- if err != nil {
- t.Fatalf("failed to set 'our' incoming symmetric key")
- }
-
- // get the key back from whisper, check that it's still the same
- outkeyback, err := ps.w.GetSymKey(outkeyid)
- if err != nil {
- t.Fatalf(err.Error())
- }
- inkey, err := ps.w.GetSymKey(inkeyid)
- if err != nil {
- t.Fatalf(err.Error())
- }
- if !bytes.Equal(outkeyback, outkey) {
- t.Fatalf("passed outgoing symkey doesnt equal stored: %x / %x", outkey, outkeyback)
- }
-
- t.Logf("symout: %v", outkeyback)
- t.Logf("symin: %v", inkey)
-
- // check that the key is stored in the peerpool
- psp := ps.symKeyPool[inkeyid][topicobj]
- if !bytes.Equal(psp.address, addr) {
- t.Fatalf("inkey address does not match; %p != %p", psp.address, addr)
- }
-}
-
-// check that we can retrieve previously added public key entires per topic and peer
-func TestGetPublickeyEntries(t *testing.T) {
-
- privkey, err := crypto.GenerateKey()
- if err != nil {
- t.Fatal(err)
- }
- ps := newTestPss(privkey, nil, nil)
- defer ps.Stop()
-
- peeraddr := network.RandomAddr().Over()
- topicaddr := make(map[Topic]PssAddress)
- topicaddr[Topic{0x13}] = peeraddr
- topicaddr[Topic{0x2a}] = peeraddr[:16]
- topicaddr[Topic{0x02, 0x9a}] = []byte{}
-
- remoteprivkey, err := crypto.GenerateKey()
- if err != nil {
- t.Fatal(err)
- }
- remotepubkeybytes := crypto.FromECDSAPub(&remoteprivkey.PublicKey)
- remotepubkeyhex := common.ToHex(remotepubkeybytes)
-
- pssapi := NewAPI(ps)
-
- for to, a := range topicaddr {
- err = pssapi.SetPeerPublicKey(remotepubkeybytes, to, a)
- if err != nil {
- t.Fatal(err)
- }
- }
-
- intopic, err := pssapi.GetPeerTopics(remotepubkeyhex)
- if err != nil {
- t.Fatal(err)
- }
-
-OUTER:
- for _, tnew := range intopic {
- for torig, addr := range topicaddr {
- if bytes.Equal(torig[:], tnew[:]) {
- inaddr, err := pssapi.GetPeerAddress(remotepubkeyhex, torig)
- if err != nil {
- t.Fatal(err)
- }
- if !bytes.Equal(addr, inaddr) {
- t.Fatalf("Address mismatch for topic %x; got %x, expected %x", torig, inaddr, addr)
- }
- delete(topicaddr, torig)
- continue OUTER
- }
- }
- t.Fatalf("received topic %x did not match any existing topics", tnew)
- }
-
- if len(topicaddr) != 0 {
- t.Fatalf("%d topics were not matched", len(topicaddr))
- }
-}
-
-// forwarding should skip peers that do not have matching pss capabilities
-func TestPeerCapabilityMismatch(t *testing.T) {
-
- // create privkey for forwarder node
- privkey, err := crypto.GenerateKey()
- if err != nil {
- t.Fatal(err)
- }
-
- // initialize kad
- baseaddr := network.RandomAddr()
- kad := network.NewKademlia((baseaddr).Over(), network.NewKadParams())
- rw := &p2p.MsgPipeRW{}
-
- // one peer has a mismatching version of pss
- wrongpssaddr := network.RandomAddr()
- wrongpsscap := p2p.Cap{
- Name: pssProtocolName,
- Version: 0,
- }
- nid := enode.ID{0x01}
- wrongpsspeer := network.NewPeer(&network.BzzPeer{
- Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(wrongpssaddr.Over()), []p2p.Cap{wrongpsscap}), rw, nil),
- BzzAddr: &network.BzzAddr{OAddr: wrongpssaddr.Over(), UAddr: nil},
- }, kad)
-
- // one peer doesn't even have pss (boo!)
- nopssaddr := network.RandomAddr()
- nopsscap := p2p.Cap{
- Name: "nopss",
- Version: 1,
- }
- nid = enode.ID{0x02}
- nopsspeer := network.NewPeer(&network.BzzPeer{
- Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(nopssaddr.Over()), []p2p.Cap{nopsscap}), rw, nil),
- BzzAddr: &network.BzzAddr{OAddr: nopssaddr.Over(), UAddr: nil},
- }, kad)
-
- // add peers to kademlia and activate them
- // it's safe so don't check errors
- kad.Register(wrongpsspeer.BzzAddr)
- kad.On(wrongpsspeer)
- kad.Register(nopsspeer.BzzAddr)
- kad.On(nopsspeer)
-
- // create pss
- pssmsg := &PssMsg{
- To: []byte{},
- Expire: uint32(time.Now().Add(time.Second).Unix()),
- Payload: &whisper.Envelope{},
- }
- ps := newTestPss(privkey, kad, nil)
- defer ps.Stop()
-
- // run the forward
- // it is enough that it completes; trying to send to incapable peers would create segfault
- ps.forward(pssmsg)
-
-}
-
-// verifies that message handlers for raw messages only are invoked when minimum one handler for the topic exists in which raw messages are explicitly allowed
-func TestRawAllow(t *testing.T) {
-
- // set up pss like so many times before
- privKey, err := crypto.GenerateKey()
- if err != nil {
- t.Fatal(err)
- }
- baseAddr := network.RandomAddr()
- kad := network.NewKademlia((baseAddr).Over(), network.NewKadParams())
- ps := newTestPss(privKey, kad, nil)
- defer ps.Stop()
- topic := BytesToTopic([]byte{0x2a})
-
- // create handler innards that increments every time a message hits it
- var receives int
- rawHandlerFunc := func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error {
- log.Trace("in allowraw handler")
- receives++
- return nil
- }
-
- // wrap this handler function with a handler without raw capability and register it
- hndlrNoRaw := &handler{
- f: rawHandlerFunc,
- }
- ps.Register(&topic, hndlrNoRaw)
-
- // test it with a raw message, should be poo-poo
- pssMsg := newPssMsg(&msgParams{
- raw: true,
- })
- pssMsg.To = baseAddr.OAddr
- pssMsg.Expire = uint32(time.Now().Unix() + 4200)
- pssMsg.Payload = &whisper.Envelope{
- Topic: whisper.TopicType(topic),
- }
- ps.handlePssMsg(context.TODO(), pssMsg)
- if receives > 0 {
- t.Fatalf("Expected handler not to be executed with raw cap off")
- }
-
- // now wrap the same handler function with raw capabilities and register it
- hndlrRaw := &handler{
- f: rawHandlerFunc,
- caps: &handlerCaps{
- raw: true,
- },
- }
- deregRawHandler := ps.Register(&topic, hndlrRaw)
-
- // should work now
- pssMsg.Payload.Data = []byte("Raw Deal")
- ps.handlePssMsg(context.TODO(), pssMsg)
- if receives == 0 {
- t.Fatalf("Expected handler to be executed with raw cap on")
- }
-
- // now deregister the raw capable handler
- prevReceives := receives
- deregRawHandler()
-
- // check that raw messages fail again
- pssMsg.Payload.Data = []byte("Raw Trump")
- ps.handlePssMsg(context.TODO(), pssMsg)
- if receives != prevReceives {
- t.Fatalf("Expected handler not to be executed when raw handler is retracted")
- }
-}
-
-// BELOW HERE ARE TESTS USING THE SIMULATION FRAMEWORK
-
-// tests that the API layer can handle edge case values
-func TestApi(t *testing.T) {
- clients, err := setupNetwork(2, true)
- if err != nil {
- t.Fatal(err)
- }
-
- topic := "0xdeadbeef"
-
- err = clients[0].Call(nil, "pss_sendRaw", "0x", topic, "0x666f6f")
- if err != nil {
- t.Fatal(err)
- }
-
- err = clients[0].Call(nil, "pss_sendRaw", "0xabcdef", topic, "0x")
- if err == nil {
- t.Fatal("expected error on empty msg")
- }
-
- overflowAddr := [33]byte{}
- err = clients[0].Call(nil, "pss_sendRaw", hexutil.Encode(overflowAddr[:]), topic, "0x666f6f")
- if err == nil {
- t.Fatal("expected error on send too big address")
- }
-}
-
-// verifies that nodes can send and receive raw (verbatim) messages
-func TestSendRaw(t *testing.T) {
- t.Run("32", testSendRaw)
- t.Run("8", testSendRaw)
- t.Run("0", testSendRaw)
-}
-
-func testSendRaw(t *testing.T) {
-
- var addrsize int64
- var err error
-
- paramstring := strings.Split(t.Name(), "/")
-
- addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0)
- log.Info("raw send test", "addrsize", addrsize)
-
- clients, err := setupNetwork(2, true)
- if err != nil {
- t.Fatal(err)
- }
-
- topic := "0xdeadbeef"
-
- var loaddrhex string
- err = clients[0].Call(&loaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 1 baseaddr fail: %v", err)
- }
- loaddrhex = loaddrhex[:2+(addrsize*2)]
- var roaddrhex string
- err = clients[1].Call(&roaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 2 baseaddr fail: %v", err)
- }
- roaddrhex = roaddrhex[:2+(addrsize*2)]
-
- time.Sleep(time.Millisecond * 500)
-
- // at this point we've verified that symkeys are saved and match on each peer
- // now try sending symmetrically encrypted message, both directions
- lmsgC := make(chan APIMsg)
- lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer lcancel()
- lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, true, false)
- log.Trace("lsub", "id", lsub)
- defer lsub.Unsubscribe()
- rmsgC := make(chan APIMsg)
- rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer rcancel()
- rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, true, false)
- log.Trace("rsub", "id", rsub)
- defer rsub.Unsubscribe()
-
- // send and verify delivery
- lmsg := []byte("plugh")
- err = clients[1].Call(nil, "pss_sendRaw", loaddrhex, topic, hexutil.Encode(lmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-lmsgC:
- if !bytes.Equal(recvmsg.Msg, lmsg) {
- t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg)
- }
- case cerr := <-lctx.Done():
- t.Fatalf("test message (left) timed out: %v", cerr)
- }
- rmsg := []byte("xyzzy")
- err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, hexutil.Encode(rmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-rmsgC:
- if !bytes.Equal(recvmsg.Msg, rmsg) {
- t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg)
- }
- case cerr := <-rctx.Done():
- t.Fatalf("test message (right) timed out: %v", cerr)
- }
-}
-
-// send symmetrically encrypted message between two directly connected peers
-func TestSendSym(t *testing.T) {
- t.Run("32", testSendSym)
- t.Run("8", testSendSym)
- t.Run("0", testSendSym)
-}
-
-func testSendSym(t *testing.T) {
-
- // address hint size
- var addrsize int64
- var err error
- paramstring := strings.Split(t.Name(), "/")
- addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0)
- log.Info("sym send test", "addrsize", addrsize)
-
- clients, err := setupNetwork(2, false)
- if err != nil {
- t.Fatal(err)
- }
-
- var topic string
- err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42")
- if err != nil {
- t.Fatal(err)
- }
-
- var loaddrhex string
- err = clients[0].Call(&loaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 1 baseaddr fail: %v", err)
- }
- loaddrhex = loaddrhex[:2+(addrsize*2)]
- var roaddrhex string
- err = clients[1].Call(&roaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 2 baseaddr fail: %v", err)
- }
- roaddrhex = roaddrhex[:2+(addrsize*2)]
-
- // retrieve public key from pss instance
- // set this public key reciprocally
- var lpubkeyhex string
- err = clients[0].Call(&lpubkeyhex, "pss_getPublicKey")
- if err != nil {
- t.Fatalf("rpc get node 1 pubkey fail: %v", err)
- }
- var rpubkeyhex string
- err = clients[1].Call(&rpubkeyhex, "pss_getPublicKey")
- if err != nil {
- t.Fatalf("rpc get node 2 pubkey fail: %v", err)
- }
-
- time.Sleep(time.Millisecond * 500)
-
- // at this point we've verified that symkeys are saved and match on each peer
- // now try sending symmetrically encrypted message, both directions
- lmsgC := make(chan APIMsg)
- lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer lcancel()
- lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false)
- log.Trace("lsub", "id", lsub)
- defer lsub.Unsubscribe()
- rmsgC := make(chan APIMsg)
- rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer rcancel()
- rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false)
- log.Trace("rsub", "id", rsub)
- defer rsub.Unsubscribe()
-
- lrecvkey := network.RandomAddr().Over()
- rrecvkey := network.RandomAddr().Over()
-
- var lkeyids [2]string
- var rkeyids [2]string
-
- // manually set reciprocal symkeys
- err = clients[0].Call(&lkeyids, "psstest_setSymKeys", rpubkeyhex, lrecvkey, rrecvkey, defaultSymKeySendLimit, topic, roaddrhex)
- if err != nil {
- t.Fatal(err)
- }
- err = clients[1].Call(&rkeyids, "psstest_setSymKeys", lpubkeyhex, rrecvkey, lrecvkey, defaultSymKeySendLimit, topic, loaddrhex)
- if err != nil {
- t.Fatal(err)
- }
-
- // send and verify delivery
- lmsg := []byte("plugh")
- err = clients[1].Call(nil, "pss_sendSym", rkeyids[1], topic, hexutil.Encode(lmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-lmsgC:
- if !bytes.Equal(recvmsg.Msg, lmsg) {
- t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg)
- }
- case cerr := <-lctx.Done():
- t.Fatalf("test message timed out: %v", cerr)
- }
- rmsg := []byte("xyzzy")
- err = clients[0].Call(nil, "pss_sendSym", lkeyids[1], topic, hexutil.Encode(rmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-rmsgC:
- if !bytes.Equal(recvmsg.Msg, rmsg) {
- t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg)
- }
- case cerr := <-rctx.Done():
- t.Fatalf("test message timed out: %v", cerr)
- }
-}
-
-// send asymmetrically encrypted message between two directly connected peers
-func TestSendAsym(t *testing.T) {
- t.Run("32", testSendAsym)
- t.Run("8", testSendAsym)
- t.Run("0", testSendAsym)
-}
-
-func testSendAsym(t *testing.T) {
-
- // address hint size
- var addrsize int64
- var err error
- paramstring := strings.Split(t.Name(), "/")
- addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0)
- log.Info("asym send test", "addrsize", addrsize)
-
- clients, err := setupNetwork(2, false)
- if err != nil {
- t.Fatal(err)
- }
-
- var topic string
- err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42")
- if err != nil {
- t.Fatal(err)
- }
-
- time.Sleep(time.Millisecond * 250)
-
- var loaddrhex string
- err = clients[0].Call(&loaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 1 baseaddr fail: %v", err)
- }
- loaddrhex = loaddrhex[:2+(addrsize*2)]
- var roaddrhex string
- err = clients[1].Call(&roaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 2 baseaddr fail: %v", err)
- }
- roaddrhex = roaddrhex[:2+(addrsize*2)]
-
- // retrieve public key from pss instance
- // set this public key reciprocally
- var lpubkey string
- err = clients[0].Call(&lpubkey, "pss_getPublicKey")
- if err != nil {
- t.Fatalf("rpc get node 1 pubkey fail: %v", err)
- }
- var rpubkey string
- err = clients[1].Call(&rpubkey, "pss_getPublicKey")
- if err != nil {
- t.Fatalf("rpc get node 2 pubkey fail: %v", err)
- }
-
- time.Sleep(time.Millisecond * 500) // replace with hive healthy code
-
- lmsgC := make(chan APIMsg)
- lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer lcancel()
- lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic, false, false)
- log.Trace("lsub", "id", lsub)
- defer lsub.Unsubscribe()
- rmsgC := make(chan APIMsg)
- rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10)
- defer rcancel()
- rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false)
- log.Trace("rsub", "id", rsub)
- defer rsub.Unsubscribe()
-
- // store reciprocal public keys
- err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex)
- if err != nil {
- t.Fatal(err)
- }
- err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex)
- if err != nil {
- t.Fatal(err)
- }
-
- // send and verify delivery
- rmsg := []byte("xyzzy")
- err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-rmsgC:
- if !bytes.Equal(recvmsg.Msg, rmsg) {
- t.Fatalf("node 2 received payload mismatch: expected %v, got %v", rmsg, recvmsg.Msg)
- }
- case cerr := <-rctx.Done():
- t.Fatalf("test message timed out: %v", cerr)
- }
- lmsg := []byte("plugh")
- err = clients[1].Call(nil, "pss_sendAsym", lpubkey, topic, hexutil.Encode(lmsg))
- if err != nil {
- t.Fatal(err)
- }
- select {
- case recvmsg := <-lmsgC:
- if !bytes.Equal(recvmsg.Msg, lmsg) {
- t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg.Msg)
- }
- case cerr := <-lctx.Done():
- t.Fatalf("test message timed out: %v", cerr)
- }
-}
-
-type Job struct {
- Msg []byte
- SendNode enode.ID
- RecvNode enode.ID
-}
-
-func worker(id int, jobs <-chan Job, rpcs map[enode.ID]*rpc.Client, pubkeys map[enode.ID]string, topic string) {
- for j := range jobs {
- rpcs[j.SendNode].Call(nil, "pss_sendAsym", pubkeys[j.RecvNode], topic, hexutil.Encode(j.Msg))
- }
-}
-
-func TestNetwork(t *testing.T) {
- t.Run("16/1000/4/sim", testNetwork)
-}
-
-// params in run name:
-// nodes/recipientAddresses/addrbytes/adaptertype
-// if adaptertype is exec uses execadapter, simadapter otherwise
-func TestNetwork2000(t *testing.T) {
- if !*longrunning {
- t.Skip("run with --longrunning flag to run extensive network tests")
- }
- t.Run("3/2000/4/sim", testNetwork)
- t.Run("4/2000/4/sim", testNetwork)
- t.Run("8/2000/4/sim", testNetwork)
- t.Run("16/2000/4/sim", testNetwork)
-}
-
-func TestNetwork5000(t *testing.T) {
- if !*longrunning {
- t.Skip("run with --longrunning flag to run extensive network tests")
- }
- t.Run("3/5000/4/sim", testNetwork)
- t.Run("4/5000/4/sim", testNetwork)
- t.Run("8/5000/4/sim", testNetwork)
- t.Run("16/5000/4/sim", testNetwork)
-}
-
-func TestNetwork10000(t *testing.T) {
- if !*longrunning {
- t.Skip("run with --longrunning flag to run extensive network tests")
- }
- t.Run("3/10000/4/sim", testNetwork)
- t.Run("4/10000/4/sim", testNetwork)
- t.Run("8/10000/4/sim", testNetwork)
-}
-
-func testNetwork(t *testing.T) {
- paramstring := strings.Split(t.Name(), "/")
- nodecount, _ := strconv.ParseInt(paramstring[1], 10, 0)
- msgcount, _ := strconv.ParseInt(paramstring[2], 10, 0)
- addrsize, _ := strconv.ParseInt(paramstring[3], 10, 0)
- adapter := paramstring[4]
-
- log.Info("network test", "nodecount", nodecount, "msgcount", msgcount, "addrhintsize", addrsize)
-
- nodes := make([]enode.ID, nodecount)
- bzzaddrs := make(map[enode.ID]string, nodecount)
- rpcs := make(map[enode.ID]*rpc.Client, nodecount)
- pubkeys := make(map[enode.ID]string, nodecount)
-
- sentmsgs := make([][]byte, msgcount)
- recvmsgs := make([]bool, msgcount)
- nodemsgcount := make(map[enode.ID]int, nodecount)
-
- trigger := make(chan enode.ID)
-
- var a adapters.NodeAdapter
- if adapter == "exec" {
- dirname, err := ioutil.TempDir(".", "")
- if err != nil {
- t.Fatal(err)
- }
- a = adapters.NewExecAdapter(dirname)
- } else if adapter == "tcp" {
- a = adapters.NewTCPAdapter(newServices(false))
- } else if adapter == "sim" {
- a = adapters.NewSimAdapter(newServices(false))
- }
- net := simulations.NewNetwork(a, &simulations.NetworkConfig{
- ID: "0",
- })
- defer net.Shutdown()
-
- f, err := os.Open(fmt.Sprintf("testdata/snapshot_%d.json", nodecount))
- if err != nil {
- t.Fatal(err)
- }
- jsonbyte, err := ioutil.ReadAll(f)
- if err != nil {
- t.Fatal(err)
- }
- var snap simulations.Snapshot
- err = json.Unmarshal(jsonbyte, &snap)
- if err != nil {
- t.Fatal(err)
- }
- err = net.Load(&snap)
- if err != nil {
- //TODO: Fix p2p simulation framework to not crash when loading 32-nodes
- //t.Fatal(err)
- }
-
- time.Sleep(1 * time.Second)
-
- triggerChecks := func(trigger chan enode.ID, id enode.ID, rpcclient *rpc.Client, topic string) error {
- msgC := make(chan APIMsg)
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic, false, false)
- if err != nil {
- t.Fatal(err)
- }
- go func() {
- defer sub.Unsubscribe()
- for {
- select {
- case recvmsg := <-msgC:
- idx, _ := binary.Uvarint(recvmsg.Msg)
- if !recvmsgs[idx] {
- log.Debug("msg recv", "idx", idx, "id", id)
- recvmsgs[idx] = true
- trigger <- id
- }
- case <-sub.Err():
- return
- }
- }
- }()
- return nil
- }
-
- var topic string
- for i, nod := range net.GetNodes() {
- nodes[i] = nod.ID()
- rpcs[nodes[i]], err = nod.Client()
- if err != nil {
- t.Fatal(err)
- }
- if topic == "" {
- err = rpcs[nodes[i]].Call(&topic, "pss_stringToTopic", "foo:42")
- if err != nil {
- t.Fatal(err)
- }
- }
- var pubkey string
- err = rpcs[nodes[i]].Call(&pubkey, "pss_getPublicKey")
- if err != nil {
- t.Fatal(err)
- }
- pubkeys[nod.ID()] = pubkey
- var addrhex string
- err = rpcs[nodes[i]].Call(&addrhex, "pss_baseAddr")
- if err != nil {
- t.Fatal(err)
- }
- bzzaddrs[nodes[i]] = addrhex
- err = triggerChecks(trigger, nodes[i], rpcs[nodes[i]], topic)
- if err != nil {
- t.Fatal(err)
- }
- }
-
- time.Sleep(1 * time.Second)
-
- // setup workers
- jobs := make(chan Job, 10)
- for w := 1; w <= 10; w++ {
- go worker(w, jobs, rpcs, pubkeys, topic)
- }
-
- time.Sleep(1 * time.Second)
-
- for i := 0; i < int(msgcount); i++ {
- sendnodeidx := rand.Intn(int(nodecount))
- recvnodeidx := rand.Intn(int(nodecount - 1))
- if recvnodeidx >= sendnodeidx {
- recvnodeidx++
- }
- nodemsgcount[nodes[recvnodeidx]]++
- sentmsgs[i] = make([]byte, 8)
- c := binary.PutUvarint(sentmsgs[i], uint64(i))
- if c == 0 {
- t.Fatal("0 byte message")
- }
- if err != nil {
- t.Fatal(err)
- }
- err = rpcs[nodes[sendnodeidx]].Call(nil, "pss_setPeerPublicKey", pubkeys[nodes[recvnodeidx]], topic, bzzaddrs[nodes[recvnodeidx]])
- if err != nil {
- t.Fatal(err)
- }
-
- jobs <- Job{
- Msg: sentmsgs[i],
- SendNode: nodes[sendnodeidx],
- RecvNode: nodes[recvnodeidx],
- }
- }
-
- finalmsgcount := 0
- ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
- defer cancel()
-outer:
- for i := 0; i < int(msgcount); i++ {
- select {
- case id := <-trigger:
- nodemsgcount[id]--
- finalmsgcount++
- case <-ctx.Done():
- log.Warn("timeout")
- break outer
- }
- }
-
- for i, msg := range recvmsgs {
- if !msg {
- log.Debug("missing message", "idx", i)
- }
- }
- t.Logf("%d of %d messages received", finalmsgcount, msgcount)
-
- if finalmsgcount != int(msgcount) {
- t.Fatalf("%d messages were not received", int(msgcount)-finalmsgcount)
- }
-
-}
-
-// check that in a network of a -> b -> c -> a
-// a doesn't receive a sent message twice
-func TestDeduplication(t *testing.T) {
- var err error
-
- clients, err := setupNetwork(3, false)
- if err != nil {
- t.Fatal(err)
- }
-
- var addrsize = 32
- var loaddrhex string
- err = clients[0].Call(&loaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 1 baseaddr fail: %v", err)
- }
- loaddrhex = loaddrhex[:2+(addrsize*2)]
- var roaddrhex string
- err = clients[1].Call(&roaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 2 baseaddr fail: %v", err)
- }
- roaddrhex = roaddrhex[:2+(addrsize*2)]
- var xoaddrhex string
- err = clients[2].Call(&xoaddrhex, "pss_baseAddr")
- if err != nil {
- t.Fatalf("rpc get node 3 baseaddr fail: %v", err)
- }
- xoaddrhex = xoaddrhex[:2+(addrsize*2)]
-
- log.Info("peer", "l", loaddrhex, "r", roaddrhex, "x", xoaddrhex)
-
- var topic string
- err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42")
- if err != nil {
- t.Fatal(err)
- }
-
- time.Sleep(time.Millisecond * 250)
-
- // retrieve public key from pss instance
- // set this public key reciprocally
- var rpubkey string
- err = clients[1].Call(&rpubkey, "pss_getPublicKey")
- if err != nil {
- t.Fatalf("rpc get receivenode pubkey fail: %v", err)
- }
-
- time.Sleep(time.Millisecond * 500) // replace with hive healthy code
-
- rmsgC := make(chan APIMsg)
- rctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
- defer cancel()
- rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic, false, false)
- log.Trace("rsub", "id", rsub)
- defer rsub.Unsubscribe()
-
- // store public key for recipient
- // zero-length address means forward to all
- // we have just two peers, they will be in proxbin, and will both receive
- err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, "0x")
- if err != nil {
- t.Fatal(err)
- }
-
- // send and verify delivery
- rmsg := []byte("xyzzy")
- err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg))
- if err != nil {
- t.Fatal(err)
- }
-
- var receivedok bool
-OUTER:
- for {
- select {
- case <-rmsgC:
- if receivedok {
- t.Fatalf("duplicate message received")
- }
- receivedok = true
- case <-rctx.Done():
- break OUTER
- }
- }
- if !receivedok {
- t.Fatalf("message did not arrive")
- }
-}
-
-// symmetric send performance with varying message sizes
-func BenchmarkSymkeySend(b *testing.B) {
- b.Run(fmt.Sprintf("%d", 256), benchmarkSymKeySend)
- b.Run(fmt.Sprintf("%d", 1024), benchmarkSymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkSymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkSymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkSymKeySend)
-}
-
-func benchmarkSymKeySend(b *testing.B) {
- msgsizestring := strings.Split(b.Name(), "/")
- if len(msgsizestring) != 2 {
- b.Fatalf("benchmark called without msgsize param")
- }
- msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err)
- }
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- privkey, err := w.GetPrivateKey(keys)
- ps := newTestPss(privkey, nil, nil)
- defer ps.Stop()
- msg := make([]byte, msgsize)
- rand.Read(msg)
- topic := BytesToTopic([]byte("foo"))
- to := make(PssAddress, 32)
- copy(to[:], network.RandomAddr().Over())
- symkeyid, err := ps.GenerateSymmetricKey(topic, to, true)
- if err != nil {
- b.Fatalf("could not generate symkey: %v", err)
- }
- symkey, err := ps.w.GetSymKey(symkeyid)
- if err != nil {
- b.Fatalf("could not retrieve symkey: %v", err)
- }
- ps.SetSymmetricKey(symkey, topic, to, false)
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- ps.SendSym(symkeyid, topic, msg)
- }
-}
-
-// asymmetric send performance with varying message sizes
-func BenchmarkAsymkeySend(b *testing.B) {
- b.Run(fmt.Sprintf("%d", 256), benchmarkAsymKeySend)
- b.Run(fmt.Sprintf("%d", 1024), benchmarkAsymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkAsymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkAsymKeySend)
- b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkAsymKeySend)
-}
-
-func benchmarkAsymKeySend(b *testing.B) {
- msgsizestring := strings.Split(b.Name(), "/")
- if len(msgsizestring) != 2 {
- b.Fatalf("benchmark called without msgsize param")
- }
- msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err)
- }
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- privkey, err := w.GetPrivateKey(keys)
- ps := newTestPss(privkey, nil, nil)
- defer ps.Stop()
- msg := make([]byte, msgsize)
- rand.Read(msg)
- topic := BytesToTopic([]byte("foo"))
- to := make(PssAddress, 32)
- copy(to[:], network.RandomAddr().Over())
- ps.SetPeerPublicKey(&privkey.PublicKey, topic, to)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- ps.SendAsym(common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey)), topic, msg)
- }
-}
-func BenchmarkSymkeyBruteforceChangeaddr(b *testing.B) {
- for i := 100; i < 100000; i = i * 10 {
- for j := 32; j < 10000; j = j * 8 {
- b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceChangeaddr)
- }
- //b.Run(fmt.Sprintf("%d", i), benchmarkSymkeyBruteforceChangeaddr)
- }
-}
-
-// decrypt performance using symkey cache, worst case
-// (decrypt key always last in cache)
-func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) {
- keycountstring := strings.Split(b.Name(), "/")
- cachesize := int64(0)
- var ps *Pss
- if len(keycountstring) < 2 {
- b.Fatalf("benchmark called without count param")
- }
- keycount, err := strconv.ParseInt(keycountstring[1], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err)
- }
- if len(keycountstring) == 3 {
- cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err)
- }
- }
- pssmsgs := make([]*PssMsg, 0, keycount)
- var keyid string
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- privkey, err := w.GetPrivateKey(keys)
- if cachesize > 0 {
- ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)})
- } else {
- ps = newTestPss(privkey, nil, nil)
- }
- defer ps.Stop()
- topic := BytesToTopic([]byte("foo"))
- for i := 0; i < int(keycount); i++ {
- to := make(PssAddress, 32)
- copy(to[:], network.RandomAddr().Over())
- keyid, err = ps.GenerateSymmetricKey(topic, to, true)
- if err != nil {
- b.Fatalf("cant generate symkey #%d: %v", i, err)
- }
- symkey, err := ps.w.GetSymKey(keyid)
- if err != nil {
- b.Fatalf("could not retrieve symkey %s: %v", keyid, err)
- }
- wparams := &whisper.MessageParams{
- TTL: defaultWhisperTTL,
- KeySym: symkey,
- Topic: whisper.TopicType(topic),
- WorkTime: defaultWhisperWorkTime,
- PoW: defaultWhisperPoW,
- Payload: []byte("xyzzy"),
- Padding: []byte("1234567890abcdef"),
- }
- woutmsg, err := whisper.NewSentMessage(wparams)
- if err != nil {
- b.Fatalf("could not create whisper message: %v", err)
- }
- env, err := woutmsg.Wrap(wparams)
- if err != nil {
- b.Fatalf("could not generate whisper envelope: %v", err)
- }
- ps.Register(&topic, &handler{
- f: noopHandlerFunc,
- })
- pssmsgs = append(pssmsgs, &PssMsg{
- To: to,
- Payload: env,
- })
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1], false, false); err != nil {
- b.Fatalf("pss processing failed: %v", err)
- }
- }
-}
-
-func BenchmarkSymkeyBruteforceSameaddr(b *testing.B) {
- for i := 100; i < 100000; i = i * 10 {
- for j := 32; j < 10000; j = j * 8 {
- b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceSameaddr)
- }
- }
-}
-
-// decrypt performance using symkey cache, best case
-// (decrypt key always first in cache)
-func benchmarkSymkeyBruteforceSameaddr(b *testing.B) {
- var keyid string
- var ps *Pss
- cachesize := int64(0)
- keycountstring := strings.Split(b.Name(), "/")
- if len(keycountstring) < 2 {
- b.Fatalf("benchmark called without count param")
- }
- keycount, err := strconv.ParseInt(keycountstring[1], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err)
- }
- if len(keycountstring) == 3 {
- cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0)
- if err != nil {
- b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err)
- }
- }
- addr := make([]PssAddress, keycount)
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctx)
- privkey, err := w.GetPrivateKey(keys)
- if cachesize > 0 {
- ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)})
- } else {
- ps = newTestPss(privkey, nil, nil)
- }
- defer ps.Stop()
- topic := BytesToTopic([]byte("foo"))
- for i := 0; i < int(keycount); i++ {
- copy(addr[i], network.RandomAddr().Over())
- keyid, err = ps.GenerateSymmetricKey(topic, addr[i], true)
- if err != nil {
- b.Fatalf("cant generate symkey #%d: %v", i, err)
- }
-
- }
- symkey, err := ps.w.GetSymKey(keyid)
- if err != nil {
- b.Fatalf("could not retrieve symkey %s: %v", keyid, err)
- }
- wparams := &whisper.MessageParams{
- TTL: defaultWhisperTTL,
- KeySym: symkey,
- Topic: whisper.TopicType(topic),
- WorkTime: defaultWhisperWorkTime,
- PoW: defaultWhisperPoW,
- Payload: []byte("xyzzy"),
- Padding: []byte("1234567890abcdef"),
- }
- woutmsg, err := whisper.NewSentMessage(wparams)
- if err != nil {
- b.Fatalf("could not create whisper message: %v", err)
- }
- env, err := woutmsg.Wrap(wparams)
- if err != nil {
- b.Fatalf("could not generate whisper envelope: %v", err)
- }
- ps.Register(&topic, &handler{
- f: noopHandlerFunc,
- })
- pssmsg := &PssMsg{
- To: addr[len(addr)-1][:],
- Payload: env,
- }
- for i := 0; i < b.N; i++ {
- if err := ps.process(pssmsg, false, false); err != nil {
- b.Fatalf("pss processing failed: %v", err)
- }
- }
-}
-
-// setup simulated network with bzz/discovery and pss services.
-// connects nodes in a circle
-// if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams)
-func setupNetwork(numnodes int, allowRaw bool) (clients []*rpc.Client, err error) {
- nodes := make([]*simulations.Node, numnodes)
- clients = make([]*rpc.Client, numnodes)
- if numnodes < 2 {
- return nil, fmt.Errorf("Minimum two nodes in network")
- }
- adapter := adapters.NewSimAdapter(newServices(allowRaw))
- net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
- ID: "0",
- DefaultService: "bzz",
- })
- for i := 0; i < numnodes; i++ {
- nodeconf := adapters.RandomNodeConfig()
- nodeconf.Services = []string{"bzz", pssProtocolName}
- nodes[i], err = net.NewNodeWithConfig(nodeconf)
- if err != nil {
- return nil, fmt.Errorf("error creating node 1: %v", err)
- }
- err = net.Start(nodes[i].ID())
- if err != nil {
- return nil, fmt.Errorf("error starting node 1: %v", err)
- }
- if i > 0 {
- err = net.Connect(nodes[i].ID(), nodes[i-1].ID())
- if err != nil {
- return nil, fmt.Errorf("error connecting nodes: %v", err)
- }
- }
- clients[i], err = nodes[i].Client()
- if err != nil {
- return nil, fmt.Errorf("create node 1 rpc client fail: %v", err)
- }
- }
- if numnodes > 2 {
- err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID())
- if err != nil {
- return nil, fmt.Errorf("error connecting first and last nodes")
- }
- }
- return clients, nil
-}
-
-func newServices(allowRaw bool) adapters.Services {
- stateStore := state.NewInmemoryStore()
- kademlias := make(map[enode.ID]*network.Kademlia)
- kademlia := func(id enode.ID) *network.Kademlia {
- if k, ok := kademlias[id]; ok {
- return k
- }
- params := network.NewKadParams()
- params.NeighbourhoodSize = 2
- params.MaxBinSize = 3
- params.MinBinSize = 1
- params.MaxRetries = 1000
- params.RetryExponent = 2
- params.RetryInterval = 1000000
- kademlias[id] = network.NewKademlia(id[:], params)
- return kademlias[id]
- }
- return adapters.Services{
- pssProtocolName: func(ctx *adapters.ServiceContext) (node.Service, error) {
- // execadapter does not exec init()
- initTest()
-
- ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- keys, err := wapi.NewKeyPair(ctxlocal)
- privkey, err := w.GetPrivateKey(keys)
- pssp := NewPssParams().WithPrivateKey(privkey)
- pssp.AllowRaw = allowRaw
- pskad := kademlia(ctx.Config.ID)
- ps, err := NewPss(pskad, pssp)
- if err != nil {
- return nil, err
- }
-
- ping := &Ping{
- OutC: make(chan bool),
- Pong: true,
- }
- p2pp := NewPingProtocol(ping)
- pp, err := RegisterProtocol(ps, &PingTopic, PingProtocol, p2pp, &ProtocolParams{Asymmetric: true})
- if err != nil {
- return nil, err
- }
- if useHandshake {
- SetHandshakeController(ps, NewHandshakeParams())
- }
- ps.Register(&PingTopic, &handler{
- f: pp.Handle,
- caps: &handlerCaps{
- raw: true,
- },
- })
- ps.addAPI(rpc.API{
- Namespace: "psstest",
- Version: "0.3",
- Service: NewAPITest(ps),
- Public: false,
- })
- if err != nil {
- log.Error("Couldnt register pss protocol", "err", err)
- os.Exit(1)
- }
- pssprotocols[ctx.Config.ID.String()] = &protoCtrl{
- C: ping.OutC,
- protocol: pp,
- run: p2pp.Run,
- }
- return ps, nil
- },
- "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) {
- addr := network.NewAddr(ctx.Config.Node())
- hp := network.NewHiveParams()
- hp.Discovery = false
- config := &network.BzzConfig{
- OverlayAddr: addr.Over(),
- UnderlayAddr: addr.Under(),
- HiveParams: hp,
- }
- return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil
- },
- }
-}
-
-func newTestPss(privkey *ecdsa.PrivateKey, kad *network.Kademlia, ppextra *PssParams) *Pss {
- nid := enode.PubkeyToIDV4(&privkey.PublicKey)
- // set up routing if kademlia is not passed to us
- if kad == nil {
- kp := network.NewKadParams()
- kp.NeighbourhoodSize = 3
- kad = network.NewKademlia(nid[:], kp)
- }
-
- // create pss
- pp := NewPssParams().WithPrivateKey(privkey)
- if ppextra != nil {
- pp.SymKeyCacheCapacity = ppextra.SymKeyCacheCapacity
- }
- ps, err := NewPss(kad, pp)
- if err != nil {
- return nil
- }
- ps.Start(nil)
-
- return ps
-}
-
-// API calls for test/development use
-type APITest struct {
- *Pss
-}
-
-func NewAPITest(ps *Pss) *APITest {
- return &APITest{Pss: ps}
-}
-
-func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymkey []byte, limit uint16, topic Topic, to hexutil.Bytes) ([2]string, error) {
-
- recvsymkeyid, err := apitest.SetSymmetricKey(recvsymkey, topic, PssAddress(to), true)
- if err != nil {
- return [2]string{}, err
- }
- sendsymkeyid, err := apitest.SetSymmetricKey(sendsymkey, topic, PssAddress(to), false)
- if err != nil {
- return [2]string{}, err
- }
- return [2]string{recvsymkeyid, sendsymkeyid}, nil
-}
-
-func (apitest *APITest) Clean() (int, error) {
- return apitest.Pss.cleanKeys(), nil
-}