github.com/bcskill/bcschain/v3@v3.4.9-beta2/whisper/whisperv6/peer_test.go (about) 1 // Copyright 2016 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 whisperv6 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "fmt" 24 mrand "math/rand" 25 "net" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/bcskill/bcschain/v3/common" 31 "github.com/bcskill/bcschain/v3/common/hexutil" 32 "github.com/bcskill/bcschain/v3/crypto" 33 "github.com/bcskill/bcschain/v3/p2p" 34 "github.com/bcskill/bcschain/v3/p2p/discover" 35 "github.com/bcskill/bcschain/v3/p2p/nat" 36 ) 37 38 var keys = []string{ 39 "d49dcf37238dc8a7aac57dc61b9fee68f0a97f062968978b9fafa7d1033d03a9", 40 "73fd6143c48e80ed3c56ea159fe7494a0b6b393a392227b422f4c3e8f1b54f98", 41 "119dd32adb1daa7a4c7bf77f847fb28730785aa92947edf42fdd997b54de40dc", 42 "deeda8709dea935bb772248a3144dea449ffcc13e8e5a1fd4ef20ce4e9c87837", 43 "5bd208a079633befa349441bdfdc4d85ba9bd56081525008380a63ac38a407cf", 44 "1d27fb4912002d58a2a42a50c97edb05c1b3dffc665dbaa42df1fe8d3d95c9b5", 45 "15def52800c9d6b8ca6f3066b7767a76afc7b611786c1276165fbc61636afb68", 46 "51be6ab4b2dc89f251ff2ace10f3c1cc65d6855f3e083f91f6ff8efdfd28b48c", 47 "ef1ef7441bf3c6419b162f05da6037474664f198b58db7315a6f4de52414b4a0", 48 "09bdf6985aabc696dc1fbeb5381aebd7a6421727343872eb2fadfc6d82486fd9", 49 "15d811bf2e01f99a224cdc91d0cf76cea08e8c67905c16fee9725c9be71185c4", 50 "2f83e45cf1baaea779789f755b7da72d8857aeebff19362dd9af31d3c9d14620", 51 "73f04e34ac6532b19c2aae8f8e52f38df1ac8f5cd10369f92325b9b0494b0590", 52 "1e2e07b69e5025537fb73770f483dc8d64f84ae3403775ef61cd36e3faf162c1", 53 "8963d9bbb3911aac6d30388c786756b1c423c4fbbc95d1f96ddbddf39809e43a", 54 "0422da85abc48249270b45d8de38a4cc3c02032ede1fcf0864a51092d58a2f1f", 55 "8ae5c15b0e8c7cade201fdc149831aa9b11ff626a7ffd27188886cc108ad0fa8", 56 "acd8f5a71d4aecfcb9ad00d32aa4bcf2a602939b6a9dd071bab443154184f805", 57 "a285a922125a7481600782ad69debfbcdb0316c1e97c267aff29ef50001ec045", 58 "28fd4eee78c6cd4bf78f39f8ab30c32c67c24a6223baa40e6f9c9a0e1de7cef5", 59 "c5cca0c9e6f043b288c6f1aef448ab59132dab3e453671af5d0752961f013fc7", 60 "46df99b051838cb6f8d1b73f232af516886bd8c4d0ee07af9a0a033c391380fd", 61 "c6a06a53cbaadbb432884f36155c8f3244e244881b5ee3e92e974cfa166d793f", 62 "783b90c75c63dc72e2f8d11b6f1b4de54d63825330ec76ee8db34f06b38ea211", 63 "9450038f10ca2c097a8013e5121b36b422b95b04892232f930a29292d9935611", 64 "e215e6246ed1cfdcf7310d4d8cdbe370f0d6a8371e4eb1089e2ae05c0e1bc10f", 65 "487110939ed9d64ebbc1f300adeab358bc58875faf4ca64990fbd7fe03b78f2b", 66 "824a70ea76ac81366da1d4f4ac39de851c8ac49dca456bb3f0a186ceefa269a5", 67 "ba8f34fa40945560d1006a328fe70c42e35cc3d1017e72d26864cd0d1b150f15", 68 "30a5dfcfd144997f428901ea88a43c8d176b19c79dde54cc58eea001aa3d246c", 69 "de59f7183aca39aa245ce66a05245fecfc7e2c75884184b52b27734a4a58efa2", 70 "92629e2ff5f0cb4f5f08fffe0f64492024d36f045b901efb271674b801095c5a", 71 "7184c1701569e3a4c4d2ddce691edd983b81e42e09196d332e1ae2f1e062cff4", 72 } 73 74 type TestData struct { 75 counter [NumNodes]int 76 mutex sync.RWMutex 77 } 78 79 type TestNode struct { 80 shh *Whisper 81 id *ecdsa.PrivateKey 82 server *p2p.Server 83 filerID string 84 } 85 86 const NumNodes = 8 // must not exceed the number of keys (32) 87 88 var result TestData 89 var nodes [NumNodes]*TestNode 90 var sharedKey = hexutil.MustDecode("0x03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31") 91 var wrongKey = hexutil.MustDecode("0xf91156714d7ec88d3edc1c652c2181dbb3044e8771c683f3b30d33c12b986b11") 92 var sharedTopic = TopicType{0xF, 0x1, 0x2, 0} 93 var wrongTopic = TopicType{0, 0, 0, 0} 94 var expectedMessage = []byte("per aspera ad astra") 95 var unexpectedMessage = []byte("per rectum ad astra") 96 var masterBloomFilter []byte 97 var masterPow = 0.00000001 98 var round = 1 99 var debugMode = false 100 var prevTime time.Time 101 var cntPrev int 102 103 func TestSimulation(t *testing.T) { 104 // create a chain of whisper nodes, 105 // installs the filters with shared (predefined) parameters 106 initialize(t) 107 if err := startServers(); err != nil { 108 t.Fatal(err) 109 } 110 defer stopServers() 111 112 // each node sends one random (not decryptable) message 113 for i := 0; i < NumNodes; i++ { 114 if err := sendMsg(false, i); err != nil { 115 t.Error(err) 116 } 117 } 118 119 // node #0 sends one expected (decryptable) message 120 if err := sendMsg(true, 0); err != nil { 121 t.Error(err) 122 } 123 124 // check if each node have received and decrypted exactly one message 125 if err := checkPropagation(true); err != nil { 126 t.Error(err) 127 } 128 129 const iterations = 200 130 const sleep = 50 * time.Millisecond 131 // check if Status message was correctly decoded 132 if err := try(iterations, sleep, checkBloomFilterExchange); err != nil { 133 t.Error(err) 134 } 135 if err := checkPowExchange(); err != nil { 136 t.Error(err) 137 } 138 139 // send new pow and bloom exchange messages 140 resetParams() 141 142 // node #1 sends one expected (decryptable) message 143 if err := sendMsg(true, 1); err != nil { 144 t.Error(err) 145 } 146 147 // check if each node (except node #0) have received and decrypted exactly one message 148 if err := checkPropagation(false); err != nil { 149 t.Error(err) 150 } 151 152 // check if corresponding protocol-level messages were correctly decoded 153 if err := try(iterations, sleep, checkPowExchangeForNodeZero); err != nil { 154 t.Error(err) 155 } 156 if err := try(iterations, sleep, checkBloomFilterExchange); err != nil { 157 t.Error(err) 158 } 159 } 160 161 func resetParams() { 162 // change pow only for node zero 163 masterPow = 7777777.0 164 nodes[0].shh.SetMinimumPoW(context.Background(), masterPow) 165 166 // change bloom for all nodes 167 masterBloomFilter = TopicToBloom(sharedTopic) 168 for i := 0; i < NumNodes; i++ { 169 nodes[i].shh.SetBloomFilter(context.Background(), masterBloomFilter) 170 } 171 172 round++ 173 } 174 175 func initBloom(t *testing.T) { 176 masterBloomFilter = make([]byte, bloomFilterSize) 177 _, err := mrand.Read(masterBloomFilter) 178 if err != nil { 179 t.Fatalf("rand failed: %s.", err) 180 } 181 182 msgBloom := TopicToBloom(sharedTopic) 183 masterBloomFilter = addBloom(masterBloomFilter, msgBloom) 184 for i := 0; i < 32; i++ { 185 masterBloomFilter[i] = 0xFF 186 } 187 188 if !bloomFilterMatch(masterBloomFilter, msgBloom) { 189 t.Fatalf("bloom mismatch on initBloom.") 190 } 191 } 192 193 func initialize(t *testing.T) { 194 initBloom(t) 195 196 var err error 197 ip := net.IPv4(127, 0, 0, 1) 198 port0 := 30403 199 200 for i := 0; i < NumNodes; i++ { 201 var node TestNode 202 b := make([]byte, bloomFilterSize) 203 copy(b, masterBloomFilter) 204 node.shh = New(&DefaultConfig) 205 node.shh.SetMinimumPoW(context.Background(), masterPow) 206 node.shh.SetBloomFilter(context.Background(), b) 207 if !bytes.Equal(node.shh.BloomFilter(), masterBloomFilter) { 208 t.Fatalf("bloom mismatch on init.") 209 } 210 node.shh.Start(nil) 211 topics := make([]TopicType, 0) 212 topics = append(topics, sharedTopic) 213 f := Filter{KeySym: sharedKey} 214 f.Topics = [][]byte{topics[0][:]} 215 node.filerID, err = node.shh.Subscribe(&f) 216 if err != nil { 217 t.Fatalf("failed to install the filter: %s.", err) 218 } 219 node.id, err = crypto.HexToECDSA(keys[i]) 220 if err != nil { 221 t.Fatalf("failed convert the key: %s.", keys[i]) 222 } 223 port := port0 + i 224 addr := fmt.Sprintf(":%d", port) // e.g. ":30303" 225 name := common.MakeName("whisper-go", "2.0") 226 var peers []*discover.Node 227 if i > 0 { 228 peerNodeID := nodes[i-1].id 229 peerPort := uint16(port - 1) 230 peerNode := discover.PubkeyID(&peerNodeID.PublicKey) 231 peer := discover.NewNode(peerNode, ip, peerPort, peerPort) 232 peers = append(peers, peer) 233 } 234 235 node.server = &p2p.Server{ 236 Config: p2p.Config{ 237 PrivateKey: node.id, 238 MaxPeers: NumNodes/2 + 1, 239 Name: name, 240 Protocols: node.shh.Protocols(), 241 ListenAddr: addr, 242 NAT: nat.Any(), 243 BootstrapNodes: peers, 244 StaticNodes: peers, 245 TrustedNodes: peers, 246 }, 247 } 248 249 nodes[i] = &node 250 } 251 } 252 func startServers() error { 253 resp := make(chan error, NumNodes) 254 for i := 0; i < NumNodes; i++ { 255 go func(i int) { 256 resp <- nodes[i].server.Start() 257 }(i) 258 } 259 done := make(chan error) 260 go func() { 261 defer close(done) 262 var cnt int 263 for err := range resp { 264 if err != nil { 265 done <- err 266 return 267 } 268 cnt++ 269 if cnt == NumNodes { 270 return 271 } 272 } 273 274 }() 275 select { 276 case <-time.After(10 * time.Second): 277 return fmt.Errorf("timeout waiting to start servers") 278 case err := <-done: 279 return err 280 } 281 } 282 283 func stopServers() { 284 for i := 0; i < NumNodes; i++ { 285 n := nodes[i] 286 if n != nil { 287 n.shh.Unsubscribe(n.filerID) 288 n.shh.Stop() 289 n.server.Stop() 290 } 291 } 292 } 293 294 func checkPropagation(includingNodeZero bool) error { 295 prevTime = time.Now() 296 // (cycle * iterations) should not exceed 50 seconds, since TTL=50 297 const cycle = 200 // time in milliseconds 298 const iterations = 250 299 300 first := 0 301 if !includingNodeZero { 302 first = 1 303 } 304 305 for j := 0; j < iterations; j++ { 306 for i := first; i < NumNodes; i++ { 307 f := nodes[i].shh.GetFilter(nodes[i].filerID) 308 if f == nil { 309 return fmt.Errorf("failed to get filterId %s from node %d, round %d", nodes[i].filerID, i, round) 310 } 311 312 mail := f.Retrieve() 313 if err := validateMail(i, mail); err != nil { 314 return err 315 } 316 317 if isTestComplete() { 318 checkTestStatus() 319 return nil 320 } 321 } 322 323 checkTestStatus() 324 time.Sleep(cycle * time.Millisecond) 325 } 326 327 if !includingNodeZero { 328 f := nodes[0].shh.GetFilter(nodes[0].filerID) 329 if f != nil { 330 return fmt.Errorf("node zero received a message with low PoW") 331 } 332 } 333 334 return fmt.Errorf("test was not complete (%d round): timeout %d seconds. nodes=%v", round, iterations*cycle/1000, nodes) 335 } 336 337 func validateMail(index int, mail []*ReceivedMessage) error { 338 var cnt int 339 for _, m := range mail { 340 if bytes.Equal(m.Payload, expectedMessage) { 341 cnt++ 342 } 343 } 344 345 if cnt == 0 { 346 // no messages received yet: nothing is wrong 347 return nil 348 } 349 if cnt > 1 { 350 return fmt.Errorf("node %d received %d.", index, cnt) 351 } 352 353 if cnt == 1 { 354 result.mutex.Lock() 355 defer result.mutex.Unlock() 356 result.counter[index] += cnt 357 if result.counter[index] > 1 { 358 return fmt.Errorf("node %d accumulated %d.", index, result.counter[index]) 359 } 360 } 361 return nil 362 } 363 364 func checkTestStatus() { 365 var cnt int 366 var arr [NumNodes]int 367 368 for i := 0; i < NumNodes; i++ { 369 arr[i] = nodes[i].server.PeerCount() 370 envelopes := nodes[i].shh.Envelopes() 371 if len(envelopes) >= NumNodes { 372 cnt++ 373 } 374 } 375 376 if debugMode { 377 if cntPrev != cnt { 378 fmt.Printf(" %v \t number of nodes that have received all msgs: %d, number of peers per node: %v \n", 379 time.Since(prevTime), cnt, arr) 380 prevTime = time.Now() 381 cntPrev = cnt 382 } 383 } 384 } 385 386 func isTestComplete() bool { 387 result.mutex.RLock() 388 defer result.mutex.RUnlock() 389 390 for i := 0; i < NumNodes; i++ { 391 if result.counter[i] < 1 { 392 return false 393 } 394 } 395 396 for i := 0; i < NumNodes; i++ { 397 envelopes := nodes[i].shh.Envelopes() 398 if len(envelopes) < NumNodes+1 { 399 return false 400 } 401 } 402 403 return true 404 } 405 406 func sendMsg(expected bool, id int) error { 407 opt := MessageParams{KeySym: sharedKey, Topic: sharedTopic, Payload: expectedMessage, PoW: 0.00000001, WorkTime: 1} 408 if !expected { 409 opt.KeySym = wrongKey 410 opt.Topic = wrongTopic 411 opt.Payload = unexpectedMessage 412 opt.Payload[0] = byte(id) 413 } 414 415 msg, err := NewSentMessage(&opt) 416 if err != nil { 417 return fmt.Errorf("failed to create new message with seed %d: %s", seed, err) 418 } 419 envelope, err := msg.Wrap(&opt) 420 if err != nil { 421 return fmt.Errorf("failed to seal message: %s", err) 422 } 423 424 err = nodes[id].shh.Send(envelope) 425 if err != nil { 426 return fmt.Errorf("failed to send message: %s", err) 427 } 428 return nil 429 } 430 431 func TestPeerBasic(t *testing.T) { 432 InitSingleTest() 433 434 params, err := generateMessageParams() 435 if err != nil { 436 t.Fatalf("failed generateMessageParams with seed %d.", seed) 437 } 438 439 params.PoW = 0.001 440 msg, err := NewSentMessage(params) 441 if err != nil { 442 t.Fatalf("failed to create new message with seed %d: %s.", seed, err) 443 } 444 env, err := msg.Wrap(params) 445 if err != nil { 446 t.Fatalf("failed Wrap with seed %d.", seed) 447 } 448 449 p := newPeer(nil, nil, nil) 450 p.mark(env) 451 if !p.marked(env) { 452 t.Fatalf("failed mark with seed %d.", seed) 453 } 454 } 455 456 func try(iterations int, sleep time.Duration, fn func() error) (err error) { 457 for j := 0; j < iterations; j++ { 458 if err = fn(); err != nil { 459 if j == iterations-1 { 460 return err 461 } 462 time.Sleep(sleep) 463 continue 464 } 465 return nil 466 } 467 return 468 } 469 470 func checkPowExchangeForNodeZero() error { 471 cnt := 0 472 for i, node := range nodes { 473 for _, peer := range node.shh.getPeers() { 474 fmt.Println(peer.peer.ID().String()) 475 if peer.peer.ID() == discover.PubkeyID(&nodes[0].id.PublicKey) { 476 cnt++ 477 peer.mu.RLock() 478 pow := peer.powRequirement 479 peer.mu.RUnlock() 480 if pow != masterPow { 481 return fmt.Errorf("node %d: failed to set the new pow requirement for node zero", i) 482 } 483 } 484 } 485 } 486 if cnt == 0 { 487 return fmt.Errorf("looking for node zero: no matching peers found") 488 } 489 return nil 490 } 491 492 func checkPowExchange() error { 493 for i, node := range nodes { 494 for _, peer := range node.shh.getPeers() { 495 if peer.peer.ID() != discover.PubkeyID(&nodes[0].id.PublicKey) { 496 peer.mu.RLock() 497 pow := peer.powRequirement 498 peer.mu.RUnlock() 499 if pow != masterPow { 500 return fmt.Errorf("node %d: failed to exchange pow requirement in round %d; expected %f, got %f", 501 i, round, masterPow, pow) 502 } 503 } 504 } 505 } 506 return nil 507 } 508 509 func checkBloomFilterExchange() error { 510 for i, node := range nodes { 511 for _, peer := range node.shh.getPeers() { 512 peer.mu.RLock() 513 bf := peer.bloomFilter 514 peer.mu.RUnlock() 515 if !bytes.Equal(bf, masterBloomFilter) { 516 return fmt.Errorf("node %d: failed to exchange bloom filter requirement in round %d. \n%x expected \n%x got", 517 i, round, masterBloomFilter, bf) 518 } 519 } 520 } 521 522 return nil 523 }