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