github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/swarm/network/kademlia_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package network
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/p2p"
    28  	"github.com/ethereum/go-ethereum/p2p/enode"
    29  	"github.com/ethereum/go-ethereum/p2p/protocols"
    30  	"github.com/ethereum/go-ethereum/swarm/pot"
    31  )
    32  
    33  func init() {
    34  	h := log.LvlFilterHandler(log.LvlWarn, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))
    35  	log.Root().SetHandler(h)
    36  }
    37  
    38  func testKadPeerAddr(s string) *BzzAddr {
    39  	a := pot.NewAddressFromString(s)
    40  	return &BzzAddr{OAddr: a, UAddr: a}
    41  }
    42  
    43  func newTestKademliaParams() *KadParams {
    44  	params := NewKadParams()
    45  	params.MinBinSize = 2
    46  	params.NeighbourhoodSize = 2
    47  	return params
    48  }
    49  
    50  type testKademlia struct {
    51  	*Kademlia
    52  	t *testing.T
    53  }
    54  
    55  func newTestKademlia(t *testing.T, b string) *testKademlia {
    56  	base := pot.NewAddressFromString(b)
    57  	return &testKademlia{
    58  		Kademlia: NewKademlia(base, newTestKademliaParams()),
    59  		t:        t,
    60  	}
    61  }
    62  
    63  func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer {
    64  	return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia)
    65  }
    66  
    67  func (tk *testKademlia) On(ons ...string) {
    68  	for _, s := range ons {
    69  		tk.Kademlia.On(tk.newTestKadPeer(s, false))
    70  	}
    71  }
    72  
    73  func (tk *testKademlia) Off(offs ...string) {
    74  	for _, s := range offs {
    75  		tk.Kademlia.Off(tk.newTestKadPeer(s, false))
    76  	}
    77  }
    78  
    79  func (tk *testKademlia) Register(regs ...string) {
    80  	var as []*BzzAddr
    81  	for _, s := range regs {
    82  		as = append(as, testKadPeerAddr(s))
    83  	}
    84  	err := tk.Kademlia.Register(as...)
    85  	if err != nil {
    86  		panic(err.Error())
    87  	}
    88  }
    89  
    90  // tests the validity of neighborhood depth calculations
    91  //
    92  // in particular, it tests that if there are one or more consecutive
    93  // empty bins above the farthest "nearest neighbor-peer" then
    94  // the depth should be set at the farthest of those empty bins
    95  //
    96  // TODO: Make test adapt to change in NeighbourhoodSize
    97  func TestNeighbourhoodDepth(t *testing.T) {
    98  	baseAddressBytes := RandomAddr().OAddr
    99  	kad := NewKademlia(baseAddressBytes, NewKadParams())
   100  
   101  	baseAddress := pot.NewAddressFromBytes(baseAddressBytes)
   102  
   103  	// generate the peers
   104  	var peers []*Peer
   105  	for i := 0; i < 7; i++ {
   106  		addr := pot.RandomAddressAt(baseAddress, i)
   107  		peers = append(peers, newTestDiscoveryPeer(addr, kad))
   108  	}
   109  	var sevenPeers []*Peer
   110  	for i := 0; i < 2; i++ {
   111  		addr := pot.RandomAddressAt(baseAddress, 7)
   112  		sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad))
   113  	}
   114  
   115  	testNum := 0
   116  	// first try with empty kademlia
   117  	depth := kad.NeighbourhoodDepth()
   118  	if depth != 0 {
   119  		t.Fatalf("%d expected depth 0, was %d", testNum, depth)
   120  	}
   121  	testNum++
   122  
   123  	// add one peer on 7
   124  	kad.On(sevenPeers[0])
   125  	depth = kad.NeighbourhoodDepth()
   126  	if depth != 0 {
   127  		t.Fatalf("%d expected depth 0, was %d", testNum, depth)
   128  	}
   129  	testNum++
   130  
   131  	// add a second on 7
   132  	kad.On(sevenPeers[1])
   133  	depth = kad.NeighbourhoodDepth()
   134  	if depth != 0 {
   135  		t.Fatalf("%d expected depth 0, was %d", testNum, depth)
   136  	}
   137  	testNum++
   138  
   139  	// add from 0 to 6
   140  	for i, p := range peers {
   141  		kad.On(p)
   142  		depth = kad.NeighbourhoodDepth()
   143  		if depth != i+1 {
   144  			t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth)
   145  		}
   146  	}
   147  	testNum++
   148  
   149  	kad.Off(sevenPeers[1])
   150  	depth = kad.NeighbourhoodDepth()
   151  	if depth != 6 {
   152  		t.Fatalf("%d expected depth 6, was %d", testNum, depth)
   153  	}
   154  	testNum++
   155  
   156  	kad.Off(peers[4])
   157  	depth = kad.NeighbourhoodDepth()
   158  	if depth != 4 {
   159  		t.Fatalf("%d expected depth 4, was %d", testNum, depth)
   160  	}
   161  	testNum++
   162  
   163  	kad.Off(peers[3])
   164  	depth = kad.NeighbourhoodDepth()
   165  	if depth != 3 {
   166  		t.Fatalf("%d expected depth 3, was %d", testNum, depth)
   167  	}
   168  	testNum++
   169  }
   170  
   171  // TestHealthStrict tests the simplest definition of health
   172  // Which means whether we are connected to all neighbors we know of
   173  func TestHealthStrict(t *testing.T) {
   174  
   175  	// base address is all zeros
   176  	// no peers
   177  	// unhealthy (and lonely)
   178  	tk := newTestKademlia(t, "11111111")
   179  	tk.checkHealth(false, false)
   180  
   181  	// know one peer but not connected
   182  	// unhealthy
   183  	tk.Register("11100000")
   184  	tk.checkHealth(false, false)
   185  
   186  	// know one peer and connected
   187  	// healthy
   188  	tk.On("11100000")
   189  	tk.checkHealth(true, false)
   190  
   191  	// know two peers, only one connected
   192  	// unhealthy
   193  	tk.Register("11111100")
   194  	tk.checkHealth(false, false)
   195  
   196  	// know two peers and connected to both
   197  	// healthy
   198  	tk.On("11111100")
   199  	tk.checkHealth(true, false)
   200  
   201  	// know three peers, connected to the two deepest
   202  	// healthy
   203  	tk.Register("00000000")
   204  	tk.checkHealth(true, false)
   205  
   206  	// know three peers, connected to all three
   207  	// healthy
   208  	tk.On("00000000")
   209  	tk.checkHealth(true, false)
   210  
   211  	// add fourth peer deeper than current depth
   212  	// unhealthy
   213  	tk.Register("11110000")
   214  	tk.checkHealth(false, false)
   215  
   216  	// connected to three deepest peers
   217  	// healthy
   218  	tk.On("11110000")
   219  	tk.checkHealth(true, false)
   220  
   221  	// add additional peer in same bin as deepest peer
   222  	// unhealthy
   223  	tk.Register("11111101")
   224  	tk.checkHealth(false, false)
   225  
   226  	// four deepest of five peers connected
   227  	// healthy
   228  	tk.On("11111101")
   229  	tk.checkHealth(true, false)
   230  }
   231  
   232  func (tk *testKademlia) checkHealth(expectHealthy bool, expectSaturation bool) {
   233  	tk.t.Helper()
   234  	kid := common.Bytes2Hex(tk.BaseAddr())
   235  	addrs := [][]byte{tk.BaseAddr()}
   236  	tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool {
   237  		addrs = append(addrs, addr.Address())
   238  		return true
   239  	})
   240  
   241  	pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs)
   242  	healthParams := tk.Healthy(pp[kid])
   243  
   244  	// definition of health, all conditions but be true:
   245  	// - we at least know one peer
   246  	// - we know all neighbors
   247  	// - we are connected to all known neighbors
   248  	health := healthParams.KnowNN && healthParams.ConnectNN && healthParams.CountKnowNN > 0
   249  	if expectHealthy != health {
   250  		tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String())
   251  	}
   252  }
   253  
   254  func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) {
   255  	tk.t.Helper()
   256  	addr, depth, changed := tk.SuggestPeer()
   257  	log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed)
   258  	if binStr(addr) != expAddr {
   259  		tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr))
   260  	}
   261  	if depth != expDepth {
   262  		tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth)
   263  	}
   264  	if changed != expChanged {
   265  		tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed)
   266  	}
   267  }
   268  
   269  func binStr(a *BzzAddr) string {
   270  	if a == nil {
   271  		return "<nil>"
   272  	}
   273  	return pot.ToBin(a.Address())[:8]
   274  }
   275  
   276  func TestSuggestPeerFindPeers(t *testing.T) {
   277  	tk := newTestKademlia(t, "00000000")
   278  	tk.On("00100000")
   279  	tk.checkSuggestPeer("<nil>", 0, false)
   280  
   281  	tk.On("00010000")
   282  	tk.checkSuggestPeer("<nil>", 0, false)
   283  
   284  	tk.On("10000000", "10000001")
   285  	tk.checkSuggestPeer("<nil>", 0, false)
   286  
   287  	tk.On("01000000")
   288  	tk.Off("10000001")
   289  	tk.checkSuggestPeer("10000001", 0, true)
   290  
   291  	tk.On("00100001")
   292  	tk.Off("01000000")
   293  	tk.checkSuggestPeer("01000000", 0, false)
   294  
   295  	// second time disconnected peer not callable
   296  	// with reasonably set Interval
   297  	tk.checkSuggestPeer("<nil>", 0, false)
   298  
   299  	// on and off again, peer callable again
   300  	tk.On("01000000")
   301  	tk.Off("01000000")
   302  	tk.checkSuggestPeer("01000000", 0, false)
   303  
   304  	tk.On("01000000", "10000001")
   305  	tk.checkSuggestPeer("<nil>", 0, false)
   306  
   307  	tk.Register("00010001")
   308  	tk.checkSuggestPeer("00010001", 0, false)
   309  
   310  	tk.On("00010001")
   311  	tk.Off("01000000")
   312  	tk.checkSuggestPeer("01000000", 0, false)
   313  
   314  	tk.On("01000000")
   315  	tk.checkSuggestPeer("<nil>", 0, false)
   316  
   317  	tk.Register("01000001")
   318  	tk.checkSuggestPeer("01000001", 0, false)
   319  
   320  	tk.On("01000001")
   321  	tk.checkSuggestPeer("<nil>", 0, false)
   322  
   323  	tk.Register("10000010", "01000010", "00100010")
   324  	tk.checkSuggestPeer("<nil>", 0, false)
   325  
   326  	tk.Register("00010010")
   327  	tk.checkSuggestPeer("00010010", 0, false)
   328  
   329  	tk.Off("00100001")
   330  	tk.checkSuggestPeer("00100010", 2, true)
   331  
   332  	tk.Off("01000001")
   333  	tk.checkSuggestPeer("01000010", 1, true)
   334  
   335  	tk.checkSuggestPeer("01000001", 0, false)
   336  	tk.checkSuggestPeer("00100001", 0, false)
   337  	tk.checkSuggestPeer("<nil>", 0, false)
   338  
   339  	tk.On("01000001", "00100001")
   340  	tk.Register("10000100", "01000100", "00100100")
   341  	tk.Register("00000100", "00000101", "00000110")
   342  	tk.Register("00000010", "00000011", "00000001")
   343  
   344  	tk.checkSuggestPeer("00000110", 0, false)
   345  	tk.checkSuggestPeer("00000101", 0, false)
   346  	tk.checkSuggestPeer("00000100", 0, false)
   347  	tk.checkSuggestPeer("00000011", 0, false)
   348  	tk.checkSuggestPeer("00000010", 0, false)
   349  	tk.checkSuggestPeer("00000001", 0, false)
   350  	tk.checkSuggestPeer("<nil>", 0, false)
   351  
   352  }
   353  
   354  // a node should stay in the address book if it's removed from the kademlia
   355  func TestOffEffectingAddressBookNormalNode(t *testing.T) {
   356  	tk := newTestKademlia(t, "00000000")
   357  	// peer added to kademlia
   358  	tk.On("01000000")
   359  	// peer should be in the address book
   360  	if tk.addrs.Size() != 1 {
   361  		t.Fatal("known peer addresses should contain 1 entry")
   362  	}
   363  	// peer should be among live connections
   364  	if tk.conns.Size() != 1 {
   365  		t.Fatal("live peers should contain 1 entry")
   366  	}
   367  	// remove peer from kademlia
   368  	tk.Off("01000000")
   369  	// peer should be in the address book
   370  	if tk.addrs.Size() != 1 {
   371  		t.Fatal("known peer addresses should contain 1 entry")
   372  	}
   373  	// peer should not be among live connections
   374  	if tk.conns.Size() != 0 {
   375  		t.Fatal("live peers should contain 0 entry")
   376  	}
   377  }
   378  
   379  // a light node should not be in the address book
   380  func TestOffEffectingAddressBookLightNode(t *testing.T) {
   381  	tk := newTestKademlia(t, "00000000")
   382  	// light node peer added to kademlia
   383  	tk.Kademlia.On(tk.newTestKadPeer("01000000", true))
   384  	// peer should not be in the address book
   385  	if tk.addrs.Size() != 0 {
   386  		t.Fatal("known peer addresses should contain 0 entry")
   387  	}
   388  	// peer should be among live connections
   389  	if tk.conns.Size() != 1 {
   390  		t.Fatal("live peers should contain 1 entry")
   391  	}
   392  	// remove peer from kademlia
   393  	tk.Kademlia.Off(tk.newTestKadPeer("01000000", true))
   394  	// peer should not be in the address book
   395  	if tk.addrs.Size() != 0 {
   396  		t.Fatal("known peer addresses should contain 0 entry")
   397  	}
   398  	// peer should not be among live connections
   399  	if tk.conns.Size() != 0 {
   400  		t.Fatal("live peers should contain 0 entry")
   401  	}
   402  }
   403  
   404  func TestSuggestPeerRetries(t *testing.T) {
   405  	tk := newTestKademlia(t, "00000000")
   406  	tk.RetryInterval = int64(300 * time.Millisecond) // cycle
   407  	tk.MaxRetries = 50
   408  	tk.RetryExponent = 2
   409  	sleep := func(n int) {
   410  		ts := tk.RetryInterval
   411  		for i := 1; i < n; i++ {
   412  			ts *= int64(tk.RetryExponent)
   413  		}
   414  		time.Sleep(time.Duration(ts))
   415  	}
   416  
   417  	tk.Register("01000000")
   418  	tk.On("00000001", "00000010")
   419  	tk.checkSuggestPeer("01000000", 0, false)
   420  
   421  	tk.checkSuggestPeer("<nil>", 0, false)
   422  
   423  	sleep(1)
   424  	tk.checkSuggestPeer("01000000", 0, false)
   425  
   426  	tk.checkSuggestPeer("<nil>", 0, false)
   427  
   428  	sleep(1)
   429  	tk.checkSuggestPeer("01000000", 0, false)
   430  
   431  	tk.checkSuggestPeer("<nil>", 0, false)
   432  
   433  	sleep(2)
   434  	tk.checkSuggestPeer("01000000", 0, false)
   435  
   436  	tk.checkSuggestPeer("<nil>", 0, false)
   437  
   438  	sleep(2)
   439  	tk.checkSuggestPeer("<nil>", 0, false)
   440  }
   441  
   442  func TestKademliaHiveString(t *testing.T) {
   443  	tk := newTestKademlia(t, "00000000")
   444  	tk.On("01000000", "00100000")
   445  	tk.Register("10000000", "10000001")
   446  	tk.MaxProxDisplay = 8
   447  	h := tk.String()
   448  	expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000  0                              |  2 8100 (0) 8000 (0)\n001  1 4000                         |  1 4000 (0)\n002  1 2000                         |  1 2000 (0)\n003  0                              |  0\n004  0                              |  0\n005  0                              |  0\n006  0                              |  0\n007  0                              |  0\n========================================================================="
   449  	if expH[104:] != h[104:] {
   450  		t.Fatalf("incorrect hive output. expected %v, got %v", expH, h)
   451  	}
   452  }
   453  
   454  func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer {
   455  	rw := &p2p.MsgPipeRW{}
   456  	p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{})
   457  	pp := protocols.NewPeer(p, rw, &protocols.Spec{})
   458  	bp := &BzzPeer{
   459  		Peer: pp,
   460  		BzzAddr: &BzzAddr{
   461  			OAddr: addr.Bytes(),
   462  			UAddr: []byte(fmt.Sprintf("%x", addr[:])),
   463  		},
   464  	}
   465  	return NewPeer(bp, kad)
   466  }