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