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