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  }