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