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