github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/cmd/wnode/main.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 // This is a simple Whisper node. It could be used as a stand-alone bootstrap node. 18 // Also, could be used for different test and diagnostics purposes. 19 20 package main 21 22 import ( 23 "bufio" 24 "crypto/ecdsa" 25 crand "crypto/rand" 26 "crypto/sha512" 27 "encoding/binary" 28 "encoding/hex" 29 "flag" 30 "fmt" 31 "io/ioutil" 32 "os" 33 "path/filepath" 34 "strconv" 35 "strings" 36 "time" 37 38 "github.com/insight-chain/inb-go/cmd/utils" 39 "github.com/insight-chain/inb-go/common" 40 "github.com/insight-chain/inb-go/console" 41 "github.com/insight-chain/inb-go/crypto" 42 "github.com/insight-chain/inb-go/log" 43 "github.com/insight-chain/inb-go/p2p" 44 "github.com/insight-chain/inb-go/p2p/enode" 45 "github.com/insight-chain/inb-go/p2p/nat" 46 "github.com/insight-chain/inb-go/whisper/mailserver" 47 whisper "github.com/insight-chain/inb-go/whisper/whisperv6" 48 "golang.org/x/crypto/pbkdf2" 49 ) 50 51 const quitCommand = "~Q" 52 const entropySize = 32 53 54 // singletons 55 var ( 56 server *p2p.Server 57 shh *whisper.Whisper 58 done chan struct{} 59 mailServer mailserver.WMailServer 60 entropy [entropySize]byte 61 62 input = bufio.NewReader(os.Stdin) 63 ) 64 65 // encryption 66 var ( 67 symKey []byte 68 pub *ecdsa.PublicKey 69 asymKey *ecdsa.PrivateKey 70 nodeid *ecdsa.PrivateKey 71 topic whisper.TopicType 72 73 asymKeyID string 74 asymFilterID string 75 symFilterID string 76 symPass string 77 msPassword string 78 ) 79 80 // cmd arguments 81 var ( 82 bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't initiate connection to peers, just wait for incoming connections") 83 forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither encrypt nor decrypt messages") 84 mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand") 85 requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server") 86 asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption") 87 generateKey = flag.Bool("generatekey", false, "generate and show the private key") 88 fileExMode = flag.Bool("fileexchange", false, "file exchange mode") 89 fileReader = flag.Bool("filereader", false, "load and decrypt messages saved as files, display as plain text") 90 testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics (password, etc.)") 91 echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics") 92 93 argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level") 94 argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds") 95 argWorkTime = flag.Uint("work", 5, "work time in seconds") 96 argMaxSize = flag.Uint("maxsize", uint(whisper.DefaultMaxMessageSize), "max size of message") 97 argPoW = flag.Float64("pow", whisper.DefaultMinimumPoW, "PoW for normal messages in float format (e.g. 2.7)") 98 argServerPoW = flag.Float64("mspow", whisper.DefaultMinimumPoW, "PoW requirement for Mail Server request") 99 100 argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:30303)") 101 argPub = flag.String("pub", "", "public key for asymmetric encryption") 102 argDBPath = flag.String("dbpath", "", "path to the server's DB directory") 103 argIDFile = flag.String("idfile", "", "file name with node id (private key)") 104 argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)") 105 argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)") 106 argSaveDir = flag.String("savedir", "", "directory where all incoming messages will be saved as files") 107 ) 108 109 110 // main 111 func main() { 112 processArgs() 113 initialize() 114 run() 115 shutdown() 116 } 117 118 func processArgs() { 119 flag.Parse() 120 121 if len(*argIDFile) > 0 { 122 var err error 123 nodeid, err = crypto.LoadECDSA(*argIDFile) 124 if err != nil { 125 utils.Fatalf("Failed to load file [%s]: %s.", *argIDFile, err) 126 } 127 } 128 129 const enodePrefix = "enode://" 130 if len(*argEnode) > 0 { 131 if (*argEnode)[:len(enodePrefix)] != enodePrefix { 132 *argEnode = enodePrefix + *argEnode 133 } 134 } 135 136 if len(*argTopic) > 0 { 137 x, err := hex.DecodeString(*argTopic) 138 if err != nil { 139 utils.Fatalf("Failed to parse the topic: %s", err) 140 } 141 topic = whisper.BytesToTopic(x) 142 } 143 144 if *asymmetricMode && len(*argPub) > 0 { 145 var err error 146 if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil { 147 utils.Fatalf("invalid public key") 148 } 149 } 150 151 if len(*argSaveDir) > 0 { 152 if _, err := os.Stat(*argSaveDir); os.IsNotExist(err) { 153 utils.Fatalf("Download directory '%s' does not exist", *argSaveDir) 154 } 155 } else if *fileExMode { 156 utils.Fatalf("Parameter 'savedir' is mandatory for file exchange mode") 157 } 158 159 if *echoMode { 160 echo() 161 } 162 } 163 164 func echo() { 165 fmt.Printf("ttl = %d \n", *argTTL) 166 fmt.Printf("workTime = %d \n", *argWorkTime) 167 fmt.Printf("pow = %f \n", *argPoW) 168 fmt.Printf("mspow = %f \n", *argServerPoW) 169 fmt.Printf("ip = %s \n", *argIP) 170 fmt.Printf("pub = %s \n", common.ToHex(crypto.FromECDSAPub(pub))) 171 fmt.Printf("idfile = %s \n", *argIDFile) 172 fmt.Printf("dbpath = %s \n", *argDBPath) 173 fmt.Printf("boot = %s \n", *argEnode) 174 } 175 176 func initialize() { 177 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*argVerbosity), log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 178 179 done = make(chan struct{}) 180 var peers []*enode.Node 181 var err error 182 183 if *generateKey { 184 key, err := crypto.GenerateKey() 185 if err != nil { 186 utils.Fatalf("Failed to generate private key: %s", err) 187 } 188 k := hex.EncodeToString(crypto.FromECDSA(key)) 189 fmt.Printf("Random private key: %s \n", k) 190 os.Exit(0) 191 } 192 193 if *testMode { 194 symPass = "wwww" // ascii code: 0x77777777 195 msPassword = "wwww" 196 } 197 198 if *bootstrapMode { 199 if len(*argIP) == 0 { 200 argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ") 201 } 202 } else if *fileReader { 203 *bootstrapMode = true 204 } else { 205 if len(*argEnode) == 0 { 206 argEnode = scanLineA("Please enter the peer's enode: ") 207 } 208 peer := enode.MustParseV4(*argEnode) 209 peers = append(peers, peer) 210 } 211 212 if *mailServerMode { 213 if len(msPassword) == 0 { 214 msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ") 215 if err != nil { 216 utils.Fatalf("Failed to read Mail Server password: %s", err) 217 } 218 } 219 } 220 221 cfg := &whisper.Config{ 222 MaxMessageSize: uint32(*argMaxSize), 223 MinimumAcceptedPOW: *argPoW, 224 } 225 226 shh = whisper.New(cfg) 227 228 if *argPoW != whisper.DefaultMinimumPoW { 229 err := shh.SetMinimumPoW(*argPoW) 230 if err != nil { 231 utils.Fatalf("Failed to set PoW: %s", err) 232 } 233 } 234 235 if uint32(*argMaxSize) != whisper.DefaultMaxMessageSize { 236 err := shh.SetMaxMessageSize(uint32(*argMaxSize)) 237 if err != nil { 238 utils.Fatalf("Failed to set max message size: %s", err) 239 } 240 } 241 242 asymKeyID, err = shh.NewKeyPair() 243 if err != nil { 244 utils.Fatalf("Failed to generate a new key pair: %s", err) 245 } 246 247 asymKey, err = shh.GetPrivateKey(asymKeyID) 248 if err != nil { 249 utils.Fatalf("Failed to retrieve a new key pair: %s", err) 250 } 251 252 if nodeid == nil { 253 tmpID, err := shh.NewKeyPair() 254 if err != nil { 255 utils.Fatalf("Failed to generate a new key pair: %s", err) 256 } 257 258 nodeid, err = shh.GetPrivateKey(tmpID) 259 if err != nil { 260 utils.Fatalf("Failed to retrieve a new key pair: %s", err) 261 } 262 } 263 264 maxPeers := 80 265 if *bootstrapMode { 266 maxPeers = 800 267 } 268 269 _, err = crand.Read(entropy[:]) 270 if err != nil { 271 utils.Fatalf("crypto/rand failed: %s", err) 272 } 273 274 if *mailServerMode { 275 shh.RegisterServer(&mailServer) 276 if err := mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW); err != nil { 277 utils.Fatalf("Failed to init MailServer: %s", err) 278 } 279 } 280 281 server = &p2p.Server{ 282 Config: p2p.Config{ 283 PrivateKey: nodeid, 284 MaxPeers: maxPeers, 285 Name: common.MakeName("wnode", "6.0"), 286 Protocols: shh.Protocols(), 287 ListenAddr: *argIP, 288 NAT: nat.Any(), 289 BootstrapNodes: peers, 290 StaticNodes: peers, 291 TrustedNodes: peers, 292 }, 293 } 294 } 295 296 func startServer() error { 297 err := server.Start() 298 if err != nil { 299 fmt.Printf("Failed to start Whisper peer: %s.", err) 300 return err 301 } 302 303 fmt.Printf("my public key: %s \n", common.ToHex(crypto.FromECDSAPub(&asymKey.PublicKey))) 304 fmt.Println(server.NodeInfo().Enode) 305 306 if *bootstrapMode { 307 configureNode() 308 fmt.Println("Bootstrap Whisper node started") 309 } else { 310 fmt.Println("Whisper node started") 311 // first see if we can establish connection, then ask for user input 312 waitForConnection(true) 313 configureNode() 314 } 315 316 if *fileExMode { 317 fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand) 318 } else if *fileReader { 319 fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand) 320 } else if !*forwarderMode { 321 fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand) 322 } 323 return nil 324 } 325 326 func configureNode() { 327 var err error 328 var p2pAccept bool 329 330 if *forwarderMode { 331 return 332 } 333 334 if *asymmetricMode { 335 if len(*argPub) == 0 { 336 s := scanLine("Please enter the peer's public key: ") 337 b := common.FromHex(s) 338 if b == nil { 339 utils.Fatalf("Error: can not convert hexadecimal string") 340 } 341 if pub, err = crypto.UnmarshalPubkey(b); err != nil { 342 utils.Fatalf("Error: invalid peer public key") 343 } 344 } 345 } 346 347 if *requestMail { 348 p2pAccept = true 349 if len(msPassword) == 0 { 350 msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ") 351 if err != nil { 352 utils.Fatalf("Failed to read Mail Server password: %s", err) 353 } 354 } 355 } 356 357 if !*asymmetricMode && !*forwarderMode { 358 if len(symPass) == 0 { 359 symPass, err = console.Stdin.PromptPassword("Please enter the password for symmetric encryption: ") 360 if err != nil { 361 utils.Fatalf("Failed to read passphrase: %v", err) 362 } 363 } 364 365 symKeyID, err := shh.AddSymKeyFromPassword(symPass) 366 if err != nil { 367 utils.Fatalf("Failed to create symmetric key: %s", err) 368 } 369 symKey, err = shh.GetSymKey(symKeyID) 370 if err != nil { 371 utils.Fatalf("Failed to save symmetric key: %s", err) 372 } 373 if len(*argTopic) == 0 { 374 generateTopic([]byte(symPass)) 375 } 376 377 fmt.Printf("Filter is configured for the topic: %x \n", topic) 378 } 379 380 if *mailServerMode { 381 if len(*argDBPath) == 0 { 382 argDBPath = scanLineA("Please enter the path to DB file: ") 383 } 384 } 385 386 symFilter := whisper.Filter{ 387 KeySym: symKey, 388 Topics: [][]byte{topic[:]}, 389 AllowP2P: p2pAccept, 390 } 391 symFilterID, err = shh.Subscribe(&symFilter) 392 if err != nil { 393 utils.Fatalf("Failed to install filter: %s", err) 394 } 395 396 asymFilter := whisper.Filter{ 397 KeyAsym: asymKey, 398 Topics: [][]byte{topic[:]}, 399 AllowP2P: p2pAccept, 400 } 401 asymFilterID, err = shh.Subscribe(&asymFilter) 402 if err != nil { 403 utils.Fatalf("Failed to install filter: %s", err) 404 } 405 } 406 407 func generateTopic(password []byte) { 408 x := pbkdf2.Key(password, password, 4096, 128, sha512.New) 409 for i := 0; i < len(x); i++ { 410 topic[i%whisper.TopicLength] ^= x[i] 411 } 412 } 413 414 func waitForConnection(timeout bool) { 415 var cnt int 416 var connected bool 417 for !connected { 418 time.Sleep(time.Millisecond * 50) 419 connected = server.PeerCount() > 0 420 if timeout { 421 cnt++ 422 if cnt > 1000 { 423 utils.Fatalf("Timeout expired, failed to connect") 424 } 425 } 426 } 427 428 fmt.Println("Connected to peer.") 429 } 430 431 func run() { 432 err := startServer() 433 if err != nil { 434 return 435 } 436 defer server.Stop() 437 shh.Start(nil) 438 defer shh.Stop() 439 440 if !*forwarderMode { 441 go messageLoop() 442 } 443 444 if *requestMail { 445 requestExpiredMessagesLoop() 446 } else if *fileExMode { 447 sendFilesLoop() 448 } else if *fileReader { 449 fileReaderLoop() 450 } else { 451 sendLoop() 452 } 453 } 454 455 func shutdown() { 456 close(done) 457 mailServer.Close() 458 } 459 460 func sendLoop() { 461 for { 462 s := scanLine("") 463 if s == quitCommand { 464 fmt.Println("Quit command received") 465 return 466 } 467 sendMsg([]byte(s)) 468 if *asymmetricMode { 469 // print your own message for convenience, 470 // because in asymmetric mode it is impossible to decrypt it 471 timestamp := time.Now().Unix() 472 from := crypto.PubkeyToAddress(asymKey.PublicKey) 473 fmt.Printf("\n%d <%x>: %s\n", timestamp, from, s) 474 } 475 } 476 } 477 478 func sendFilesLoop() { 479 for { 480 s := scanLine("") 481 if s == quitCommand { 482 fmt.Println("Quit command received") 483 return 484 } 485 b, err := ioutil.ReadFile(s) 486 if err != nil { 487 fmt.Printf(">>> Error: %s \n", err) 488 } else { 489 h := sendMsg(b) 490 if (h == common.Hash{}) { 491 fmt.Printf(">>> Error: message was not sent \n") 492 } else { 493 timestamp := time.Now().Unix() 494 from := crypto.PubkeyToAddress(asymKey.PublicKey) 495 fmt.Printf("\n%d <%x>: sent message with hash %x\n", timestamp, from, h) 496 } 497 } 498 } 499 } 500 501 func fileReaderLoop() { 502 watcher1 := shh.GetFilter(symFilterID) 503 watcher2 := shh.GetFilter(asymFilterID) 504 if watcher1 == nil && watcher2 == nil { 505 fmt.Println("Error: neither symmetric nor asymmetric filter is installed") 506 return 507 } 508 509 for { 510 s := scanLine("") 511 if s == quitCommand { 512 fmt.Println("Quit command received") 513 return 514 } 515 raw, err := ioutil.ReadFile(s) 516 if err != nil { 517 fmt.Printf(">>> Error: %s \n", err) 518 } else { 519 env := whisper.Envelope{Data: raw} // the topic is zero 520 msg := env.Open(watcher1) // force-open envelope regardless of the topic 521 if msg == nil { 522 msg = env.Open(watcher2) 523 } 524 if msg == nil { 525 fmt.Printf(">>> Error: failed to decrypt the message \n") 526 } else { 527 printMessageInfo(msg) 528 } 529 } 530 } 531 } 532 533 func scanLine(prompt string) string { 534 if len(prompt) > 0 { 535 fmt.Print(prompt) 536 } 537 txt, err := input.ReadString('\n') 538 if err != nil { 539 utils.Fatalf("input error: %s", err) 540 } 541 txt = strings.TrimRight(txt, "\n\r") 542 return txt 543 } 544 545 func scanLineA(prompt string) *string { 546 s := scanLine(prompt) 547 return &s 548 } 549 550 func scanUint(prompt string) uint32 { 551 s := scanLine(prompt) 552 i, err := strconv.Atoi(s) 553 if err != nil { 554 utils.Fatalf("Fail to parse the lower time limit: %s", err) 555 } 556 return uint32(i) 557 } 558 559 func sendMsg(payload []byte) common.Hash { 560 params := whisper.MessageParams{ 561 Src: asymKey, 562 Dst: pub, 563 KeySym: symKey, 564 Payload: payload, 565 Topic: topic, 566 TTL: uint32(*argTTL), 567 PoW: *argPoW, 568 WorkTime: uint32(*argWorkTime), 569 } 570 571 msg, err := whisper.NewSentMessage(¶ms) 572 if err != nil { 573 utils.Fatalf("failed to create new message: %s", err) 574 } 575 576 envelope, err := msg.Wrap(¶ms) 577 if err != nil { 578 fmt.Printf("failed to seal message: %v \n", err) 579 return common.Hash{} 580 } 581 582 err = shh.Send(envelope) 583 if err != nil { 584 fmt.Printf("failed to send message: %v \n", err) 585 return common.Hash{} 586 } 587 588 return envelope.Hash() 589 } 590 591 func messageLoop() { 592 sf := shh.GetFilter(symFilterID) 593 if sf == nil { 594 utils.Fatalf("symmetric filter is not installed") 595 } 596 597 af := shh.GetFilter(asymFilterID) 598 if af == nil { 599 utils.Fatalf("asymmetric filter is not installed") 600 } 601 602 ticker := time.NewTicker(time.Millisecond * 50) 603 604 for { 605 select { 606 case <-ticker.C: 607 m1 := sf.Retrieve() 608 m2 := af.Retrieve() 609 messages := append(m1, m2...) 610 for _, msg := range messages { 611 reportedOnce := false 612 if !*fileExMode && len(msg.Payload) <= 2048 { 613 printMessageInfo(msg) 614 reportedOnce = true 615 } 616 617 // All messages are saved upon specifying argSaveDir. 618 // fileExMode only specifies how messages are displayed on the console after they are saved. 619 // if fileExMode == true, only the hashes are displayed, since messages might be too big. 620 if len(*argSaveDir) > 0 { 621 writeMessageToFile(*argSaveDir, msg, !reportedOnce) 622 } 623 } 624 case <-done: 625 return 626 } 627 } 628 } 629 630 func printMessageInfo(msg *whisper.ReceivedMessage) { 631 timestamp := fmt.Sprintf("%d", msg.Sent) // unix timestamp for diagnostics 632 text := string(msg.Payload) 633 634 var address common.Address 635 if msg.Src != nil { 636 address = crypto.PubkeyToAddress(*msg.Src) 637 } 638 639 if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { 640 fmt.Printf("\n%s <%x>: %s\n", timestamp, address, text) // message from myself 641 } else { 642 fmt.Printf("\n%s [%x]: %s\n", timestamp, address, text) // message from a peer 643 } 644 } 645 646 func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) { 647 if len(dir) == 0 { 648 return 649 } 650 651 timestamp := fmt.Sprintf("%d", msg.Sent) 652 name := fmt.Sprintf("%x", msg.EnvelopeHash) 653 654 var address common.Address 655 if msg.Src != nil { 656 address = crypto.PubkeyToAddress(*msg.Src) 657 } 658 659 env := shh.GetEnvelope(msg.EnvelopeHash) 660 if env == nil { 661 fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash) 662 return 663 } 664 665 // this is a sample code; uncomment if you don't want to save your own messages. 666 //if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { 667 // fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name) 668 // return 669 //} 670 671 fullpath := filepath.Join(dir, name) 672 err := ioutil.WriteFile(fullpath, env.Data, 0644) 673 if err != nil { 674 fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err) 675 } else if show { 676 fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data)) 677 } 678 } 679 680 func requestExpiredMessagesLoop() { 681 var key, peerID, bloom []byte 682 var timeLow, timeUpp uint32 683 var t string 684 var xt whisper.TopicType 685 686 keyID, err := shh.AddSymKeyFromPassword(msPassword) 687 if err != nil { 688 utils.Fatalf("Failed to create symmetric key for mail request: %s", err) 689 } 690 key, err = shh.GetSymKey(keyID) 691 if err != nil { 692 utils.Fatalf("Failed to save symmetric key for mail request: %s", err) 693 } 694 peerID = extractIDFromEnode(*argEnode) 695 shh.AllowP2PMessagesFromPeer(peerID) 696 697 for { 698 timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ") 699 timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ") 700 t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ") 701 if len(t) == whisper.TopicLength*2 { 702 x, err := hex.DecodeString(t) 703 if err != nil { 704 fmt.Printf("Failed to parse the topic: %s \n", err) 705 continue 706 } 707 xt = whisper.BytesToTopic(x) 708 bloom = whisper.TopicToBloom(xt) 709 obfuscateBloom(bloom) 710 } else if len(t) == 0 { 711 bloom = whisper.MakeFullNodeBloom() 712 } else { 713 fmt.Println("Error: topic is invalid, request aborted") 714 continue 715 } 716 717 if timeUpp == 0 { 718 timeUpp = 0xFFFFFFFF 719 } 720 721 data := make([]byte, 8, 8+whisper.BloomFilterSize) 722 binary.BigEndian.PutUint32(data, timeLow) 723 binary.BigEndian.PutUint32(data[4:], timeUpp) 724 data = append(data, bloom...) 725 726 var params whisper.MessageParams 727 params.PoW = *argServerPoW 728 params.Payload = data 729 params.KeySym = key 730 params.Src = asymKey 731 params.WorkTime = 5 732 733 msg, err := whisper.NewSentMessage(¶ms) 734 if err != nil { 735 utils.Fatalf("failed to create new message: %s", err) 736 } 737 env, err := msg.Wrap(¶ms) 738 if err != nil { 739 utils.Fatalf("Wrap failed: %s", err) 740 } 741 742 err = shh.RequestHistoricMessages(peerID, env) 743 if err != nil { 744 utils.Fatalf("Failed to send P2P message: %s", err) 745 } 746 747 time.Sleep(time.Second * 5) 748 } 749 } 750 751 func extractIDFromEnode(s string) []byte { 752 n, err := enode.ParseV4(s) 753 if err != nil { 754 utils.Fatalf("Failed to parse enode: %s", err) 755 } 756 return n.ID().Bytes() 757 } 758 759 // obfuscateBloom adds 16 random bits to the bloom 760 // filter, in order to obfuscate the containing topics. 761 // it does so deterministically within every session. 762 // despite additional bits, it will match on average 763 // 32000 times less messages than full node's bloom filter. 764 func obfuscateBloom(bloom []byte) { 765 const half = entropySize / 2 766 for i := 0; i < half; i++ { 767 x := int(entropy[i]) 768 if entropy[half+i] < 128 { 769 x += 256 770 } 771 772 bloom[x/8] = 1 << uint(x%8) // set the bit number X 773 } 774 }