github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/whisper/whisperv5/filter_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 whisperv5 18 19 import ( 20 "math/big" 21 "math/rand" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/crypto" 27 ) 28 29 var seed int64 30 31 // InitSingleTest should be called in the beginning of every 32 // test, which uses RNG, in order to make the tests 33 // reproduciblity independent of their sequence. 34 func InitSingleTest() { 35 seed = time.Now().Unix() 36 rand.Seed(seed) 37 } 38 39 func InitDebugTest(i int64) { 40 seed = i 41 rand.Seed(seed) 42 } 43 44 type FilterTestCase struct { 45 f *Filter 46 id string 47 alive bool 48 msgCnt int 49 } 50 51 func generateFilter(t *testing.T, symmetric bool) (*Filter, error) { 52 var f Filter 53 f.Messages = make(map[common.Hash]*ReceivedMessage) 54 55 const topicNum = 8 56 f.Topics = make([]TopicType, topicNum) 57 for i := 0; i < topicNum; i++ { 58 randomize(f.Topics[i][:]) 59 f.Topics[i][0] = 0x01 60 } 61 62 key, err := crypto.GenerateKey() 63 if err != nil { 64 t.Fatalf("generateFilter 1 failed with seed %d.", seed) 65 return nil, err 66 } 67 f.Src = &key.PublicKey 68 69 if symmetric { 70 f.KeySym = make([]byte, 12) 71 randomize(f.KeySym) 72 f.SymKeyHash = crypto.Keccak256Hash(f.KeySym) 73 } else { 74 f.KeyAsym, err = crypto.GenerateKey() 75 if err != nil { 76 t.Fatalf("generateFilter 2 failed with seed %d.", seed) 77 return nil, err 78 } 79 } 80 81 // AcceptP2P & PoW are not set 82 return &f, nil 83 } 84 85 func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase { 86 cases := make([]FilterTestCase, SizeTestFilters) 87 for i := 0; i < SizeTestFilters; i++ { 88 f, _ := generateFilter(t, true) 89 cases[i].f = f 90 cases[i].alive = (rand.Int()&int(1) == 0) 91 } 92 return cases 93 } 94 95 func TestInstallFilters(t *testing.T) { 96 InitSingleTest() 97 98 const SizeTestFilters = 256 99 w := New() 100 filters := NewFilters(w) 101 tst := generateTestCases(t, SizeTestFilters) 102 103 var err error 104 var j string 105 for i := 0; i < SizeTestFilters; i++ { 106 j, err = filters.Install(tst[i].f) 107 if err != nil { 108 t.Fatalf("seed %d: failed to install filter: %s", seed, err) 109 } 110 tst[i].id = j 111 if len(j) != 40 { 112 t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j)) 113 } 114 } 115 116 for _, testCase := range tst { 117 if !testCase.alive { 118 filters.Uninstall(testCase.id) 119 } 120 } 121 122 for i, testCase := range tst { 123 fil := filters.Get(testCase.id) 124 exist := (fil != nil) 125 if exist != testCase.alive { 126 t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive) 127 } 128 if exist && fil.PoW != testCase.f.PoW { 129 t.Fatalf("seed %d: failed Get: %d, %v, %v", seed, i, exist, testCase.alive) 130 } 131 } 132 } 133 134 func TestComparePubKey(t *testing.T) { 135 InitSingleTest() 136 137 key1, err := crypto.GenerateKey() 138 if err != nil { 139 t.Fatalf("failed to generate first key with seed %d: %s.", seed, err) 140 } 141 key2, err := crypto.GenerateKey() 142 if err != nil { 143 t.Fatalf("failed to generate second key with seed %d: %s.", seed, err) 144 } 145 if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) { 146 t.Fatalf("public keys are equal, seed %d.", seed) 147 } 148 149 // generate key3 == key1 150 rand.Seed(seed) 151 key3, err := crypto.GenerateKey() 152 if err != nil { 153 t.Fatalf("failed to generate third key with seed %d: %s.", seed, err) 154 } 155 if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) { 156 t.Fatalf("key1 == key3, seed %d.", seed) 157 } 158 } 159 160 func TestMatchEnvelope(t *testing.T) { 161 InitSingleTest() 162 163 fsym, err := generateFilter(t, true) 164 if err != nil { 165 t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) 166 } 167 168 fasym, err := generateFilter(t, false) 169 if err != nil { 170 t.Fatalf("failed generateFilter() with seed %d: %s.", seed, err) 171 } 172 173 params, err := generateMessageParams() 174 if err != nil { 175 t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) 176 } 177 178 params.Topic[0] = 0xFF // ensure mismatch 179 180 // mismatch with pseudo-random data 181 msg := NewSentMessage(params) 182 env, err := msg.Wrap(params) 183 if err != nil { 184 t.Fatalf("failed Wrap with seed %d: %s.", seed, err) 185 } 186 match := fsym.MatchEnvelope(env) 187 if match { 188 t.Fatalf("failed MatchEnvelope symmetric with seed %d.", seed) 189 } 190 match = fasym.MatchEnvelope(env) 191 if match { 192 t.Fatalf("failed MatchEnvelope asymmetric with seed %d.", seed) 193 } 194 195 // encrypt symmetrically 196 i := rand.Int() % 4 197 fsym.Topics[i] = params.Topic 198 fasym.Topics[i] = params.Topic 199 msg = NewSentMessage(params) 200 env, err = msg.Wrap(params) 201 if err != nil { 202 t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) 203 } 204 205 // symmetric + matching topic: match 206 match = fsym.MatchEnvelope(env) 207 if !match { 208 t.Fatalf("failed MatchEnvelope() symmetric with seed %d.", seed) 209 } 210 211 // asymmetric + matching topic: mismatch 212 match = fasym.MatchEnvelope(env) 213 if match { 214 t.Fatalf("failed MatchEnvelope() asymmetric with seed %d.", seed) 215 } 216 217 // symmetric + matching topic + insufficient PoW: mismatch 218 fsym.PoW = env.PoW() + 1.0 219 match = fsym.MatchEnvelope(env) 220 if match { 221 t.Fatalf("failed MatchEnvelope(symmetric + matching topic + insufficient PoW) asymmetric with seed %d.", seed) 222 } 223 224 // symmetric + matching topic + sufficient PoW: match 225 fsym.PoW = env.PoW() / 2 226 match = fsym.MatchEnvelope(env) 227 if !match { 228 t.Fatalf("failed MatchEnvelope(symmetric + matching topic + sufficient PoW) with seed %d.", seed) 229 } 230 231 // symmetric + topics are nil (wildcard): match 232 prevTopics := fsym.Topics 233 fsym.Topics = nil 234 match = fsym.MatchEnvelope(env) 235 if !match { 236 t.Fatalf("failed MatchEnvelope(symmetric + topics are nil) with seed %d.", seed) 237 } 238 fsym.Topics = prevTopics 239 240 // encrypt asymmetrically 241 key, err := crypto.GenerateKey() 242 if err != nil { 243 t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) 244 } 245 params.KeySym = nil 246 params.Dst = &key.PublicKey 247 msg = NewSentMessage(params) 248 env, err = msg.Wrap(params) 249 if err != nil { 250 t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) 251 } 252 253 // encryption method mismatch 254 match = fsym.MatchEnvelope(env) 255 if match { 256 t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) 257 } 258 259 // asymmetric + mismatching topic: mismatch 260 match = fasym.MatchEnvelope(env) 261 if !match { 262 t.Fatalf("failed MatchEnvelope(asymmetric + mismatching topic) with seed %d.", seed) 263 } 264 265 // asymmetric + matching topic: match 266 fasym.Topics[i] = fasym.Topics[i+1] 267 match = fasym.MatchEnvelope(env) 268 if match { 269 t.Fatalf("failed MatchEnvelope(asymmetric + matching topic) with seed %d.", seed) 270 } 271 272 // asymmetric + filter without topic (wildcard): match 273 fasym.Topics = nil 274 match = fasym.MatchEnvelope(env) 275 if !match { 276 t.Fatalf("failed MatchEnvelope(asymmetric + filter without topic) with seed %d.", seed) 277 } 278 279 // asymmetric + insufficient PoW: mismatch 280 fasym.PoW = env.PoW() + 1.0 281 match = fasym.MatchEnvelope(env) 282 if match { 283 t.Fatalf("failed MatchEnvelope(asymmetric + insufficient PoW) with seed %d.", seed) 284 } 285 286 // asymmetric + sufficient PoW: match 287 fasym.PoW = env.PoW() / 2 288 match = fasym.MatchEnvelope(env) 289 if !match { 290 t.Fatalf("failed MatchEnvelope(asymmetric + sufficient PoW) with seed %d.", seed) 291 } 292 293 // filter without topic + envelope without topic: match 294 env.Topic = TopicType{} 295 match = fasym.MatchEnvelope(env) 296 if !match { 297 t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed) 298 } 299 300 // filter with topic + envelope without topic: mismatch 301 fasym.Topics = fsym.Topics 302 match = fasym.MatchEnvelope(env) 303 if match { 304 t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed) 305 } 306 } 307 308 func TestMatchMessageSym(t *testing.T) { 309 InitSingleTest() 310 311 params, err := generateMessageParams() 312 if err != nil { 313 t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) 314 } 315 316 f, err := generateFilter(t, true) 317 if err != nil { 318 t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) 319 } 320 321 const index = 1 322 params.KeySym = f.KeySym 323 params.Topic = f.Topics[index] 324 325 sentMessage := NewSentMessage(params) 326 env, err := sentMessage.Wrap(params) 327 if err != nil { 328 t.Fatalf("failed Wrap with seed %d: %s.", seed, err) 329 } 330 331 msg := env.Open(f) 332 if msg == nil { 333 t.Fatalf("failed Open with seed %d.", seed) 334 } 335 336 // Src mismatch 337 if f.MatchMessage(msg) { 338 t.Fatalf("failed MatchMessage(src mismatch) with seed %d.", seed) 339 } 340 341 // Src: match 342 *f.Src.X = *params.Src.PublicKey.X 343 *f.Src.Y = *params.Src.PublicKey.Y 344 if !f.MatchMessage(msg) { 345 t.Fatalf("failed MatchEnvelope(src match) with seed %d.", seed) 346 } 347 348 // insufficient PoW: mismatch 349 f.PoW = msg.PoW + 1.0 350 if f.MatchMessage(msg) { 351 t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed) 352 } 353 354 // sufficient PoW: match 355 f.PoW = msg.PoW / 2 356 if !f.MatchMessage(msg) { 357 t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed) 358 } 359 360 // topic mismatch 361 f.Topics[index][0]++ 362 if f.MatchMessage(msg) { 363 t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) 364 } 365 f.Topics[index][0]-- 366 367 // key mismatch 368 f.SymKeyHash[0]++ 369 if f.MatchMessage(msg) { 370 t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed) 371 } 372 f.SymKeyHash[0]-- 373 374 // Src absent: match 375 f.Src = nil 376 if !f.MatchMessage(msg) { 377 t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed) 378 } 379 380 // key hash mismatch 381 h := f.SymKeyHash 382 f.SymKeyHash = common.Hash{} 383 if f.MatchMessage(msg) { 384 t.Fatalf("failed MatchEnvelope(key hash mismatch) with seed %d.", seed) 385 } 386 f.SymKeyHash = h 387 if !f.MatchMessage(msg) { 388 t.Fatalf("failed MatchEnvelope(key hash match) with seed %d.", seed) 389 } 390 391 // encryption method mismatch 392 f.KeySym = nil 393 f.KeyAsym, err = crypto.GenerateKey() 394 if err != nil { 395 t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err) 396 } 397 if f.MatchMessage(msg) { 398 t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) 399 } 400 } 401 402 func TestMatchMessageAsym(t *testing.T) { 403 InitSingleTest() 404 405 f, err := generateFilter(t, false) 406 if err != nil { 407 t.Fatalf("failed generateFilter with seed %d: %s.", seed, err) 408 } 409 410 params, err := generateMessageParams() 411 if err != nil { 412 t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) 413 } 414 415 const index = 1 416 params.Topic = f.Topics[index] 417 params.Dst = &f.KeyAsym.PublicKey 418 keySymOrig := params.KeySym 419 params.KeySym = nil 420 421 sentMessage := NewSentMessage(params) 422 env, err := sentMessage.Wrap(params) 423 if err != nil { 424 t.Fatalf("failed Wrap with seed %d: %s.", seed, err) 425 } 426 427 msg := env.Open(f) 428 if msg == nil { 429 t.Fatalf("failed to open with seed %d.", seed) 430 } 431 432 // Src mismatch 433 if f.MatchMessage(msg) { 434 t.Fatalf("failed MatchMessage(src mismatch) with seed %d.", seed) 435 } 436 437 // Src: match 438 *f.Src.X = *params.Src.PublicKey.X 439 *f.Src.Y = *params.Src.PublicKey.Y 440 if !f.MatchMessage(msg) { 441 t.Fatalf("failed MatchMessage(src match) with seed %d.", seed) 442 } 443 444 // insufficient PoW: mismatch 445 f.PoW = msg.PoW + 1.0 446 if f.MatchMessage(msg) { 447 t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed) 448 } 449 450 // sufficient PoW: match 451 f.PoW = msg.PoW / 2 452 if !f.MatchMessage(msg) { 453 t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed) 454 } 455 456 // topic mismatch 457 f.Topics[index][0]++ 458 if f.MatchMessage(msg) { 459 t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed) 460 } 461 f.Topics[index][0]-- 462 463 // key mismatch 464 prev := *f.KeyAsym.PublicKey.X 465 zero := *big.NewInt(0) 466 *f.KeyAsym.PublicKey.X = zero 467 if f.MatchMessage(msg) { 468 t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed) 469 } 470 *f.KeyAsym.PublicKey.X = prev 471 472 // Src absent: match 473 f.Src = nil 474 if !f.MatchMessage(msg) { 475 t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed) 476 } 477 478 // encryption method mismatch 479 f.KeySym = keySymOrig 480 f.KeyAsym = nil 481 if f.MatchMessage(msg) { 482 t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed) 483 } 484 } 485 486 func cloneFilter(orig *Filter) *Filter { 487 var clone Filter 488 clone.Messages = make(map[common.Hash]*ReceivedMessage) 489 clone.Src = orig.Src 490 clone.KeyAsym = orig.KeyAsym 491 clone.KeySym = orig.KeySym 492 clone.Topics = orig.Topics 493 clone.PoW = orig.PoW 494 clone.AcceptP2P = orig.AcceptP2P 495 clone.SymKeyHash = orig.SymKeyHash 496 return &clone 497 } 498 499 func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope { 500 params, err := generateMessageParams() 501 if err != nil { 502 t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) 503 return nil 504 } 505 506 params.KeySym = f.KeySym 507 params.Topic = f.Topics[2] 508 sentMessage := NewSentMessage(params) 509 env, err := sentMessage.Wrap(params) 510 if err != nil { 511 t.Fatalf("failed Wrap with seed %d: %s.", seed, err) 512 return nil 513 } 514 return env 515 } 516 517 func TestWatchers(t *testing.T) { 518 InitSingleTest() 519 520 const NumFilters = 16 521 const NumMessages = 256 522 var i int 523 var j uint32 524 var e *Envelope 525 var x, firstID string 526 var err error 527 528 w := New() 529 filters := NewFilters(w) 530 tst := generateTestCases(t, NumFilters) 531 for i = 0; i < NumFilters; i++ { 532 tst[i].f.Src = nil 533 x, err = filters.Install(tst[i].f) 534 if err != nil { 535 t.Fatalf("failed to install filter with seed %d: %s.", seed, err) 536 } 537 tst[i].id = x 538 if len(firstID) == 0 { 539 firstID = x 540 } 541 } 542 543 lastID := x 544 545 var envelopes [NumMessages]*Envelope 546 for i = 0; i < NumMessages; i++ { 547 j = rand.Uint32() % NumFilters 548 e = generateCompatibeEnvelope(t, tst[j].f) 549 envelopes[i] = e 550 tst[j].msgCnt++ 551 } 552 553 for i = 0; i < NumMessages; i++ { 554 filters.NotifyWatchers(envelopes[i], false) 555 } 556 557 var total int 558 var mail []*ReceivedMessage 559 var count [NumFilters]int 560 561 for i = 0; i < NumFilters; i++ { 562 mail = tst[i].f.Retrieve() 563 count[i] = len(mail) 564 total += len(mail) 565 } 566 567 if total != NumMessages { 568 t.Fatalf("failed with seed %d: total = %d, want: %d.", seed, total, NumMessages) 569 } 570 571 for i = 0; i < NumFilters; i++ { 572 mail = tst[i].f.Retrieve() 573 if len(mail) != 0 { 574 t.Fatalf("failed with seed %d: i = %d.", seed, i) 575 } 576 577 if tst[i].msgCnt != count[i] { 578 t.Fatalf("failed with seed %d: count[%d]: get %d, want %d.", seed, i, tst[i].msgCnt, count[i]) 579 } 580 } 581 582 // another round with a cloned filter 583 584 clone := cloneFilter(tst[0].f) 585 filters.Uninstall(lastID) 586 total = 0 587 last := NumFilters - 1 588 tst[last].f = clone 589 filters.Install(clone) 590 for i = 0; i < NumFilters; i++ { 591 tst[i].msgCnt = 0 592 count[i] = 0 593 } 594 595 // make sure that the first watcher receives at least one message 596 e = generateCompatibeEnvelope(t, tst[0].f) 597 envelopes[0] = e 598 tst[0].msgCnt++ 599 for i = 1; i < NumMessages; i++ { 600 j = rand.Uint32() % NumFilters 601 e = generateCompatibeEnvelope(t, tst[j].f) 602 envelopes[i] = e 603 tst[j].msgCnt++ 604 } 605 606 for i = 0; i < NumMessages; i++ { 607 filters.NotifyWatchers(envelopes[i], false) 608 } 609 610 for i = 0; i < NumFilters; i++ { 611 mail = tst[i].f.Retrieve() 612 count[i] = len(mail) 613 total += len(mail) 614 } 615 616 combined := tst[0].msgCnt + tst[last].msgCnt 617 if total != NumMessages+count[0] { 618 t.Fatalf("failed with seed %d: total = %d, count[0] = %d.", seed, total, count[0]) 619 } 620 621 if combined != count[0] { 622 t.Fatalf("failed with seed %d: combined = %d, count[0] = %d.", seed, combined, count[0]) 623 } 624 625 if combined != count[last] { 626 t.Fatalf("failed with seed %d: combined = %d, count[last] = %d.", seed, combined, count[last]) 627 } 628 629 for i = 1; i < NumFilters-1; i++ { 630 mail = tst[i].f.Retrieve() 631 if len(mail) != 0 { 632 t.Fatalf("failed with seed %d: i = %d.", seed, i) 633 } 634 635 if tst[i].msgCnt != count[i] { 636 t.Fatalf("failed with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i]) 637 } 638 } 639 640 // test AcceptP2P 641 642 total = 0 643 filters.NotifyWatchers(envelopes[0], true) 644 645 for i = 0; i < NumFilters; i++ { 646 mail = tst[i].f.Retrieve() 647 total += len(mail) 648 } 649 650 if total != 0 { 651 t.Fatalf("failed with seed %d: total: got %d, want 0.", seed, total) 652 } 653 654 f := filters.Get(firstID) 655 if f == nil { 656 t.Fatalf("failed to get the filter with seed %d.", seed) 657 } 658 f.AcceptP2P = true 659 total = 0 660 filters.NotifyWatchers(envelopes[0], true) 661 662 for i = 0; i < NumFilters; i++ { 663 mail = tst[i].f.Retrieve() 664 total += len(mail) 665 } 666 667 if total != 1 { 668 t.Fatalf("failed with seed %d: total: got %d, want 1.", seed, total) 669 } 670 }