github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/p2p/pex/addrbook_test.go (about)

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