cmd/swarm/swarm-smoke: pss aync test, send multiple msgs

This commit is contained in:
Rafael Matias 2019-03-25 14:43:41 +01:00
parent e9c6a587ab
commit 85721d6e7d
No known key found for this signature in database
GPG key ID: 1BC39532FB4A2DBD
2 changed files with 88 additions and 59 deletions

View file

@ -48,6 +48,7 @@ var (
timeout int timeout int
single bool single bool
trackTimeout int trackTimeout int
pssMessageCount int
) )
func main() { func main() {
@ -116,6 +117,12 @@ func main() {
Usage: "timeout in seconds to wait for GetAllReferences to return", Usage: "timeout in seconds to wait for GetAllReferences to return",
Destination: &trackTimeout, Destination: &trackTimeout,
}, },
cli.IntFlag{
Name: "pss-messages",
Value: 10,
Usage: "number of pss messages that should be send in the pss smoke test",
Destination: &pssMessageCount,
},
} }
app.Flags = append(app.Flags, []cli.Flag{ app.Flags = append(app.Flags, []cli.Flag{
@ -155,10 +162,10 @@ func main() {
Action: wrapCliCommand("sliding-window", slidingWindowCmd), Action: wrapCliCommand("sliding-window", slidingWindowCmd),
}, },
{ {
Name: "pss", Name: "pss-asym",
Aliases: []string{"p"}, Aliases: []string{"pa"},
Usage: "pss send and receive checks", Usage: "PSS: send and receive multiple messages across random nodes using asymmetric encryption",
Action: wrapCliCommand("pss", pssChecks), Action: wrapCliCommand("pss-asym", pssAsymCheck),
}, },
} }

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/sha1" "crypto/sha1"
"errors"
"fmt" "fmt"
"math/rand" "math/rand"
"time" "time"
@ -27,7 +28,6 @@ const (
type pssJob struct { type pssJob struct {
msg []byte msg []byte
mode int mode int
prox bool
} }
type pssNode struct { type pssNode struct {
@ -39,24 +39,33 @@ type pssNode struct {
msgC chan pss.APIMsg msgC chan pss.APIMsg
} }
// keyed by hex representation of overlay address
type pssSession struct { type pssSession struct {
topic pss.Topic topic pss.Topic
msgC chan pss.APIMsg msgC chan pss.APIMsg
nodes []*pssNode nodes []*pssNode
requiredJobs map[string]*pssJob requiredJobs map[string]*pssJob
allowedJobs map[string]*pssJob
} }
func pssChecks(ctx *cli.Context, tuid string) error { // pssAsymCheck sends one or more messages (depending on pssMessageCount)
return pssAsym(ctx, tuid) // using asymmetric encryption across random nodes.
} func pssAsymCheck(ctx *cli.Context, tuid string) error {
func pssAsym(ctx *cli.Context, tuid string) error { // use input seed if it has been set
if inputSeed != 0 {
seed = inputSeed
}
rand.Seed(int64(seed))
if pssMessageCount <= 0 {
pssMessageCount = 1
log.Warn(fmt.Sprintf("message count should be a positive number. Defaulting to %d", pssMessageCount))
}
log.Info("pss-asym test started", "msgCount", pssMessageCount)
errc := make(chan error) errc := make(chan error)
session := pssSetup() session := pssSetup()
if len(session.nodes) <= 1 {
return errors.New("at least 2 nodes are required to be working")
}
defer func() { defer func() {
for _, n := range session.nodes { for _, n := range session.nodes {
n.deregisterFunc() n.deregisterFunc()
@ -64,37 +73,54 @@ func pssAsym(ctx *cli.Context, tuid string) error {
}() }()
go func() { go func() {
errc <- pssAsymDo(ctx, session, tuid) var failCount, successCount int64
for i := 0; i < pssMessageCount; i++ {
err := pssAsymDo(ctx, session, tuid)
if err != nil {
failCount++
log.Error("error sending pss msg", "err", err)
} else {
successCount++
}
}
metrics.GetOrRegisterCounter("pss.asym.failMsg", nil).Inc(failCount)
metrics.GetOrRegisterCounter("pss.asym.successMsg", nil).Inc(successCount)
log.Info("pss-asym test ended", "success", successCount, "failures", failCount)
if failCount > 0 {
errc <- errors.New("some messages were not delivered")
} else {
errc <- nil
}
}() }()
select { select {
case err := <-errc: case err := <-errc:
if err != nil { if err != nil {
metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) metrics.GetOrRegisterCounter("pss.asym.fail", nil).Inc(1)
} }
return err return err
case <-time.After(time.Duration(timeout) * time.Second): case <-time.After(time.Duration(timeout) * time.Second):
metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) metrics.GetOrRegisterCounter("pss.asym.timeout", nil).Inc(1)
return fmt.Errorf("timeout after %v sec", timeout)
e := fmt.Errorf("timeout after %v sec", timeout)
return e
} }
} }
func pssSetup() *pssSession { func pssSetup() *pssSession {
// random topic, one per session, same for all msgs // random topic, one per session, same for all msgs
topic := pss.BytesToTopic(testutil.RandomBytes(seed, 4)) topic := pss.BytesToTopic(testutil.RandomBytes(seed, 4))
log.Trace("pss random topic", "topic", topic.String())
session := &pssSession{ session := &pssSession{
msgC: make(chan pss.APIMsg), msgC: make(chan pss.APIMsg),
requiredJobs: make(map[string]*pssJob), requiredJobs: make(map[string]*pssJob),
allowedJobs: make(map[string]*pssJob),
topic: topic, topic: topic,
} }
// hosts is global :/
// set up the necessary info for each pss node // set up the necessary info for each pss node
for i, host := range hosts { for i, host := range hosts {
httpHost := fmt.Sprintf("ws://%s:%d", host, 8546) httpHost := fmt.Sprintf("ws://%s:%d", host, 8546)
@ -105,7 +131,6 @@ func pssSetup() *pssSession {
} }
// get overlay address // get overlay address
// TODO this should be done automatically for all nodes anyway in all smokes perhaps?
var addr hexutil.Bytes var addr hexutil.Bytes
err = rpcClient.Call(&addr, "pss_baseAddr") err = rpcClient.Call(&addr, "pss_baseAddr")
if err != nil { if err != nil {
@ -124,7 +149,6 @@ func pssSetup() *pssSession {
// subscribe to the topic for the session // subscribe to the topic for the session
// this creates the incoming message handler automatically // this creates the incoming message handler automatically
// any message received with this topic comes on the channel // any message received with this topic comes on the channel
//msgC := make(chan pss.APIMsg)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel() defer cancel()
sub, err := rpcClient.Subscribe(ctx, "pss", session.msgC, "receive", session.topic, true, false) sub, err := rpcClient.Subscribe(ctx, "pss", session.msgC, "receive", session.topic, true, false)
@ -135,7 +159,6 @@ func pssSetup() *pssSession {
session.nodes = append(session.nodes, session.nodes = append(session.nodes,
&pssNode{ &pssNode{
hostIdx: i, hostIdx: i,
//msgC: msgC,
addr: []byte(addr), addr: []byte(addr),
client: rpcClient, client: rpcClient,
pubkey: pubkey, pubkey: pubkey,
@ -147,14 +170,20 @@ func pssSetup() *pssSession {
return session return session
} }
// pssAsymDo sends a single PSS message between two random nodes using asymetric encryption
func pssAsymDo(ctx *cli.Context, session *pssSession, tuid string) error { func pssAsymDo(ctx *cli.Context, session *pssSession, tuid string) error {
// can we choose? if so, change senderNodeIdx := rand.Intn(len(session.nodes))
senderNode := session.nodes[0] senderNode := session.nodes[senderNodeIdx]
log.Trace("sender node", "pss_baseAddr", hexutil.Encode(senderNode.addr), "host", hosts[senderNodeIdx])
// add if single blah blah... // receiving node has to be different than sender
recvNodeIdx := rand.Intn(len(session.nodes)-1) + 1 recvNodeIdx := senderNodeIdx
for recvNodeIdx == senderNodeIdx {
recvNodeIdx = rand.Intn(len(session.nodes))
}
recvNode := session.nodes[recvNodeIdx] recvNode := session.nodes[recvNodeIdx]
log.Trace("recv node", "pss_baseAddr", hexutil.Encode(recvNode.addr), "host", hosts[recvNodeIdx])
// set recipient in pivot node // set recipient in pivot node
err := senderNode.client.Call(nil, "pss_setPeerPublicKey", recvNode.pubkey, session.topic, "0x") err := senderNode.client.Call(nil, "pss_setPeerPublicKey", recvNode.pubkey, session.topic, "0x")
@ -162,46 +191,39 @@ func pssAsymDo(ctx *cli.Context, session *pssSession, tuid string) error {
return err return err
} }
// for asym it's not necessary to set recipient, but for sym we must
// err = recvNode.client.Call(nil, "pss_setPeerPublicKey", senderNode.pubkey, session.topic, "0x")
// if err != nil {
// return err
// }
// create new message and add it to job index to check for receives // create new message and add it to job index to check for receives
randomMsg := testutil.RandomBytes(seed, 128) randomMsg := testutil.RandomBytes(seed, 128)
// change seed so that the next random message is different
seed = seed + 1
msgIdx := toMsgIdx(randomMsg) msgIdx := toMsgIdx(randomMsg)
session.requiredJobs[msgIdx] = &pssJob{ session.requiredJobs[msgIdx] = &pssJob{
msg: randomMsg, msg: randomMsg,
mode: pssModeAsym, mode: pssModeAsym,
} }
// send the msg // send the message
hostIdx := session.nodes[recvNodeIdx].hostIdx hostIdx := session.nodes[recvNodeIdx].hostIdx
log.Info("sending pss", "sender", hosts[0], "recv", hosts[hostIdx]) log.Debug("sending msg", "job", hexutil.Encode([]byte(msgIdx)), "sender", hosts[senderNodeIdx], "recv", hosts[hostIdx])
err = senderNode.client.Call(nil, "pss_sendAsym", recvNode.pubkey, session.topic, hexutil.Encode(randomMsg)) err = senderNode.client.Call(nil, "pss_sendAsym", recvNode.pubkey, session.topic, hexutil.Encode(randomMsg))
if err != nil { if err != nil {
return err return err
} }
// receive the msg or timeout and fail // receive the message and check for its content
// and check its validity
pctx, cancel := context.WithTimeout(context.TODO(), time.Second)
defer cancel()
select { select {
//case res := <-(recvNode.msgC): case res := <-session.msgC:
case res := <-(session.msgC):
resIdx := toMsgIdx(res.Msg) resIdx := toMsgIdx(res.Msg)
resJob, ok := session.requiredJobs[resIdx] resJob, ok := session.requiredJobs[resIdx]
if !ok { if !ok {
return fmt.Errorf("corrupt message", "job", resIdx) return fmt.Errorf("corrupt message for job %s", resIdx)
} }
if !bytes.Equal(res.Msg, resJob.msg) { if !bytes.Equal(res.Msg, resJob.msg) {
return fmt.Errorf("message mismatch", "job", resIdx) return fmt.Errorf("message mismatch. expected: %s got: %s", resJob.msg, res.Msg)
} }
log.Info("got msg", "job", hexutil.Encode([]byte(resIdx))) log.Debug("got msg", "job", hexutil.Encode([]byte(resIdx)))
case <-pctx.Done(): case <-time.After(1 * time.Second):
return pctx.Err() return errors.New("msg timeout after 1 sec")
} }
return nil return nil
} }