github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/pss/pss_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package pss 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "encoding/binary" 24 "encoding/hex" 25 "encoding/json" 26 "flag" 27 "fmt" 28 "io/ioutil" 29 "math/rand" 30 "os" 31 "strconv" 32 "strings" 33 "sync" 34 "testing" 35 "time" 36 37 "github.com/FusionFoundation/efsn/common" 38 "github.com/FusionFoundation/efsn/common/hexutil" 39 "github.com/FusionFoundation/efsn/crypto" 40 "github.com/FusionFoundation/efsn/log" 41 "github.com/FusionFoundation/efsn/metrics" 42 "github.com/FusionFoundation/efsn/metrics/influxdb" 43 "github.com/FusionFoundation/efsn/node" 44 "github.com/FusionFoundation/efsn/p2p" 45 "github.com/FusionFoundation/efsn/p2p/discover" 46 "github.com/FusionFoundation/efsn/p2p/protocols" 47 "github.com/FusionFoundation/efsn/p2p/simulations" 48 "github.com/FusionFoundation/efsn/p2p/simulations/adapters" 49 "github.com/FusionFoundation/efsn/rpc" 50 "github.com/FusionFoundation/efsn/swarm/network" 51 "github.com/FusionFoundation/efsn/swarm/state" 52 whisper "github.com/FusionFoundation/efsn/whisper/whisperv5" 53 ) 54 55 var ( 56 initOnce = sync.Once{} 57 debugdebugflag = flag.Bool("vv", false, "veryverbose") 58 debugflag = flag.Bool("v", false, "verbose") 59 longrunning = flag.Bool("longrunning", false, "do run long-running tests") 60 w *whisper.Whisper 61 wapi *whisper.PublicWhisperAPI 62 psslogmain log.Logger 63 pssprotocols map[string]*protoCtrl 64 useHandshake bool 65 ) 66 67 func init() { 68 flag.Parse() 69 rand.Seed(time.Now().Unix()) 70 71 adapters.RegisterServices(newServices(false)) 72 initTest() 73 } 74 75 func initTest() { 76 initOnce.Do( 77 func() { 78 loglevel := log.LvlInfo 79 if *debugflag { 80 loglevel = log.LvlDebug 81 } else if *debugdebugflag { 82 loglevel = log.LvlTrace 83 } 84 85 psslogmain = log.New("psslog", "*") 86 hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) 87 hf := log.LvlFilterHandler(loglevel, hs) 88 h := log.CallerFileHandler(hf) 89 log.Root().SetHandler(h) 90 91 w = whisper.New(&whisper.DefaultConfig) 92 wapi = whisper.NewPublicWhisperAPI(w) 93 94 pssprotocols = make(map[string]*protoCtrl) 95 }, 96 ) 97 } 98 99 // test that topic conversion functions give predictable results 100 func TestTopic(t *testing.T) { 101 102 api := &API{} 103 104 topicstr := strings.Join([]string{PingProtocol.Name, strconv.Itoa(int(PingProtocol.Version))}, ":") 105 106 // bytestotopic is the authoritative topic conversion source 107 topicobj := BytesToTopic([]byte(topicstr)) 108 109 // string to topic and bytes to topic must match 110 topicapiobj, _ := api.StringToTopic(topicstr) 111 if topicobj != topicapiobj { 112 t.Fatalf("bytes and string topic conversion mismatch; %s != %s", topicobj, topicapiobj) 113 } 114 115 // string representation of topichex 116 topichex := topicobj.String() 117 118 // protocoltopic wrapper on pingtopic should be same as topicstring 119 // check that it matches 120 pingtopichex := PingTopic.String() 121 if topichex != pingtopichex { 122 t.Fatalf("protocol topic conversion mismatch; %s != %s", topichex, pingtopichex) 123 } 124 125 // json marshal of topic 126 topicjsonout, err := topicobj.MarshalJSON() 127 if err != nil { 128 t.Fatal(err) 129 } 130 if string(topicjsonout)[1:len(topicjsonout)-1] != topichex { 131 t.Fatalf("topic json marshal mismatch; %s != \"%s\"", topicjsonout, topichex) 132 } 133 134 // json unmarshal of topic 135 var topicjsonin Topic 136 topicjsonin.UnmarshalJSON(topicjsonout) 137 if topicjsonin != topicobj { 138 t.Fatalf("topic json unmarshal mismatch: %x != %x", topicjsonin, topicobj) 139 } 140 } 141 142 // test bit packing of message control flags 143 func TestMsgParams(t *testing.T) { 144 var ctrl byte 145 ctrl |= pssControlRaw 146 p := newMsgParamsFromBytes([]byte{ctrl}) 147 m := newPssMsg(p) 148 if !m.isRaw() || m.isSym() { 149 t.Fatal("expected raw=true and sym=false") 150 } 151 ctrl |= pssControlSym 152 p = newMsgParamsFromBytes([]byte{ctrl}) 153 m = newPssMsg(p) 154 if !m.isRaw() || !m.isSym() { 155 t.Fatal("expected raw=true and sym=true") 156 } 157 ctrl &= 0xff &^ pssControlRaw 158 p = newMsgParamsFromBytes([]byte{ctrl}) 159 m = newPssMsg(p) 160 if m.isRaw() || !m.isSym() { 161 t.Fatal("expected raw=false and sym=true") 162 } 163 } 164 165 // test if we can insert into cache, match items with cache and cache expiry 166 func TestCache(t *testing.T) { 167 var err error 168 to, _ := hex.DecodeString("08090a0b0c0d0e0f1011121314150001020304050607161718191a1b1c1d1e1f") 169 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 170 defer cancel() 171 keys, err := wapi.NewKeyPair(ctx) 172 privkey, err := w.GetPrivateKey(keys) 173 if err != nil { 174 t.Fatal(err) 175 } 176 ps := newTestPss(privkey, nil, nil) 177 pp := NewPssParams().WithPrivateKey(privkey) 178 data := []byte("foo") 179 datatwo := []byte("bar") 180 datathree := []byte("baz") 181 wparams := &whisper.MessageParams{ 182 TTL: defaultWhisperTTL, 183 Src: privkey, 184 Dst: &privkey.PublicKey, 185 Topic: whisper.TopicType(PingTopic), 186 WorkTime: defaultWhisperWorkTime, 187 PoW: defaultWhisperPoW, 188 Payload: data, 189 } 190 woutmsg, err := whisper.NewSentMessage(wparams) 191 env, err := woutmsg.Wrap(wparams) 192 msg := &PssMsg{ 193 Payload: env, 194 To: to, 195 } 196 wparams.Payload = datatwo 197 woutmsg, err = whisper.NewSentMessage(wparams) 198 envtwo, err := woutmsg.Wrap(wparams) 199 msgtwo := &PssMsg{ 200 Payload: envtwo, 201 To: to, 202 } 203 wparams.Payload = datathree 204 woutmsg, err = whisper.NewSentMessage(wparams) 205 envthree, err := woutmsg.Wrap(wparams) 206 msgthree := &PssMsg{ 207 Payload: envthree, 208 To: to, 209 } 210 211 digest := ps.digest(msg) 212 if err != nil { 213 t.Fatalf("could not store cache msgone: %v", err) 214 } 215 digesttwo := ps.digest(msgtwo) 216 if err != nil { 217 t.Fatalf("could not store cache msgtwo: %v", err) 218 } 219 digestthree := ps.digest(msgthree) 220 if err != nil { 221 t.Fatalf("could not store cache msgthree: %v", err) 222 } 223 224 if digest == digesttwo { 225 t.Fatalf("different msgs return same hash: %d", digesttwo) 226 } 227 228 // check the cache 229 err = ps.addFwdCache(msg) 230 if err != nil { 231 t.Fatalf("write to pss expire cache failed: %v", err) 232 } 233 234 if !ps.checkFwdCache(msg) { 235 t.Fatalf("message %v should have EXPIRE record in cache but checkCache returned false", msg) 236 } 237 238 if ps.checkFwdCache(msgtwo) { 239 t.Fatalf("message %v should NOT have EXPIRE record in cache but checkCache returned true", msgtwo) 240 } 241 242 time.Sleep(pp.CacheTTL + 1*time.Second) 243 err = ps.addFwdCache(msgthree) 244 if err != nil { 245 t.Fatalf("write to pss expire cache failed: %v", err) 246 } 247 248 if ps.checkFwdCache(msg) { 249 t.Fatalf("message %v should have expired from cache but checkCache returned true", msg) 250 } 251 252 if _, ok := ps.fwdCache[digestthree]; !ok { 253 t.Fatalf("unexpired message should be in the cache: %v", digestthree) 254 } 255 256 if _, ok := ps.fwdCache[digesttwo]; ok { 257 t.Fatalf("expired message should have been cleared from the cache: %v", digesttwo) 258 } 259 } 260 261 // matching of address hints; whether a message could be or is for the node 262 func TestAddressMatch(t *testing.T) { 263 264 localaddr := network.RandomAddr().Over() 265 copy(localaddr[:8], []byte("deadbeef")) 266 remoteaddr := []byte("feedbeef") 267 kadparams := network.NewKadParams() 268 kad := network.NewKademlia(localaddr, kadparams) 269 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 270 defer cancel() 271 keys, err := wapi.NewKeyPair(ctx) 272 if err != nil { 273 t.Fatalf("Could not generate private key: %v", err) 274 } 275 privkey, err := w.GetPrivateKey(keys) 276 pssp := NewPssParams().WithPrivateKey(privkey) 277 ps, err := NewPss(kad, pssp) 278 if err != nil { 279 t.Fatal(err.Error()) 280 } 281 282 pssmsg := &PssMsg{ 283 To: remoteaddr, 284 Payload: &whisper.Envelope{}, 285 } 286 287 // differ from first byte 288 if ps.isSelfRecipient(pssmsg) { 289 t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) 290 } 291 if ps.isSelfPossibleRecipient(pssmsg) { 292 t.Fatalf("isSelfPossibleRecipient true but %x != %x", remoteaddr[:8], localaddr[:8]) 293 } 294 295 // 8 first bytes same 296 copy(remoteaddr[:4], localaddr[:4]) 297 if ps.isSelfRecipient(pssmsg) { 298 t.Fatalf("isSelfRecipient true but %x != %x", remoteaddr, localaddr) 299 } 300 if !ps.isSelfPossibleRecipient(pssmsg) { 301 t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) 302 } 303 304 // all bytes same 305 pssmsg.To = localaddr 306 if !ps.isSelfRecipient(pssmsg) { 307 t.Fatalf("isSelfRecipient false but %x == %x", remoteaddr, localaddr) 308 } 309 if !ps.isSelfPossibleRecipient(pssmsg) { 310 t.Fatalf("isSelfPossibleRecipient false but %x == %x", remoteaddr[:8], localaddr[:8]) 311 } 312 } 313 314 // 315 func TestHandlerConditions(t *testing.T) { 316 317 t.Skip("Disabled due to probable faulty logic for outbox expectations") 318 // setup 319 privkey, err := crypto.GenerateKey() 320 if err != nil { 321 t.Fatal(err.Error()) 322 } 323 324 addr := make([]byte, 32) 325 addr[0] = 0x01 326 ps := newTestPss(privkey, network.NewKademlia(addr, network.NewKadParams()), NewPssParams()) 327 328 // message should pass 329 msg := &PssMsg{ 330 To: addr, 331 Expire: uint32(time.Now().Add(time.Second * 60).Unix()), 332 Payload: &whisper.Envelope{ 333 Topic: [4]byte{}, 334 Data: []byte{0x66, 0x6f, 0x6f}, 335 }, 336 } 337 if err := ps.handlePssMsg(context.TODO(), msg); err != nil { 338 t.Fatal(err.Error()) 339 } 340 tmr := time.NewTimer(time.Millisecond * 100) 341 var outmsg *PssMsg 342 select { 343 case outmsg = <-ps.outbox: 344 case <-tmr.C: 345 default: 346 } 347 if outmsg != nil { 348 t.Fatalf("expected outbox empty after full address on msg, but had message %s", msg) 349 } 350 351 // message should pass and queue due to partial length 352 msg.To = addr[0:1] 353 msg.Payload.Data = []byte{0x78, 0x79, 0x80, 0x80, 0x79} 354 if err := ps.handlePssMsg(context.TODO(), msg); err != nil { 355 t.Fatal(err.Error()) 356 } 357 tmr.Reset(time.Millisecond * 100) 358 outmsg = nil 359 select { 360 case outmsg = <-ps.outbox: 361 case <-tmr.C: 362 } 363 if outmsg == nil { 364 t.Fatal("expected message in outbox on encrypt fail, but empty") 365 } 366 outmsg = nil 367 select { 368 case outmsg = <-ps.outbox: 369 default: 370 } 371 if outmsg != nil { 372 t.Fatalf("expected only one queued message but also had message %v", msg) 373 } 374 375 // full address mismatch should put message in queue 376 msg.To[0] = 0xff 377 if err := ps.handlePssMsg(context.TODO(), msg); err != nil { 378 t.Fatal(err.Error()) 379 } 380 tmr.Reset(time.Millisecond * 10) 381 outmsg = nil 382 select { 383 case outmsg = <-ps.outbox: 384 case <-tmr.C: 385 } 386 if outmsg == nil { 387 t.Fatal("expected message in outbox on address mismatch, but empty") 388 } 389 outmsg = nil 390 select { 391 case outmsg = <-ps.outbox: 392 default: 393 } 394 if outmsg != nil { 395 t.Fatalf("expected only one queued message but also had message %v", msg) 396 } 397 398 // expired message should be dropped 399 msg.Expire = uint32(time.Now().Add(-time.Second).Unix()) 400 if err := ps.handlePssMsg(context.TODO(), msg); err != nil { 401 t.Fatal(err.Error()) 402 } 403 tmr.Reset(time.Millisecond * 10) 404 outmsg = nil 405 select { 406 case outmsg = <-ps.outbox: 407 case <-tmr.C: 408 default: 409 } 410 if outmsg != nil { 411 t.Fatalf("expected empty queue but have message %v", msg) 412 } 413 414 // invalid message should return error 415 fckedupmsg := &struct { 416 pssMsg *PssMsg 417 }{ 418 pssMsg: &PssMsg{}, 419 } 420 if err := ps.handlePssMsg(context.TODO(), fckedupmsg); err == nil { 421 t.Fatalf("expected error from processMsg but error nil") 422 } 423 424 // outbox full should return error 425 msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix()) 426 for i := 0; i < defaultOutboxCapacity; i++ { 427 ps.outbox <- msg 428 } 429 msg.Payload.Data = []byte{0x62, 0x61, 0x72} 430 err = ps.handlePssMsg(context.TODO(), msg) 431 if err == nil { 432 t.Fatal("expected error when mailbox full, but was nil") 433 } 434 } 435 436 // set and generate pubkeys and symkeys 437 func TestKeys(t *testing.T) { 438 // make our key and init pss with it 439 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 440 defer cancel() 441 ourkeys, err := wapi.NewKeyPair(ctx) 442 if err != nil { 443 t.Fatalf("create 'our' key fail") 444 } 445 ctx, cancel2 := context.WithTimeout(context.Background(), time.Second) 446 defer cancel2() 447 theirkeys, err := wapi.NewKeyPair(ctx) 448 if err != nil { 449 t.Fatalf("create 'their' key fail") 450 } 451 ourprivkey, err := w.GetPrivateKey(ourkeys) 452 if err != nil { 453 t.Fatalf("failed to retrieve 'our' private key") 454 } 455 theirprivkey, err := w.GetPrivateKey(theirkeys) 456 if err != nil { 457 t.Fatalf("failed to retrieve 'their' private key") 458 } 459 ps := newTestPss(ourprivkey, nil, nil) 460 461 // set up peer with mock address, mapped to mocked publicaddress and with mocked symkey 462 addr := make(PssAddress, 32) 463 copy(addr, network.RandomAddr().Over()) 464 outkey := network.RandomAddr().Over() 465 topicobj := BytesToTopic([]byte("foo:42")) 466 ps.SetPeerPublicKey(&theirprivkey.PublicKey, topicobj, &addr) 467 outkeyid, err := ps.SetSymmetricKey(outkey, topicobj, &addr, false) 468 if err != nil { 469 t.Fatalf("failed to set 'our' outgoing symmetric key") 470 } 471 472 // make a symmetric key that we will send to peer for encrypting messages to us 473 inkeyid, err := ps.GenerateSymmetricKey(topicobj, &addr, true) 474 if err != nil { 475 t.Fatalf("failed to set 'our' incoming symmetric key") 476 } 477 478 // get the key back from whisper, check that it's still the same 479 outkeyback, err := ps.w.GetSymKey(outkeyid) 480 if err != nil { 481 t.Fatalf(err.Error()) 482 } 483 inkey, err := ps.w.GetSymKey(inkeyid) 484 if err != nil { 485 t.Fatalf(err.Error()) 486 } 487 if !bytes.Equal(outkeyback, outkey) { 488 t.Fatalf("passed outgoing symkey doesnt equal stored: %x / %x", outkey, outkeyback) 489 } 490 491 t.Logf("symout: %v", outkeyback) 492 t.Logf("symin: %v", inkey) 493 494 // check that the key is stored in the peerpool 495 psp := ps.symKeyPool[inkeyid][topicobj] 496 if psp.address != &addr { 497 t.Fatalf("inkey address does not match; %p != %p", psp.address, &addr) 498 } 499 } 500 501 func TestGetPublickeyEntries(t *testing.T) { 502 503 privkey, err := crypto.GenerateKey() 504 if err != nil { 505 t.Fatal(err) 506 } 507 ps := newTestPss(privkey, nil, nil) 508 509 peeraddr := network.RandomAddr().Over() 510 topicaddr := make(map[Topic]PssAddress) 511 topicaddr[Topic{0x13}] = peeraddr 512 topicaddr[Topic{0x2a}] = peeraddr[:16] 513 topicaddr[Topic{0x02, 0x9a}] = []byte{} 514 515 remoteprivkey, err := crypto.GenerateKey() 516 if err != nil { 517 t.Fatal(err) 518 } 519 remotepubkeybytes := crypto.FromECDSAPub(&remoteprivkey.PublicKey) 520 remotepubkeyhex := common.ToHex(remotepubkeybytes) 521 522 pssapi := NewAPI(ps) 523 524 for to, a := range topicaddr { 525 err = pssapi.SetPeerPublicKey(remotepubkeybytes, to, a) 526 if err != nil { 527 t.Fatal(err) 528 } 529 } 530 531 intopic, err := pssapi.GetPeerTopics(remotepubkeyhex) 532 if err != nil { 533 t.Fatal(err) 534 } 535 536 OUTER: 537 for _, tnew := range intopic { 538 for torig, addr := range topicaddr { 539 if bytes.Equal(torig[:], tnew[:]) { 540 inaddr, err := pssapi.GetPeerAddress(remotepubkeyhex, torig) 541 if err != nil { 542 t.Fatal(err) 543 } 544 if !bytes.Equal(addr, inaddr) { 545 t.Fatalf("Address mismatch for topic %x; got %x, expected %x", torig, inaddr, addr) 546 } 547 delete(topicaddr, torig) 548 continue OUTER 549 } 550 } 551 t.Fatalf("received topic %x did not match any existing topics", tnew) 552 } 553 554 if len(topicaddr) != 0 { 555 t.Fatalf("%d topics were not matched", len(topicaddr)) 556 } 557 } 558 559 // forwarding should skip peers that do not have matching pss capabilities 560 func TestMismatch(t *testing.T) { 561 562 // create privkey for forwarder node 563 privkey, err := crypto.GenerateKey() 564 if err != nil { 565 t.Fatal(err) 566 } 567 568 // initialize kad 569 baseaddr := network.RandomAddr() 570 kad := network.NewKademlia((baseaddr).Over(), network.NewKadParams()) 571 rw := &p2p.MsgPipeRW{} 572 573 // one peer has a mismatching version of pss 574 wrongpssaddr := network.RandomAddr() 575 wrongpsscap := p2p.Cap{ 576 Name: pssProtocolName, 577 Version: 0, 578 } 579 nid, _ := discover.HexID("0x01") 580 wrongpsspeer := network.NewPeer(&network.BzzPeer{ 581 Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(wrongpssaddr.Over()), []p2p.Cap{wrongpsscap}), rw, nil), 582 BzzAddr: &network.BzzAddr{OAddr: wrongpssaddr.Over(), UAddr: nil}, 583 }, kad) 584 585 // one peer doesn't even have pss (boo!) 586 nopssaddr := network.RandomAddr() 587 nopsscap := p2p.Cap{ 588 Name: "nopss", 589 Version: 1, 590 } 591 nid, _ = discover.HexID("0x02") 592 nopsspeer := network.NewPeer(&network.BzzPeer{ 593 Peer: protocols.NewPeer(p2p.NewPeer(nid, common.ToHex(nopssaddr.Over()), []p2p.Cap{nopsscap}), rw, nil), 594 BzzAddr: &network.BzzAddr{OAddr: nopssaddr.Over(), UAddr: nil}, 595 }, kad) 596 597 // add peers to kademlia and activate them 598 // it's safe so don't check errors 599 kad.Register(wrongpsspeer.BzzAddr) 600 kad.On(wrongpsspeer) 601 kad.Register(nopsspeer.BzzAddr) 602 kad.On(nopsspeer) 603 604 // create pss 605 pssmsg := &PssMsg{ 606 To: []byte{}, 607 Expire: uint32(time.Now().Add(time.Second).Unix()), 608 Payload: &whisper.Envelope{}, 609 } 610 ps := newTestPss(privkey, kad, nil) 611 612 // run the forward 613 // it is enough that it completes; trying to send to incapable peers would create segfault 614 ps.forward(pssmsg) 615 616 } 617 618 func TestSendRaw(t *testing.T) { 619 t.Run("32", testSendRaw) 620 t.Run("8", testSendRaw) 621 t.Run("0", testSendRaw) 622 } 623 624 func testSendRaw(t *testing.T) { 625 626 var addrsize int64 627 var err error 628 629 paramstring := strings.Split(t.Name(), "/") 630 631 addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) 632 log.Info("raw send test", "addrsize", addrsize) 633 634 clients, err := setupNetwork(2, true) 635 if err != nil { 636 t.Fatal(err) 637 } 638 639 topic := "0xdeadbeef" 640 641 var loaddrhex string 642 err = clients[0].Call(&loaddrhex, "pss_baseAddr") 643 if err != nil { 644 t.Fatalf("rpc get node 1 baseaddr fail: %v", err) 645 } 646 loaddrhex = loaddrhex[:2+(addrsize*2)] 647 var roaddrhex string 648 err = clients[1].Call(&roaddrhex, "pss_baseAddr") 649 if err != nil { 650 t.Fatalf("rpc get node 2 baseaddr fail: %v", err) 651 } 652 roaddrhex = roaddrhex[:2+(addrsize*2)] 653 654 time.Sleep(time.Millisecond * 500) 655 656 // at this point we've verified that symkeys are saved and match on each peer 657 // now try sending symmetrically encrypted message, both directions 658 lmsgC := make(chan APIMsg) 659 lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) 660 defer lcancel() 661 lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) 662 log.Trace("lsub", "id", lsub) 663 defer lsub.Unsubscribe() 664 rmsgC := make(chan APIMsg) 665 rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) 666 defer rcancel() 667 rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) 668 log.Trace("rsub", "id", rsub) 669 defer rsub.Unsubscribe() 670 671 // send and verify delivery 672 lmsg := []byte("plugh") 673 err = clients[1].Call(nil, "pss_sendRaw", loaddrhex, topic, lmsg) 674 if err != nil { 675 t.Fatal(err) 676 } 677 select { 678 case recvmsg := <-lmsgC: 679 if !bytes.Equal(recvmsg.Msg, lmsg) { 680 t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) 681 } 682 case cerr := <-lctx.Done(): 683 t.Fatalf("test message (left) timed out: %v", cerr) 684 } 685 rmsg := []byte("xyzzy") 686 err = clients[0].Call(nil, "pss_sendRaw", roaddrhex, topic, rmsg) 687 if err != nil { 688 t.Fatal(err) 689 } 690 select { 691 case recvmsg := <-rmsgC: 692 if !bytes.Equal(recvmsg.Msg, rmsg) { 693 t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) 694 } 695 case cerr := <-rctx.Done(): 696 t.Fatalf("test message (right) timed out: %v", cerr) 697 } 698 } 699 700 // send symmetrically encrypted message between two directly connected peers 701 func TestSendSym(t *testing.T) { 702 t.Run("32", testSendSym) 703 t.Run("8", testSendSym) 704 t.Run("0", testSendSym) 705 } 706 707 func testSendSym(t *testing.T) { 708 709 // address hint size 710 var addrsize int64 711 var err error 712 paramstring := strings.Split(t.Name(), "/") 713 addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) 714 log.Info("sym send test", "addrsize", addrsize) 715 716 clients, err := setupNetwork(2, false) 717 if err != nil { 718 t.Fatal(err) 719 } 720 721 var topic string 722 err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") 723 if err != nil { 724 t.Fatal(err) 725 } 726 727 var loaddrhex string 728 err = clients[0].Call(&loaddrhex, "pss_baseAddr") 729 if err != nil { 730 t.Fatalf("rpc get node 1 baseaddr fail: %v", err) 731 } 732 loaddrhex = loaddrhex[:2+(addrsize*2)] 733 var roaddrhex string 734 err = clients[1].Call(&roaddrhex, "pss_baseAddr") 735 if err != nil { 736 t.Fatalf("rpc get node 2 baseaddr fail: %v", err) 737 } 738 roaddrhex = roaddrhex[:2+(addrsize*2)] 739 740 // retrieve public key from pss instance 741 // set this public key reciprocally 742 var lpubkeyhex string 743 err = clients[0].Call(&lpubkeyhex, "pss_getPublicKey") 744 if err != nil { 745 t.Fatalf("rpc get node 1 pubkey fail: %v", err) 746 } 747 var rpubkeyhex string 748 err = clients[1].Call(&rpubkeyhex, "pss_getPublicKey") 749 if err != nil { 750 t.Fatalf("rpc get node 2 pubkey fail: %v", err) 751 } 752 753 time.Sleep(time.Millisecond * 500) 754 755 // at this point we've verified that symkeys are saved and match on each peer 756 // now try sending symmetrically encrypted message, both directions 757 lmsgC := make(chan APIMsg) 758 lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) 759 defer lcancel() 760 lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) 761 log.Trace("lsub", "id", lsub) 762 defer lsub.Unsubscribe() 763 rmsgC := make(chan APIMsg) 764 rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) 765 defer rcancel() 766 rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) 767 log.Trace("rsub", "id", rsub) 768 defer rsub.Unsubscribe() 769 770 lrecvkey := network.RandomAddr().Over() 771 rrecvkey := network.RandomAddr().Over() 772 773 var lkeyids [2]string 774 var rkeyids [2]string 775 776 // manually set reciprocal symkeys 777 err = clients[0].Call(&lkeyids, "psstest_setSymKeys", rpubkeyhex, lrecvkey, rrecvkey, defaultSymKeySendLimit, topic, roaddrhex) 778 if err != nil { 779 t.Fatal(err) 780 } 781 err = clients[1].Call(&rkeyids, "psstest_setSymKeys", lpubkeyhex, rrecvkey, lrecvkey, defaultSymKeySendLimit, topic, loaddrhex) 782 if err != nil { 783 t.Fatal(err) 784 } 785 786 // send and verify delivery 787 lmsg := []byte("plugh") 788 err = clients[1].Call(nil, "pss_sendSym", rkeyids[1], topic, hexutil.Encode(lmsg)) 789 if err != nil { 790 t.Fatal(err) 791 } 792 select { 793 case recvmsg := <-lmsgC: 794 if !bytes.Equal(recvmsg.Msg, lmsg) { 795 t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg) 796 } 797 case cerr := <-lctx.Done(): 798 t.Fatalf("test message timed out: %v", cerr) 799 } 800 rmsg := []byte("xyzzy") 801 err = clients[0].Call(nil, "pss_sendSym", lkeyids[1], topic, hexutil.Encode(rmsg)) 802 if err != nil { 803 t.Fatal(err) 804 } 805 select { 806 case recvmsg := <-rmsgC: 807 if !bytes.Equal(recvmsg.Msg, rmsg) { 808 t.Fatalf("node 2 received payload mismatch: expected %x, got %v", rmsg, recvmsg.Msg) 809 } 810 case cerr := <-rctx.Done(): 811 t.Fatalf("test message timed out: %v", cerr) 812 } 813 } 814 815 // send asymmetrically encrypted message between two directly connected peers 816 func TestSendAsym(t *testing.T) { 817 t.Run("32", testSendAsym) 818 t.Run("8", testSendAsym) 819 t.Run("0", testSendAsym) 820 } 821 822 func testSendAsym(t *testing.T) { 823 824 // address hint size 825 var addrsize int64 826 var err error 827 paramstring := strings.Split(t.Name(), "/") 828 addrsize, _ = strconv.ParseInt(paramstring[1], 10, 0) 829 log.Info("asym send test", "addrsize", addrsize) 830 831 clients, err := setupNetwork(2, false) 832 if err != nil { 833 t.Fatal(err) 834 } 835 836 var topic string 837 err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") 838 if err != nil { 839 t.Fatal(err) 840 } 841 842 time.Sleep(time.Millisecond * 250) 843 844 var loaddrhex string 845 err = clients[0].Call(&loaddrhex, "pss_baseAddr") 846 if err != nil { 847 t.Fatalf("rpc get node 1 baseaddr fail: %v", err) 848 } 849 loaddrhex = loaddrhex[:2+(addrsize*2)] 850 var roaddrhex string 851 err = clients[1].Call(&roaddrhex, "pss_baseAddr") 852 if err != nil { 853 t.Fatalf("rpc get node 2 baseaddr fail: %v", err) 854 } 855 roaddrhex = roaddrhex[:2+(addrsize*2)] 856 857 // retrieve public key from pss instance 858 // set this public key reciprocally 859 var lpubkey string 860 err = clients[0].Call(&lpubkey, "pss_getPublicKey") 861 if err != nil { 862 t.Fatalf("rpc get node 1 pubkey fail: %v", err) 863 } 864 var rpubkey string 865 err = clients[1].Call(&rpubkey, "pss_getPublicKey") 866 if err != nil { 867 t.Fatalf("rpc get node 2 pubkey fail: %v", err) 868 } 869 870 time.Sleep(time.Millisecond * 500) // replace with hive healthy code 871 872 lmsgC := make(chan APIMsg) 873 lctx, lcancel := context.WithTimeout(context.Background(), time.Second*10) 874 defer lcancel() 875 lsub, err := clients[0].Subscribe(lctx, "pss", lmsgC, "receive", topic) 876 log.Trace("lsub", "id", lsub) 877 defer lsub.Unsubscribe() 878 rmsgC := make(chan APIMsg) 879 rctx, rcancel := context.WithTimeout(context.Background(), time.Second*10) 880 defer rcancel() 881 rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) 882 log.Trace("rsub", "id", rsub) 883 defer rsub.Unsubscribe() 884 885 // store reciprocal public keys 886 err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, roaddrhex) 887 if err != nil { 888 t.Fatal(err) 889 } 890 err = clients[1].Call(nil, "pss_setPeerPublicKey", lpubkey, topic, loaddrhex) 891 if err != nil { 892 t.Fatal(err) 893 } 894 895 // send and verify delivery 896 rmsg := []byte("xyzzy") 897 err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) 898 if err != nil { 899 t.Fatal(err) 900 } 901 select { 902 case recvmsg := <-rmsgC: 903 if !bytes.Equal(recvmsg.Msg, rmsg) { 904 t.Fatalf("node 2 received payload mismatch: expected %v, got %v", rmsg, recvmsg.Msg) 905 } 906 case cerr := <-rctx.Done(): 907 t.Fatalf("test message timed out: %v", cerr) 908 } 909 lmsg := []byte("plugh") 910 err = clients[1].Call(nil, "pss_sendAsym", lpubkey, topic, hexutil.Encode(lmsg)) 911 if err != nil { 912 t.Fatal(err) 913 } 914 select { 915 case recvmsg := <-lmsgC: 916 if !bytes.Equal(recvmsg.Msg, lmsg) { 917 t.Fatalf("node 1 received payload mismatch: expected %v, got %v", lmsg, recvmsg.Msg) 918 } 919 case cerr := <-lctx.Done(): 920 t.Fatalf("test message timed out: %v", cerr) 921 } 922 } 923 924 type Job struct { 925 Msg []byte 926 SendNode discover.NodeID 927 RecvNode discover.NodeID 928 } 929 930 func worker(id int, jobs <-chan Job, rpcs map[discover.NodeID]*rpc.Client, pubkeys map[discover.NodeID]string, topic string) { 931 for j := range jobs { 932 rpcs[j.SendNode].Call(nil, "pss_sendAsym", pubkeys[j.RecvNode], topic, hexutil.Encode(j.Msg)) 933 } 934 } 935 936 func TestNetwork(t *testing.T) { 937 t.Run("16/1000/4/sim", testNetwork) 938 } 939 940 // params in run name: 941 // nodes/msgs/addrbytes/adaptertype 942 // if adaptertype is exec uses execadapter, simadapter otherwise 943 func TestNetwork2000(t *testing.T) { 944 //enableMetrics() 945 946 if !*longrunning { 947 t.Skip("run with --longrunning flag to run extensive network tests") 948 } 949 t.Run("3/2000/4/sim", testNetwork) 950 t.Run("4/2000/4/sim", testNetwork) 951 t.Run("8/2000/4/sim", testNetwork) 952 t.Run("16/2000/4/sim", testNetwork) 953 } 954 955 func TestNetwork5000(t *testing.T) { 956 //enableMetrics() 957 958 if !*longrunning { 959 t.Skip("run with --longrunning flag to run extensive network tests") 960 } 961 t.Run("3/5000/4/sim", testNetwork) 962 t.Run("4/5000/4/sim", testNetwork) 963 t.Run("8/5000/4/sim", testNetwork) 964 t.Run("16/5000/4/sim", testNetwork) 965 } 966 967 func TestNetwork10000(t *testing.T) { 968 //enableMetrics() 969 970 if !*longrunning { 971 t.Skip("run with --longrunning flag to run extensive network tests") 972 } 973 t.Run("3/10000/4/sim", testNetwork) 974 t.Run("4/10000/4/sim", testNetwork) 975 t.Run("8/10000/4/sim", testNetwork) 976 } 977 978 func testNetwork(t *testing.T) { 979 type msgnotifyC struct { 980 id discover.NodeID 981 msgIdx int 982 } 983 984 paramstring := strings.Split(t.Name(), "/") 985 nodecount, _ := strconv.ParseInt(paramstring[1], 10, 0) 986 msgcount, _ := strconv.ParseInt(paramstring[2], 10, 0) 987 addrsize, _ := strconv.ParseInt(paramstring[3], 10, 0) 988 adapter := paramstring[4] 989 990 log.Info("network test", "nodecount", nodecount, "msgcount", msgcount, "addrhintsize", addrsize) 991 992 nodes := make([]discover.NodeID, nodecount) 993 bzzaddrs := make(map[discover.NodeID]string, nodecount) 994 rpcs := make(map[discover.NodeID]*rpc.Client, nodecount) 995 pubkeys := make(map[discover.NodeID]string, nodecount) 996 997 sentmsgs := make([][]byte, msgcount) 998 recvmsgs := make([]bool, msgcount) 999 nodemsgcount := make(map[discover.NodeID]int, nodecount) 1000 1001 trigger := make(chan discover.NodeID) 1002 1003 var a adapters.NodeAdapter 1004 if adapter == "exec" { 1005 dirname, err := ioutil.TempDir(".", "") 1006 if err != nil { 1007 t.Fatal(err) 1008 } 1009 a = adapters.NewExecAdapter(dirname) 1010 } else if adapter == "tcp" { 1011 a = adapters.NewTCPAdapter(newServices(false)) 1012 } else if adapter == "sim" { 1013 a = adapters.NewSimAdapter(newServices(false)) 1014 } 1015 net := simulations.NewNetwork(a, &simulations.NetworkConfig{ 1016 ID: "0", 1017 }) 1018 defer net.Shutdown() 1019 1020 f, err := os.Open(fmt.Sprintf("testdata/snapshot_%d.json", nodecount)) 1021 if err != nil { 1022 t.Fatal(err) 1023 } 1024 jsonbyte, err := ioutil.ReadAll(f) 1025 if err != nil { 1026 t.Fatal(err) 1027 } 1028 var snap simulations.Snapshot 1029 err = json.Unmarshal(jsonbyte, &snap) 1030 if err != nil { 1031 t.Fatal(err) 1032 } 1033 err = net.Load(&snap) 1034 if err != nil { 1035 //TODO: Fix p2p simulation framework to not crash when loading 32-nodes 1036 //t.Fatal(err) 1037 } 1038 1039 time.Sleep(1 * time.Second) 1040 1041 triggerChecks := func(trigger chan discover.NodeID, id discover.NodeID, rpcclient *rpc.Client, topic string) error { 1042 msgC := make(chan APIMsg) 1043 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 1044 defer cancel() 1045 sub, err := rpcclient.Subscribe(ctx, "pss", msgC, "receive", topic) 1046 if err != nil { 1047 t.Fatal(err) 1048 } 1049 go func() { 1050 defer sub.Unsubscribe() 1051 for { 1052 select { 1053 case recvmsg := <-msgC: 1054 idx, _ := binary.Uvarint(recvmsg.Msg) 1055 if !recvmsgs[idx] { 1056 log.Debug("msg recv", "idx", idx, "id", id) 1057 recvmsgs[idx] = true 1058 trigger <- id 1059 } 1060 case <-sub.Err(): 1061 return 1062 } 1063 } 1064 }() 1065 return nil 1066 } 1067 1068 var topic string 1069 for i, nod := range net.GetNodes() { 1070 nodes[i] = nod.ID() 1071 rpcs[nodes[i]], err = nod.Client() 1072 if err != nil { 1073 t.Fatal(err) 1074 } 1075 if topic == "" { 1076 err = rpcs[nodes[i]].Call(&topic, "pss_stringToTopic", "foo:42") 1077 if err != nil { 1078 t.Fatal(err) 1079 } 1080 } 1081 var pubkey string 1082 err = rpcs[nodes[i]].Call(&pubkey, "pss_getPublicKey") 1083 if err != nil { 1084 t.Fatal(err) 1085 } 1086 pubkeys[nod.ID()] = pubkey 1087 var addrhex string 1088 err = rpcs[nodes[i]].Call(&addrhex, "pss_baseAddr") 1089 if err != nil { 1090 t.Fatal(err) 1091 } 1092 bzzaddrs[nodes[i]] = addrhex 1093 err = triggerChecks(trigger, nodes[i], rpcs[nodes[i]], topic) 1094 if err != nil { 1095 t.Fatal(err) 1096 } 1097 } 1098 1099 time.Sleep(1 * time.Second) 1100 1101 // setup workers 1102 jobs := make(chan Job, 10) 1103 for w := 1; w <= 10; w++ { 1104 go worker(w, jobs, rpcs, pubkeys, topic) 1105 } 1106 1107 time.Sleep(1 * time.Second) 1108 1109 for i := 0; i < int(msgcount); i++ { 1110 sendnodeidx := rand.Intn(int(nodecount)) 1111 recvnodeidx := rand.Intn(int(nodecount - 1)) 1112 if recvnodeidx >= sendnodeidx { 1113 recvnodeidx++ 1114 } 1115 nodemsgcount[nodes[recvnodeidx]]++ 1116 sentmsgs[i] = make([]byte, 8) 1117 c := binary.PutUvarint(sentmsgs[i], uint64(i)) 1118 if c == 0 { 1119 t.Fatal("0 byte message") 1120 } 1121 if err != nil { 1122 t.Fatal(err) 1123 } 1124 err = rpcs[nodes[sendnodeidx]].Call(nil, "pss_setPeerPublicKey", pubkeys[nodes[recvnodeidx]], topic, bzzaddrs[nodes[recvnodeidx]]) 1125 if err != nil { 1126 t.Fatal(err) 1127 } 1128 1129 jobs <- Job{ 1130 Msg: sentmsgs[i], 1131 SendNode: nodes[sendnodeidx], 1132 RecvNode: nodes[recvnodeidx], 1133 } 1134 } 1135 1136 finalmsgcount := 0 1137 ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) 1138 defer cancel() 1139 outer: 1140 for i := 0; i < int(msgcount); i++ { 1141 select { 1142 case id := <-trigger: 1143 nodemsgcount[id]-- 1144 finalmsgcount++ 1145 case <-ctx.Done(): 1146 log.Warn("timeout") 1147 break outer 1148 } 1149 } 1150 1151 for i, msg := range recvmsgs { 1152 if !msg { 1153 log.Debug("missing message", "idx", i) 1154 } 1155 } 1156 t.Logf("%d of %d messages received", finalmsgcount, msgcount) 1157 1158 if finalmsgcount != int(msgcount) { 1159 t.Fatalf("%d messages were not received", int(msgcount)-finalmsgcount) 1160 } 1161 1162 } 1163 1164 // check that in a network of a -> b -> c -> a 1165 // a doesn't receive a sent message twice 1166 func TestDeduplication(t *testing.T) { 1167 var err error 1168 1169 clients, err := setupNetwork(3, false) 1170 if err != nil { 1171 t.Fatal(err) 1172 } 1173 1174 var addrsize = 32 1175 var loaddrhex string 1176 err = clients[0].Call(&loaddrhex, "pss_baseAddr") 1177 if err != nil { 1178 t.Fatalf("rpc get node 1 baseaddr fail: %v", err) 1179 } 1180 loaddrhex = loaddrhex[:2+(addrsize*2)] 1181 var roaddrhex string 1182 err = clients[1].Call(&roaddrhex, "pss_baseAddr") 1183 if err != nil { 1184 t.Fatalf("rpc get node 2 baseaddr fail: %v", err) 1185 } 1186 roaddrhex = roaddrhex[:2+(addrsize*2)] 1187 var xoaddrhex string 1188 err = clients[2].Call(&xoaddrhex, "pss_baseAddr") 1189 if err != nil { 1190 t.Fatalf("rpc get node 3 baseaddr fail: %v", err) 1191 } 1192 xoaddrhex = xoaddrhex[:2+(addrsize*2)] 1193 1194 log.Info("peer", "l", loaddrhex, "r", roaddrhex, "x", xoaddrhex) 1195 1196 var topic string 1197 err = clients[0].Call(&topic, "pss_stringToTopic", "foo:42") 1198 if err != nil { 1199 t.Fatal(err) 1200 } 1201 1202 time.Sleep(time.Millisecond * 250) 1203 1204 // retrieve public key from pss instance 1205 // set this public key reciprocally 1206 var rpubkey string 1207 err = clients[1].Call(&rpubkey, "pss_getPublicKey") 1208 if err != nil { 1209 t.Fatalf("rpc get receivenode pubkey fail: %v", err) 1210 } 1211 1212 time.Sleep(time.Millisecond * 500) // replace with hive healthy code 1213 1214 rmsgC := make(chan APIMsg) 1215 rctx, cancel := context.WithTimeout(context.Background(), time.Second*1) 1216 defer cancel() 1217 rsub, err := clients[1].Subscribe(rctx, "pss", rmsgC, "receive", topic) 1218 log.Trace("rsub", "id", rsub) 1219 defer rsub.Unsubscribe() 1220 1221 // store public key for recipient 1222 // zero-length address means forward to all 1223 // we have just two peers, they will be in proxbin, and will both receive 1224 err = clients[0].Call(nil, "pss_setPeerPublicKey", rpubkey, topic, "0x") 1225 if err != nil { 1226 t.Fatal(err) 1227 } 1228 1229 // send and verify delivery 1230 rmsg := []byte("xyzzy") 1231 err = clients[0].Call(nil, "pss_sendAsym", rpubkey, topic, hexutil.Encode(rmsg)) 1232 if err != nil { 1233 t.Fatal(err) 1234 } 1235 1236 var receivedok bool 1237 OUTER: 1238 for { 1239 select { 1240 case <-rmsgC: 1241 if receivedok { 1242 t.Fatalf("duplicate message received") 1243 } 1244 receivedok = true 1245 case <-rctx.Done(): 1246 break OUTER 1247 } 1248 } 1249 if !receivedok { 1250 t.Fatalf("message did not arrive") 1251 } 1252 } 1253 1254 // symmetric send performance with varying message sizes 1255 func BenchmarkSymkeySend(b *testing.B) { 1256 b.Run(fmt.Sprintf("%d", 256), benchmarkSymKeySend) 1257 b.Run(fmt.Sprintf("%d", 1024), benchmarkSymKeySend) 1258 b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkSymKeySend) 1259 b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkSymKeySend) 1260 b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkSymKeySend) 1261 } 1262 1263 func benchmarkSymKeySend(b *testing.B) { 1264 msgsizestring := strings.Split(b.Name(), "/") 1265 if len(msgsizestring) != 2 { 1266 b.Fatalf("benchmark called without msgsize param") 1267 } 1268 msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) 1269 if err != nil { 1270 b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) 1271 } 1272 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 1273 defer cancel() 1274 keys, err := wapi.NewKeyPair(ctx) 1275 privkey, err := w.GetPrivateKey(keys) 1276 ps := newTestPss(privkey, nil, nil) 1277 msg := make([]byte, msgsize) 1278 rand.Read(msg) 1279 topic := BytesToTopic([]byte("foo")) 1280 to := make(PssAddress, 32) 1281 copy(to[:], network.RandomAddr().Over()) 1282 symkeyid, err := ps.GenerateSymmetricKey(topic, &to, true) 1283 if err != nil { 1284 b.Fatalf("could not generate symkey: %v", err) 1285 } 1286 symkey, err := ps.w.GetSymKey(symkeyid) 1287 if err != nil { 1288 b.Fatalf("could not retrieve symkey: %v", err) 1289 } 1290 ps.SetSymmetricKey(symkey, topic, &to, false) 1291 1292 b.ResetTimer() 1293 for i := 0; i < b.N; i++ { 1294 ps.SendSym(symkeyid, topic, msg) 1295 } 1296 } 1297 1298 // asymmetric send performance with varying message sizes 1299 func BenchmarkAsymkeySend(b *testing.B) { 1300 b.Run(fmt.Sprintf("%d", 256), benchmarkAsymKeySend) 1301 b.Run(fmt.Sprintf("%d", 1024), benchmarkAsymKeySend) 1302 b.Run(fmt.Sprintf("%d", 1024*1024), benchmarkAsymKeySend) 1303 b.Run(fmt.Sprintf("%d", 1024*1024*10), benchmarkAsymKeySend) 1304 b.Run(fmt.Sprintf("%d", 1024*1024*100), benchmarkAsymKeySend) 1305 } 1306 1307 func benchmarkAsymKeySend(b *testing.B) { 1308 msgsizestring := strings.Split(b.Name(), "/") 1309 if len(msgsizestring) != 2 { 1310 b.Fatalf("benchmark called without msgsize param") 1311 } 1312 msgsize, err := strconv.ParseInt(msgsizestring[1], 10, 0) 1313 if err != nil { 1314 b.Fatalf("benchmark called with invalid msgsize param '%s': %v", msgsizestring[1], err) 1315 } 1316 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 1317 defer cancel() 1318 keys, err := wapi.NewKeyPair(ctx) 1319 privkey, err := w.GetPrivateKey(keys) 1320 ps := newTestPss(privkey, nil, nil) 1321 msg := make([]byte, msgsize) 1322 rand.Read(msg) 1323 topic := BytesToTopic([]byte("foo")) 1324 to := make(PssAddress, 32) 1325 copy(to[:], network.RandomAddr().Over()) 1326 ps.SetPeerPublicKey(&privkey.PublicKey, topic, &to) 1327 b.ResetTimer() 1328 for i := 0; i < b.N; i++ { 1329 ps.SendAsym(common.ToHex(crypto.FromECDSAPub(&privkey.PublicKey)), topic, msg) 1330 } 1331 } 1332 func BenchmarkSymkeyBruteforceChangeaddr(b *testing.B) { 1333 for i := 100; i < 100000; i = i * 10 { 1334 for j := 32; j < 10000; j = j * 8 { 1335 b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceChangeaddr) 1336 } 1337 //b.Run(fmt.Sprintf("%d", i), benchmarkSymkeyBruteforceChangeaddr) 1338 } 1339 } 1340 1341 // decrypt performance using symkey cache, worst case 1342 // (decrypt key always last in cache) 1343 func benchmarkSymkeyBruteforceChangeaddr(b *testing.B) { 1344 keycountstring := strings.Split(b.Name(), "/") 1345 cachesize := int64(0) 1346 var ps *Pss 1347 if len(keycountstring) < 2 { 1348 b.Fatalf("benchmark called without count param") 1349 } 1350 keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) 1351 if err != nil { 1352 b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) 1353 } 1354 if len(keycountstring) == 3 { 1355 cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) 1356 if err != nil { 1357 b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) 1358 } 1359 } 1360 pssmsgs := make([]*PssMsg, 0, keycount) 1361 var keyid string 1362 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 1363 defer cancel() 1364 keys, err := wapi.NewKeyPair(ctx) 1365 privkey, err := w.GetPrivateKey(keys) 1366 if cachesize > 0 { 1367 ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) 1368 } else { 1369 ps = newTestPss(privkey, nil, nil) 1370 } 1371 topic := BytesToTopic([]byte("foo")) 1372 for i := 0; i < int(keycount); i++ { 1373 to := make(PssAddress, 32) 1374 copy(to[:], network.RandomAddr().Over()) 1375 keyid, err = ps.GenerateSymmetricKey(topic, &to, true) 1376 if err != nil { 1377 b.Fatalf("cant generate symkey #%d: %v", i, err) 1378 } 1379 symkey, err := ps.w.GetSymKey(keyid) 1380 if err != nil { 1381 b.Fatalf("could not retrieve symkey %s: %v", keyid, err) 1382 } 1383 wparams := &whisper.MessageParams{ 1384 TTL: defaultWhisperTTL, 1385 KeySym: symkey, 1386 Topic: whisper.TopicType(topic), 1387 WorkTime: defaultWhisperWorkTime, 1388 PoW: defaultWhisperPoW, 1389 Payload: []byte("xyzzy"), 1390 Padding: []byte("1234567890abcdef"), 1391 } 1392 woutmsg, err := whisper.NewSentMessage(wparams) 1393 if err != nil { 1394 b.Fatalf("could not create whisper message: %v", err) 1395 } 1396 env, err := woutmsg.Wrap(wparams) 1397 if err != nil { 1398 b.Fatalf("could not generate whisper envelope: %v", err) 1399 } 1400 ps.Register(&topic, func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { 1401 return nil 1402 }) 1403 pssmsgs = append(pssmsgs, &PssMsg{ 1404 To: to, 1405 Payload: env, 1406 }) 1407 } 1408 b.ResetTimer() 1409 for i := 0; i < b.N; i++ { 1410 if err := ps.process(pssmsgs[len(pssmsgs)-(i%len(pssmsgs))-1]); err != nil { 1411 b.Fatalf("pss processing failed: %v", err) 1412 } 1413 } 1414 } 1415 1416 func BenchmarkSymkeyBruteforceSameaddr(b *testing.B) { 1417 for i := 100; i < 100000; i = i * 10 { 1418 for j := 32; j < 10000; j = j * 8 { 1419 b.Run(fmt.Sprintf("%d/%d", i, j), benchmarkSymkeyBruteforceSameaddr) 1420 } 1421 } 1422 } 1423 1424 // decrypt performance using symkey cache, best case 1425 // (decrypt key always first in cache) 1426 func benchmarkSymkeyBruteforceSameaddr(b *testing.B) { 1427 var keyid string 1428 var ps *Pss 1429 cachesize := int64(0) 1430 keycountstring := strings.Split(b.Name(), "/") 1431 if len(keycountstring) < 2 { 1432 b.Fatalf("benchmark called without count param") 1433 } 1434 keycount, err := strconv.ParseInt(keycountstring[1], 10, 0) 1435 if err != nil { 1436 b.Fatalf("benchmark called with invalid count param '%s': %v", keycountstring[1], err) 1437 } 1438 if len(keycountstring) == 3 { 1439 cachesize, err = strconv.ParseInt(keycountstring[2], 10, 0) 1440 if err != nil { 1441 b.Fatalf("benchmark called with invalid cachesize '%s': %v", keycountstring[2], err) 1442 } 1443 } 1444 addr := make([]PssAddress, keycount) 1445 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 1446 defer cancel() 1447 keys, err := wapi.NewKeyPair(ctx) 1448 privkey, err := w.GetPrivateKey(keys) 1449 if cachesize > 0 { 1450 ps = newTestPss(privkey, nil, &PssParams{SymKeyCacheCapacity: int(cachesize)}) 1451 } else { 1452 ps = newTestPss(privkey, nil, nil) 1453 } 1454 topic := BytesToTopic([]byte("foo")) 1455 for i := 0; i < int(keycount); i++ { 1456 copy(addr[i], network.RandomAddr().Over()) 1457 keyid, err = ps.GenerateSymmetricKey(topic, &addr[i], true) 1458 if err != nil { 1459 b.Fatalf("cant generate symkey #%d: %v", i, err) 1460 } 1461 1462 } 1463 symkey, err := ps.w.GetSymKey(keyid) 1464 if err != nil { 1465 b.Fatalf("could not retrieve symkey %s: %v", keyid, err) 1466 } 1467 wparams := &whisper.MessageParams{ 1468 TTL: defaultWhisperTTL, 1469 KeySym: symkey, 1470 Topic: whisper.TopicType(topic), 1471 WorkTime: defaultWhisperWorkTime, 1472 PoW: defaultWhisperPoW, 1473 Payload: []byte("xyzzy"), 1474 Padding: []byte("1234567890abcdef"), 1475 } 1476 woutmsg, err := whisper.NewSentMessage(wparams) 1477 if err != nil { 1478 b.Fatalf("could not create whisper message: %v", err) 1479 } 1480 env, err := woutmsg.Wrap(wparams) 1481 if err != nil { 1482 b.Fatalf("could not generate whisper envelope: %v", err) 1483 } 1484 ps.Register(&topic, func(msg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { 1485 return nil 1486 }) 1487 pssmsg := &PssMsg{ 1488 To: addr[len(addr)-1][:], 1489 Payload: env, 1490 } 1491 for i := 0; i < b.N; i++ { 1492 if err := ps.process(pssmsg); err != nil { 1493 b.Fatalf("pss processing failed: %v", err) 1494 } 1495 } 1496 } 1497 1498 // setup simulated network with bzz/discovery and pss services. 1499 // connects nodes in a circle 1500 // if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) 1501 func setupNetwork(numnodes int, allowRaw bool) (clients []*rpc.Client, err error) { 1502 nodes := make([]*simulations.Node, numnodes) 1503 clients = make([]*rpc.Client, numnodes) 1504 if numnodes < 2 { 1505 return nil, fmt.Errorf("Minimum two nodes in network") 1506 } 1507 adapter := adapters.NewSimAdapter(newServices(allowRaw)) 1508 net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 1509 ID: "0", 1510 DefaultService: "bzz", 1511 }) 1512 for i := 0; i < numnodes; i++ { 1513 nodeconf := adapters.RandomNodeConfig() 1514 nodeconf.Services = []string{"bzz", pssProtocolName} 1515 nodes[i], err = net.NewNodeWithConfig(nodeconf) 1516 if err != nil { 1517 return nil, fmt.Errorf("error creating node 1: %v", err) 1518 } 1519 err = net.Start(nodes[i].ID()) 1520 if err != nil { 1521 return nil, fmt.Errorf("error starting node 1: %v", err) 1522 } 1523 if i > 0 { 1524 err = net.Connect(nodes[i].ID(), nodes[i-1].ID()) 1525 if err != nil { 1526 return nil, fmt.Errorf("error connecting nodes: %v", err) 1527 } 1528 } 1529 clients[i], err = nodes[i].Client() 1530 if err != nil { 1531 return nil, fmt.Errorf("create node 1 rpc client fail: %v", err) 1532 } 1533 } 1534 if numnodes > 2 { 1535 err = net.Connect(nodes[0].ID(), nodes[len(nodes)-1].ID()) 1536 if err != nil { 1537 return nil, fmt.Errorf("error connecting first and last nodes") 1538 } 1539 } 1540 return clients, nil 1541 } 1542 1543 func newServices(allowRaw bool) adapters.Services { 1544 stateStore := state.NewInmemoryStore() 1545 kademlias := make(map[discover.NodeID]*network.Kademlia) 1546 kademlia := func(id discover.NodeID) *network.Kademlia { 1547 if k, ok := kademlias[id]; ok { 1548 return k 1549 } 1550 addr := network.NewAddrFromNodeID(id) 1551 params := network.NewKadParams() 1552 params.MinProxBinSize = 2 1553 params.MaxBinSize = 3 1554 params.MinBinSize = 1 1555 params.MaxRetries = 1000 1556 params.RetryExponent = 2 1557 params.RetryInterval = 1000000 1558 kademlias[id] = network.NewKademlia(addr.Over(), params) 1559 return kademlias[id] 1560 } 1561 return adapters.Services{ 1562 pssProtocolName: func(ctx *adapters.ServiceContext) (node.Service, error) { 1563 // execadapter does not exec init() 1564 initTest() 1565 1566 ctxlocal, cancel := context.WithTimeout(context.Background(), time.Second) 1567 defer cancel() 1568 keys, err := wapi.NewKeyPair(ctxlocal) 1569 privkey, err := w.GetPrivateKey(keys) 1570 pssp := NewPssParams().WithPrivateKey(privkey) 1571 pssp.AllowRaw = allowRaw 1572 pskad := kademlia(ctx.Config.ID) 1573 ps, err := NewPss(pskad, pssp) 1574 if err != nil { 1575 return nil, err 1576 } 1577 1578 ping := &Ping{ 1579 OutC: make(chan bool), 1580 Pong: true, 1581 } 1582 p2pp := NewPingProtocol(ping) 1583 pp, err := RegisterProtocol(ps, &PingTopic, PingProtocol, p2pp, &ProtocolParams{Asymmetric: true}) 1584 if err != nil { 1585 return nil, err 1586 } 1587 if useHandshake { 1588 SetHandshakeController(ps, NewHandshakeParams()) 1589 } 1590 ps.Register(&PingTopic, pp.Handle) 1591 ps.addAPI(rpc.API{ 1592 Namespace: "psstest", 1593 Version: "0.3", 1594 Service: NewAPITest(ps), 1595 Public: false, 1596 }) 1597 if err != nil { 1598 log.Error("Couldnt register pss protocol", "err", err) 1599 os.Exit(1) 1600 } 1601 pssprotocols[ctx.Config.ID.String()] = &protoCtrl{ 1602 C: ping.OutC, 1603 protocol: pp, 1604 run: p2pp.Run, 1605 } 1606 return ps, nil 1607 }, 1608 "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { 1609 addr := network.NewAddrFromNodeID(ctx.Config.ID) 1610 hp := network.NewHiveParams() 1611 hp.Discovery = false 1612 config := &network.BzzConfig{ 1613 OverlayAddr: addr.Over(), 1614 UnderlayAddr: addr.Under(), 1615 HiveParams: hp, 1616 } 1617 return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil 1618 }, 1619 } 1620 } 1621 1622 func newTestPss(privkey *ecdsa.PrivateKey, kad *network.Kademlia, ppextra *PssParams) *Pss { 1623 1624 var nid discover.NodeID 1625 copy(nid[:], crypto.FromECDSAPub(&privkey.PublicKey)) 1626 addr := network.NewAddrFromNodeID(nid) 1627 1628 // set up routing if kademlia is not passed to us 1629 if kad == nil { 1630 kp := network.NewKadParams() 1631 kp.MinProxBinSize = 3 1632 kad = network.NewKademlia(addr.Over(), kp) 1633 } 1634 1635 // create pss 1636 pp := NewPssParams().WithPrivateKey(privkey) 1637 if ppextra != nil { 1638 pp.SymKeyCacheCapacity = ppextra.SymKeyCacheCapacity 1639 } 1640 ps, err := NewPss(kad, pp) 1641 if err != nil { 1642 return nil 1643 } 1644 ps.Start(nil) 1645 1646 return ps 1647 } 1648 1649 // API calls for test/development use 1650 type APITest struct { 1651 *Pss 1652 } 1653 1654 func NewAPITest(ps *Pss) *APITest { 1655 return &APITest{Pss: ps} 1656 } 1657 1658 func (apitest *APITest) SetSymKeys(pubkeyid string, recvsymkey []byte, sendsymkey []byte, limit uint16, topic Topic, to PssAddress) ([2]string, error) { 1659 recvsymkeyid, err := apitest.SetSymmetricKey(recvsymkey, topic, &to, true) 1660 if err != nil { 1661 return [2]string{}, err 1662 } 1663 sendsymkeyid, err := apitest.SetSymmetricKey(sendsymkey, topic, &to, false) 1664 if err != nil { 1665 return [2]string{}, err 1666 } 1667 return [2]string{recvsymkeyid, sendsymkeyid}, nil 1668 } 1669 1670 func (apitest *APITest) Clean() (int, error) { 1671 return apitest.Pss.cleanKeys(), nil 1672 } 1673 1674 // enableMetrics is starting InfluxDB reporter so that we collect stats when running tests locally 1675 func enableMetrics() { 1676 metrics.Enabled = true 1677 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 1*time.Second, "http://localhost:8086", "metrics", "admin", "admin", "swarm.", map[string]string{ 1678 "host": "test", 1679 }) 1680 }