github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/p2p/pex/addrbook_test.go (about) 1 package pex 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "io/ioutil" 7 "math" 8 "net" 9 "os" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/line/ostracon/libs/log" 17 tmmath "github.com/line/ostracon/libs/math" 18 tmrand "github.com/line/ostracon/libs/rand" 19 "github.com/line/ostracon/p2p" 20 ) 21 22 // FIXME These tests should not rely on .(*addrBook) assertions 23 24 func TestAddrBookPickAddress(t *testing.T) { 25 fname := createTempFileName("addrbook_test") 26 defer deleteTempFile(fname) 27 28 // 0 addresses 29 book := NewAddrBook(fname, true) 30 book.SetLogger(log.TestingLogger()) 31 assert.Zero(t, book.Size()) 32 33 addr := book.PickAddress(50) 34 assert.Nil(t, addr, "expected no address") 35 36 randAddrs := randNetAddressPairs(t, 1) 37 addrSrc := randAddrs[0] 38 err := book.AddAddress(addrSrc.addr, addrSrc.src) 39 require.NoError(t, err) 40 41 // pick an address when we only have new address 42 addr = book.PickAddress(0) 43 assert.NotNil(t, addr, "expected an address") 44 addr = book.PickAddress(50) 45 assert.NotNil(t, addr, "expected an address") 46 addr = book.PickAddress(100) 47 assert.NotNil(t, addr, "expected an address") 48 49 // pick an address when we only have old address 50 book.MarkGood(addrSrc.addr.ID) 51 addr = book.PickAddress(0) 52 assert.NotNil(t, addr, "expected an address") 53 addr = book.PickAddress(50) 54 assert.NotNil(t, addr, "expected an address") 55 56 // in this case, nNew==0 but we biased 100% to new, so we return nil 57 addr = book.PickAddress(100) 58 assert.Nil(t, addr, "did not expected an address") 59 } 60 61 func TestAddrBookSaveLoad(t *testing.T) { 62 fname := createTempFileName("addrbook_test") 63 defer deleteTempFile(fname) 64 65 // 0 addresses 66 book := NewAddrBook(fname, true) 67 book.SetLogger(log.TestingLogger()) 68 book.Save() 69 70 book = NewAddrBook(fname, true) 71 book.SetLogger(log.TestingLogger()) 72 err := book.Start() 73 require.NoError(t, err) 74 75 assert.True(t, book.Empty()) 76 77 // 100 addresses 78 randAddrs := randNetAddressPairs(t, 100) 79 80 for _, addrSrc := range randAddrs { 81 err := book.AddAddress(addrSrc.addr, addrSrc.src) 82 require.NoError(t, err) 83 } 84 85 assert.Equal(t, 100, book.Size()) 86 book.Save() 87 88 book = NewAddrBook(fname, true) 89 book.SetLogger(log.TestingLogger()) 90 err = book.Start() 91 require.NoError(t, err) 92 93 assert.Equal(t, 100, book.Size()) 94 } 95 96 func TestAddrBookLookup(t *testing.T) { 97 fname := createTempFileName("addrbook_test") 98 defer deleteTempFile(fname) 99 100 randAddrs := randNetAddressPairs(t, 100) 101 102 book := NewAddrBook(fname, true) 103 book.SetLogger(log.TestingLogger()) 104 for _, addrSrc := range randAddrs { 105 addr := addrSrc.addr 106 src := addrSrc.src 107 err := book.AddAddress(addr, src) 108 require.NoError(t, err) 109 110 ka := book.HasAddress(addr) 111 assert.True(t, ka, "Expected to find KnownAddress %v but wasn't there.", addr) 112 } 113 } 114 115 func TestAddrBookPromoteToOld(t *testing.T) { 116 fname := createTempFileName("addrbook_test") 117 defer deleteTempFile(fname) 118 119 randAddrs := randNetAddressPairs(t, 100) 120 121 book := NewAddrBook(fname, true) 122 book.SetLogger(log.TestingLogger()) 123 for _, addrSrc := range randAddrs { 124 err := book.AddAddress(addrSrc.addr, addrSrc.src) 125 require.NoError(t, err) 126 } 127 128 // Attempt all addresses. 129 for _, addrSrc := range randAddrs { 130 book.MarkAttempt(addrSrc.addr) 131 } 132 133 // Promote half of them 134 for i, addrSrc := range randAddrs { 135 if i%2 == 0 { 136 book.MarkGood(addrSrc.addr.ID) 137 } 138 } 139 140 // TODO: do more testing :) 141 142 selection := book.GetSelection() 143 t.Logf("selection: %v", selection) 144 145 if len(selection) > book.Size() { 146 t.Errorf("selection could not be bigger than the book") 147 } 148 149 selection = book.GetSelectionWithBias(30) 150 t.Logf("selection: %v", selection) 151 152 if len(selection) > book.Size() { 153 t.Errorf("selection with bias could not be bigger than the book") 154 } 155 156 assert.Equal(t, book.Size(), 100, "expecting book size to be 100") 157 } 158 159 func TestAddrBookHandlesDuplicates(t *testing.T) { 160 fname := createTempFileName("addrbook_test") 161 defer deleteTempFile(fname) 162 163 book := NewAddrBook(fname, true) 164 book.SetLogger(log.TestingLogger()) 165 166 randAddrs := randNetAddressPairs(t, 100) 167 168 differentSrc := randIPv4Address(t) 169 for _, addrSrc := range randAddrs { 170 err := book.AddAddress(addrSrc.addr, addrSrc.src) 171 require.NoError(t, err) 172 err = book.AddAddress(addrSrc.addr, addrSrc.src) // duplicate 173 require.NoError(t, err) 174 err = book.AddAddress(addrSrc.addr, differentSrc) // different src 175 require.NoError(t, err) 176 } 177 178 assert.Equal(t, 100, book.Size()) 179 } 180 181 type netAddressPair struct { 182 addr *p2p.NetAddress 183 src *p2p.NetAddress 184 } 185 186 func randNetAddressPairs(t *testing.T, n int) []netAddressPair { 187 randAddrs := make([]netAddressPair, n) 188 for i := 0; i < n; i++ { 189 randAddrs[i] = netAddressPair{addr: randIPv4Address(t), src: randIPv4Address(t)} 190 } 191 return randAddrs 192 } 193 194 func randIPv4Address(t *testing.T) *p2p.NetAddress { 195 for { 196 ip := fmt.Sprintf("%v.%v.%v.%v", 197 tmrand.Intn(254)+1, 198 tmrand.Intn(255), 199 tmrand.Intn(255), 200 tmrand.Intn(255), 201 ) 202 port := tmrand.Intn(65535-1) + 1 203 id := p2p.ID(hex.EncodeToString(tmrand.Bytes(p2p.IDByteLength))) 204 idAddr := p2p.IDAddressString(id, fmt.Sprintf("%v:%v", ip, port)) 205 addr, err := p2p.NewNetAddressString(idAddr) 206 assert.Nil(t, err, "error generating rand network address") 207 if addr.Routable() { 208 return addr 209 } 210 } 211 } 212 213 func TestAddrBookRemoveAddress(t *testing.T) { 214 fname := createTempFileName("addrbook_test") 215 defer deleteTempFile(fname) 216 217 book := NewAddrBook(fname, true) 218 book.SetLogger(log.TestingLogger()) 219 220 addr := randIPv4Address(t) 221 err := book.AddAddress(addr, addr) 222 require.NoError(t, err) 223 assert.Equal(t, 1, book.Size()) 224 225 book.RemoveAddress(addr) 226 assert.Equal(t, 0, book.Size()) 227 228 nonExistingAddr := randIPv4Address(t) 229 book.RemoveAddress(nonExistingAddr) 230 assert.Equal(t, 0, book.Size()) 231 } 232 233 func TestAddrBookIsGood(t *testing.T) { 234 fname := createTempFileName("addrbook_test") 235 defer deleteTempFile(fname) 236 237 book := NewAddrBook(fname, true).(*addrBook) 238 book.SetLogger(log.TestingLogger()) 239 assert.Zero(t, book.Size()) 240 241 randAddrGood := netAddressPair{addr: randIPv4Address(t), src: randIPv4Address(t)} 242 err := book.AddAddress(randAddrGood.addr, randAddrGood.src) 243 require.NoError(t, err) 244 book.MarkGood(randAddrGood.addr.ID) 245 246 randAddrNew := netAddressPair{addr: randIPv4Address(t), src: randIPv4Address(t)} 247 err = book.AddAddress(randAddrNew.addr, randAddrNew.src) 248 require.NoError(t, err) 249 250 randAddrUnknown := netAddressPair{addr: randIPv4Address(t), src: randIPv4Address(t)} 251 252 assert.Equal(t, true, book.IsGood(randAddrGood.addr)) 253 assert.Equal(t, false, book.IsGood(randAddrNew.addr)) 254 assert.Equal(t, false, book.IsGood(randAddrUnknown.addr)) 255 } 256 257 func TestAddrBookGetSelectionWithOneMarkedGood(t *testing.T) { 258 // create a book with 10 addresses, 1 good/old and 9 new 259 book, fname := createAddrBookWithMOldAndNNewAddrs(t, 1, 9) 260 defer deleteTempFile(fname) 261 262 addrs := book.GetSelectionWithBias(biasToSelectNewPeers) 263 assert.NotNil(t, addrs) 264 assertMOldAndNNewAddrsInSelection(t, 1, 9, addrs, book) 265 } 266 267 func TestAddrBookGetSelectionWithOneNotMarkedGood(t *testing.T) { 268 // create a book with 10 addresses, 9 good/old and 1 new 269 book, fname := createAddrBookWithMOldAndNNewAddrs(t, 9, 1) 270 defer deleteTempFile(fname) 271 272 addrs := book.GetSelectionWithBias(biasToSelectNewPeers) 273 assert.NotNil(t, addrs) 274 assertMOldAndNNewAddrsInSelection(t, 9, 1, addrs, book) 275 } 276 277 func TestAddrBookGetSelectionReturnsNilWhenAddrBookIsEmpty(t *testing.T) { 278 book, fname := createAddrBookWithMOldAndNNewAddrs(t, 0, 0) 279 defer deleteTempFile(fname) 280 281 addrs := book.GetSelectionWithBias(biasToSelectNewPeers) 282 assert.Nil(t, addrs) 283 } 284 285 func TestAddrBookGetSelection(t *testing.T) { 286 fname := createTempFileName("addrbook_test") 287 defer deleteTempFile(fname) 288 289 book := NewAddrBook(fname, true) 290 book.SetLogger(log.TestingLogger()) 291 292 // 1) empty book 293 assert.Empty(t, book.GetSelection()) 294 295 // 2) add one address 296 addr := randIPv4Address(t) 297 err := book.AddAddress(addr, addr) 298 require.NoError(t, err) 299 300 assert.Equal(t, 1, len(book.GetSelection())) 301 assert.Equal(t, addr, book.GetSelection()[0]) 302 303 // 3) add a bunch of addresses 304 randAddrs := randNetAddressPairs(t, 100) 305 for _, addrSrc := range randAddrs { 306 err := book.AddAddress(addrSrc.addr, addrSrc.src) 307 require.NoError(t, err) 308 } 309 310 // check there is no duplicates 311 addrs := make(map[string]*p2p.NetAddress) 312 selection := book.GetSelection() 313 for _, addr := range selection { 314 if dup, ok := addrs[addr.String()]; ok { 315 t.Fatalf("selection %v contains duplicates %v", selection, dup) 316 } 317 addrs[addr.String()] = addr 318 } 319 320 if len(selection) > book.Size() { 321 t.Errorf("selection %v could not be bigger than the book", selection) 322 } 323 } 324 325 func TestAddrBookGetSelectionWithBias(t *testing.T) { 326 const biasTowardsNewAddrs = 30 327 328 fname := createTempFileName("addrbook_test") 329 defer deleteTempFile(fname) 330 331 book := NewAddrBook(fname, true) 332 book.SetLogger(log.TestingLogger()) 333 334 // 1) empty book 335 selection := book.GetSelectionWithBias(biasTowardsNewAddrs) 336 assert.Empty(t, selection) 337 338 // 2) add one address 339 addr := randIPv4Address(t) 340 err := book.AddAddress(addr, addr) 341 require.NoError(t, err) 342 343 selection = book.GetSelectionWithBias(biasTowardsNewAddrs) 344 assert.Equal(t, 1, len(selection)) 345 assert.Equal(t, addr, selection[0]) 346 347 // 3) add a bunch of addresses 348 randAddrs := randNetAddressPairs(t, 100) 349 for _, addrSrc := range randAddrs { 350 err := book.AddAddress(addrSrc.addr, addrSrc.src) 351 require.NoError(t, err) 352 } 353 354 // check there is no duplicates 355 addrs := make(map[string]*p2p.NetAddress) 356 selection = book.GetSelectionWithBias(biasTowardsNewAddrs) 357 for _, addr := range selection { 358 if dup, ok := addrs[addr.String()]; ok { 359 t.Fatalf("selection %v contains duplicates %v", selection, dup) 360 } 361 addrs[addr.String()] = addr 362 } 363 364 if len(selection) > book.Size() { 365 t.Fatalf("selection %v could not be bigger than the book", selection) 366 } 367 368 // 4) mark 80% of the addresses as good 369 randAddrsLen := len(randAddrs) 370 for i, addrSrc := range randAddrs { 371 if int((float64(i)/float64(randAddrsLen))*100) >= 20 { 372 book.MarkGood(addrSrc.addr.ID) 373 } 374 } 375 376 selection = book.GetSelectionWithBias(biasTowardsNewAddrs) 377 378 // check that ~70% of addresses returned are good 379 good := 0 380 for _, addr := range selection { 381 if book.IsGood(addr) { 382 good++ 383 } 384 } 385 386 got, expected := int((float64(good)/float64(len(selection)))*100), 100-biasTowardsNewAddrs 387 388 // compute some slack to protect against small differences due to rounding: 389 slack := int(math.Round(float64(100) / float64(len(selection)))) 390 if got > expected+slack { 391 t.Fatalf( 392 "got more good peers (%% got: %d, %% expected: %d, number of good addrs: %d, total: %d)", 393 got, 394 expected, 395 good, 396 len(selection), 397 ) 398 } 399 if got < expected-slack { 400 t.Fatalf( 401 "got fewer good peers (%% got: %d, %% expected: %d, number of good addrs: %d, total: %d)", 402 got, 403 expected, 404 good, 405 len(selection), 406 ) 407 } 408 } 409 410 func TestAddrBookHasAddress(t *testing.T) { 411 fname := createTempFileName("addrbook_test") 412 defer deleteTempFile(fname) 413 414 book := NewAddrBook(fname, true) 415 book.SetLogger(log.TestingLogger()) 416 addr := randIPv4Address(t) 417 err := book.AddAddress(addr, addr) 418 require.NoError(t, err) 419 420 assert.True(t, book.HasAddress(addr)) 421 422 book.RemoveAddress(addr) 423 424 assert.False(t, book.HasAddress(addr)) 425 } 426 427 func testCreatePrivateAddrs(t *testing.T, numAddrs int) ([]*p2p.NetAddress, []string) { 428 addrs := make([]*p2p.NetAddress, numAddrs) 429 for i := 0; i < numAddrs; i++ { 430 addrs[i] = randIPv4Address(t) 431 } 432 433 private := make([]string, numAddrs) 434 for i, addr := range addrs { 435 private[i] = string(addr.ID) 436 } 437 return addrs, private 438 } 439 440 func TestBanBadPeers(t *testing.T) { 441 fname := createTempFileName("addrbook_test") 442 defer deleteTempFile(fname) 443 444 book := NewAddrBook(fname, true) 445 book.SetLogger(log.TestingLogger()) 446 447 addr := randIPv4Address(t) 448 _ = book.AddAddress(addr, addr) 449 450 book.MarkBad(addr, 1*time.Second) 451 // addr should not reachable 452 assert.False(t, book.HasAddress(addr)) 453 assert.True(t, book.IsBanned(addr)) 454 455 err := book.AddAddress(addr, addr) 456 // book should not add address from the blacklist 457 assert.Error(t, err) 458 459 time.Sleep(1 * time.Second) 460 book.ReinstateBadPeers() 461 // address should be reinstated in the new bucket 462 assert.EqualValues(t, 1, book.Size()) 463 assert.True(t, book.HasAddress(addr)) 464 assert.False(t, book.IsGood(addr)) 465 } 466 467 func TestAddrBookEmpty(t *testing.T) { 468 fname := createTempFileName("addrbook_test") 469 defer deleteTempFile(fname) 470 471 book := NewAddrBook(fname, true) 472 book.SetLogger(log.TestingLogger()) 473 // Check that empty book is empty 474 require.True(t, book.Empty()) 475 // Check that book with our address is empty 476 book.AddOurAddress(randIPv4Address(t)) 477 require.True(t, book.Empty()) 478 // Check that book with private addrs is empty 479 _, privateIds := testCreatePrivateAddrs(t, 5) 480 book.AddPrivateIDs(privateIds) 481 require.True(t, book.Empty()) 482 483 // Check that book with address is not empty 484 err := book.AddAddress(randIPv4Address(t), randIPv4Address(t)) 485 require.NoError(t, err) 486 require.False(t, book.Empty()) 487 } 488 489 func TestPrivatePeers(t *testing.T) { 490 fname := createTempFileName("addrbook_test") 491 defer deleteTempFile(fname) 492 493 book := NewAddrBook(fname, true) 494 book.SetLogger(log.TestingLogger()) 495 496 addrs, private := testCreatePrivateAddrs(t, 10) 497 book.AddPrivateIDs(private) 498 499 // private addrs must not be added 500 for _, addr := range addrs { 501 err := book.AddAddress(addr, addr) 502 if assert.Error(t, err) { 503 _, ok := err.(ErrAddrBookPrivate) 504 assert.True(t, ok) 505 } 506 } 507 508 // addrs coming from private peers must not be added 509 err := book.AddAddress(randIPv4Address(t), addrs[0]) 510 if assert.Error(t, err) { 511 _, ok := err.(ErrAddrBookPrivateSrc) 512 assert.True(t, ok) 513 } 514 } 515 516 func testAddrBookAddressSelection(t *testing.T, bookSize int) { 517 // generate all combinations of old (m) and new addresses 518 for nBookOld := 0; nBookOld <= bookSize; nBookOld++ { 519 nBookNew := bookSize - nBookOld 520 dbgStr := fmt.Sprintf("book of size %d (new %d, old %d)", bookSize, nBookNew, nBookOld) 521 522 // create book and get selection 523 book, fname := createAddrBookWithMOldAndNNewAddrs(t, nBookOld, nBookNew) 524 defer deleteTempFile(fname) 525 addrs := book.GetSelectionWithBias(biasToSelectNewPeers) 526 assert.NotNil(t, addrs, "%s - expected a non-nil selection", dbgStr) 527 nAddrs := len(addrs) 528 assert.NotZero(t, nAddrs, "%s - expected at least one address in selection", dbgStr) 529 530 // check there's no nil addresses 531 for _, addr := range addrs { 532 if addr == nil { 533 t.Fatalf("%s - got nil address in selection %v", dbgStr, addrs) 534 } 535 } 536 537 // XXX: shadowing 538 nOld, nNew := countOldAndNewAddrsInSelection(addrs, book) 539 540 // Given: 541 // n - num new addrs, m - num old addrs 542 // k - num new addrs expected in the beginning (based on bias %) 543 // i=min(n, max(k,r-m)), aka expNew 544 // j=min(m, r-i), aka expOld 545 // 546 // We expect this layout: 547 // indices: 0...i-1 i...i+j-1 548 // addresses: N0..Ni-1 O0..Oj-1 549 // 550 // There is at least one partition and at most three. 551 var ( 552 k = percentageOfNum(biasToSelectNewPeers, nAddrs) 553 expNew = tmmath.MinInt(nNew, tmmath.MaxInt(k, nAddrs-nBookOld)) 554 expOld = tmmath.MinInt(nOld, nAddrs-expNew) 555 ) 556 557 // Verify that the number of old and new addresses are as expected 558 if nNew != expNew { 559 t.Fatalf("%s - expected new addrs %d, got %d", dbgStr, expNew, nNew) 560 } 561 if nOld != expOld { 562 t.Fatalf("%s - expected old addrs %d, got %d", dbgStr, expOld, nOld) 563 } 564 565 // Verify that the order of addresses is as expected 566 // Get the sequence types and lengths of the selection 567 seqLens, seqTypes, err := analyseSelectionLayout(book, addrs) 568 assert.NoError(t, err, "%s", dbgStr) 569 570 // Build a list with the expected lengths of partitions and another with the expected types, e.g.: 571 // expSeqLens = [10, 22], expSeqTypes = [1, 2] 572 // means we expect 10 new (type 1) addresses followed by 22 old (type 2) addresses. 573 var expSeqLens []int 574 var expSeqTypes []int 575 576 switch { 577 case expOld == 0: // all new addresses 578 expSeqLens = []int{nAddrs} 579 expSeqTypes = []int{1} 580 case expNew == 0: // all old addresses 581 expSeqLens = []int{nAddrs} 582 expSeqTypes = []int{2} 583 case nAddrs-expNew-expOld == 0: // new addresses, old addresses 584 expSeqLens = []int{expNew, expOld} 585 expSeqTypes = []int{1, 2} 586 } 587 588 assert.Equal(t, expSeqLens, seqLens, 589 "%s - expected sequence lengths of old/new %v, got %v", 590 dbgStr, expSeqLens, seqLens) 591 assert.Equal(t, expSeqTypes, seqTypes, 592 "%s - expected sequence types (1-new, 2-old) was %v, got %v", 593 dbgStr, expSeqTypes, seqTypes) 594 } 595 } 596 597 func TestMultipleAddrBookAddressSelection(t *testing.T) { 598 // test books with smaller size, < N 599 const N = 32 600 for bookSize := 1; bookSize < N; bookSize++ { 601 testAddrBookAddressSelection(t, bookSize) 602 } 603 604 // Test for two books with sizes from following ranges 605 ranges := [...][]int{{33, 100}, {100, 175}} 606 bookSizes := make([]int, 0, len(ranges)) 607 for _, r := range ranges { 608 bookSizes = append(bookSizes, tmrand.Intn(r[1]-r[0])+r[0]) 609 } 610 t.Logf("Testing address selection for the following book sizes %v\n", bookSizes) 611 for _, bookSize := range bookSizes { 612 testAddrBookAddressSelection(t, bookSize) 613 } 614 } 615 616 func TestAddrBookAddDoesNotOverwriteOldIP(t *testing.T) { 617 fname := createTempFileName("addrbook_test") 618 defer deleteTempFile(fname) 619 620 // This test creates adds a peer to the address book and marks it good 621 // It then attempts to override the peer's IP, by adding a peer with the same ID 622 // but different IP. We distinguish the IP's by "RealIP" and "OverrideAttemptIP" 623 peerID := "678503e6c8f50db7279c7da3cb9b072aac4bc0d5" 624 peerRealIP := "1.1.1.1:26656" 625 peerOverrideAttemptIP := "2.2.2.2:26656" 626 SrcAddr := "b0dd378c3fbc4c156cd6d302a799f0d2e4227201@159.89.121.174:26656" 627 628 // There is a chance that AddAddress will ignore the new peer its given. 629 // So we repeat trying to override the peer several times, 630 // to ensure we aren't in a case that got probabilistically ignored 631 numOverrideAttempts := 10 632 633 peerRealAddr, err := p2p.NewNetAddressString(peerID + "@" + peerRealIP) 634 require.Nil(t, err) 635 636 peerOverrideAttemptAddr, err := p2p.NewNetAddressString(peerID + "@" + peerOverrideAttemptIP) 637 require.Nil(t, err) 638 639 src, err := p2p.NewNetAddressString(SrcAddr) 640 require.Nil(t, err) 641 642 book := NewAddrBook(fname, true) 643 book.SetLogger(log.TestingLogger()) 644 err = book.AddAddress(peerRealAddr, src) 645 require.Nil(t, err) 646 book.MarkAttempt(peerRealAddr) 647 book.MarkGood(peerRealAddr.ID) 648 649 // Double check that adding a peer again doesn't error 650 err = book.AddAddress(peerRealAddr, src) 651 require.Nil(t, err) 652 653 // Try changing ip but keeping the same node id. (change 1.1.1.1 to 2.2.2.2) 654 // This should just be ignored, and not error. 655 for i := 0; i < numOverrideAttempts; i++ { 656 err = book.AddAddress(peerOverrideAttemptAddr, src) 657 require.Nil(t, err) 658 } 659 // Now check that the IP was not overridden. 660 // This is done by sampling several peers from addr book 661 // and ensuring they all have the correct IP. 662 // In the expected functionality, this test should only have 1 Peer, hence will pass. 663 for i := 0; i < numOverrideAttempts; i++ { 664 selection := book.GetSelection() 665 for _, addr := range selection { 666 require.Equal(t, addr.IP, peerRealAddr.IP) 667 } 668 } 669 } 670 671 func TestAddrBookGroupKey(t *testing.T) { 672 // non-strict routability 673 testCases := []struct { 674 name string 675 ip string 676 expKey string 677 }{ 678 // IPv4 normal. 679 {"ipv4 normal class a", "12.1.2.3", "12.1.0.0"}, 680 {"ipv4 normal class b", "173.1.2.3", "173.1.0.0"}, 681 {"ipv4 normal class c", "196.1.2.3", "196.1.0.0"}, 682 683 // IPv6/IPv4 translations. 684 {"ipv6 rfc3964 with ipv4 encap", "2002:0c01:0203::", "12.1.0.0"}, 685 {"ipv6 rfc4380 toredo ipv4", "2001:0:1234::f3fe:fdfc", "12.1.0.0"}, 686 {"ipv6 rfc6052 well-known prefix with ipv4", "64:ff9b::0c01:0203", "12.1.0.0"}, 687 {"ipv6 rfc6145 translated ipv4", "::ffff:0:0c01:0203", "12.1.0.0"}, 688 689 // Tor. 690 {"ipv6 tor onioncat", "fd87:d87e:eb43:1234::5678", "tor:2"}, 691 {"ipv6 tor onioncat 2", "fd87:d87e:eb43:1245::6789", "tor:2"}, 692 {"ipv6 tor onioncat 3", "fd87:d87e:eb43:1345::6789", "tor:3"}, 693 694 // IPv6 normal. 695 {"ipv6 normal", "2602:100::1", "2602:100::"}, 696 {"ipv6 normal 2", "2602:0100::1234", "2602:100::"}, 697 {"ipv6 hurricane electric", "2001:470:1f10:a1::2", "2001:470:1000::"}, 698 {"ipv6 hurricane electric 2", "2001:0470:1f10:a1::2", "2001:470:1000::"}, 699 } 700 701 for i, tc := range testCases { 702 nip := net.ParseIP(tc.ip) 703 key := groupKeyFor(p2p.NewNetAddressIPPort(nip, 26656), false) 704 assert.Equal(t, tc.expKey, key, "#%d", i) 705 } 706 707 // strict routability 708 testCases = []struct { 709 name string 710 ip string 711 expKey string 712 }{ 713 // Local addresses. 714 {"ipv4 localhost", "127.0.0.1", "local"}, 715 {"ipv6 localhost", "::1", "local"}, 716 {"ipv4 zero", "0.0.0.0", "local"}, 717 {"ipv4 first octet zero", "0.1.2.3", "local"}, 718 719 // Unroutable addresses. 720 {"ipv4 invalid bcast", "255.255.255.255", "unroutable"}, 721 {"ipv4 rfc1918 10/8", "10.1.2.3", "unroutable"}, 722 {"ipv4 rfc1918 172.16/12", "172.16.1.2", "unroutable"}, 723 {"ipv4 rfc1918 192.168/16", "192.168.1.2", "unroutable"}, 724 {"ipv6 rfc3849 2001:db8::/32", "2001:db8::1234", "unroutable"}, 725 {"ipv4 rfc3927 169.254/16", "169.254.1.2", "unroutable"}, 726 {"ipv6 rfc4193 fc00::/7", "fc00::1234", "unroutable"}, 727 {"ipv6 rfc4843 2001:10::/28", "2001:10::1234", "unroutable"}, 728 {"ipv6 rfc4862 fe80::/64", "fe80::1234", "unroutable"}, 729 } 730 731 for i, tc := range testCases { 732 nip := net.ParseIP(tc.ip) 733 key := groupKeyFor(p2p.NewNetAddressIPPort(nip, 26656), true) 734 assert.Equal(t, tc.expKey, key, "#%d", i) 735 } 736 } 737 738 func assertMOldAndNNewAddrsInSelection(t *testing.T, m, n int, addrs []*p2p.NetAddress, book *addrBook) { 739 nOld, nNew := countOldAndNewAddrsInSelection(addrs, book) 740 assert.Equal(t, m, nOld, "old addresses") 741 assert.Equal(t, n, nNew, "new addresses") 742 } 743 744 func createTempFileName(prefix string) string { 745 f, err := ioutil.TempFile("", prefix) 746 if err != nil { 747 panic(err) 748 } 749 fname := f.Name() 750 err = f.Close() 751 if err != nil { 752 panic(err) 753 } 754 return fname 755 } 756 757 func deleteTempFile(fname string) { 758 err := os.Remove(fname) 759 if err != nil { 760 panic(err) 761 } 762 } 763 764 func createAddrBookWithMOldAndNNewAddrs(t *testing.T, nOld, nNew int) (book *addrBook, fname string) { 765 fname = createTempFileName("addrbook_test") 766 767 book = NewAddrBook(fname, true).(*addrBook) 768 book.SetLogger(log.TestingLogger()) 769 assert.Zero(t, book.Size()) 770 771 randAddrs := randNetAddressPairs(t, nOld) 772 for _, addr := range randAddrs { 773 err := book.AddAddress(addr.addr, addr.src) 774 require.NoError(t, err) 775 book.MarkGood(addr.addr.ID) 776 } 777 778 randAddrs = randNetAddressPairs(t, nNew) 779 for _, addr := range randAddrs { 780 err := book.AddAddress(addr.addr, addr.src) 781 require.NoError(t, err) 782 } 783 784 return 785 } 786 787 func countOldAndNewAddrsInSelection(addrs []*p2p.NetAddress, book *addrBook) (nOld, nNew int) { 788 for _, addr := range addrs { 789 if book.IsGood(addr) { 790 nOld++ 791 } else { 792 nNew++ 793 } 794 } 795 return 796 } 797 798 // Analyse the layout of the selection specified by 'addrs' 799 // Returns: 800 // - seqLens - the lengths of the sequences of addresses of same type 801 // - seqTypes - the types of sequences in selection 802 func analyseSelectionLayout(book *addrBook, addrs []*p2p.NetAddress) (seqLens, seqTypes []int, err error) { 803 // address types are: 0 - nil, 1 - new, 2 - old 804 var ( 805 prevType = 0 806 currentSeqLen = 0 807 ) 808 809 for _, addr := range addrs { 810 addrType := 0 811 if book.IsGood(addr) { 812 addrType = 2 813 } else { 814 addrType = 1 815 } 816 if addrType != prevType && prevType != 0 { 817 seqLens = append(seqLens, currentSeqLen) 818 seqTypes = append(seqTypes, prevType) 819 currentSeqLen = 0 820 } 821 currentSeqLen++ 822 prevType = addrType 823 } 824 825 seqLens = append(seqLens, currentSeqLen) 826 seqTypes = append(seqTypes, prevType) 827 828 return 829 }