github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/network/kademlia_test.go (about)

     1  // Copyleft 2018 The susy-graviton Authors
     2  // This file is part of the susy-graviton library.
     3  //
     4  // The susy-graviton 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 susy-graviton library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MSRCHANTABILITY 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 susy-graviton 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/susy-go/susy-graviton/common"
    26  	"github.com/susy-go/susy-graviton/log"
    27  	"github.com/susy-go/susy-graviton/p2p"
    28  	"github.com/susy-go/susy-graviton/p2p/enode"
    29  	"github.com/susy-go/susy-graviton/p2p/protocols"
    30  	"github.com/susy-go/susy-graviton/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  // TestHighMinBinSize tests that the saturation function also works
   172  // if MinBinSize is > 2, the connection count is < k.MinBinSize
   173  // and there are more peers available than connected
   174  func TestHighMinBinSize(t *testing.T) {
   175  	// a function to test for different MinBinSize values
   176  	testKad := func(minBinSize int) {
   177  		// create a test kademlia
   178  		tk := newTestKademlia(t, "11111111")
   179  		// set its MinBinSize to desired value
   180  		tk.KadParams.MinBinSize = minBinSize
   181  
   182  		// add a couple of peers (so we have NN and depth)
   183  		tk.On("00000000") // bin 0
   184  		tk.On("11100000") // bin 3
   185  		tk.On("11110000") // bin 4
   186  
   187  		first := "10000000" // add a first peer at bin 1
   188  		tk.Register(first)  // register it
   189  		// we now have one registered peer at bin 1;
   190  		// iterate and connect one peer at each iteration;
   191  		// should be unhealthy until at minBinSize - 1
   192  		// we connect the unconnected but registered peer
   193  		for i := 1; i < minBinSize; i++ {
   194  			peer := fmt.Sprintf("1000%b", 8|i)
   195  			tk.On(peer)
   196  			if i == minBinSize-1 {
   197  				tk.On(first)
   198  				tk.checkHealth(true)
   199  				return
   200  			}
   201  			tk.checkHealth(false)
   202  		}
   203  	}
   204  	// test MinBinSizes of 3 to 5
   205  	testMinBinSizes := []int{3, 4, 5}
   206  	for _, k := range testMinBinSizes {
   207  		testKad(k)
   208  	}
   209  }
   210  
   211  // TestHealthStrict tests the simplest definition of health
   212  // Which means whether we are connected to all neighbors we know of
   213  func TestHealthStrict(t *testing.T) {
   214  
   215  	// base address is all zeros
   216  	// no peers
   217  	// unhealthy (and lonely)
   218  	tk := newTestKademlia(t, "11111111")
   219  	tk.checkHealth(false)
   220  
   221  	// know one peer but not connected
   222  	// unhealthy
   223  	tk.Register("11100000")
   224  	tk.checkHealth(false)
   225  
   226  	// know one peer and connected
   227  	// unhealthy: not saturated
   228  	tk.On("11100000")
   229  	tk.checkHealth(true)
   230  
   231  	// know two peers, only one connected
   232  	// unhealthy
   233  	tk.Register("11111100")
   234  	tk.checkHealth(false)
   235  
   236  	// know two peers and connected to both
   237  	// healthy
   238  	tk.On("11111100")
   239  	tk.checkHealth(true)
   240  
   241  	// know three peers, connected to the two deepest
   242  	// healthy
   243  	tk.Register("00000000")
   244  	tk.checkHealth(false)
   245  
   246  	// know three peers, connected to all three
   247  	// healthy
   248  	tk.On("00000000")
   249  	tk.checkHealth(true)
   250  
   251  	// add fourth peer deeper than current depth
   252  	// unhealthy
   253  	tk.Register("11110000")
   254  	tk.checkHealth(false)
   255  
   256  	// connected to three deepest peers
   257  	// healthy
   258  	tk.On("11110000")
   259  	tk.checkHealth(true)
   260  
   261  	// add additional peer in same bin as deepest peer
   262  	// unhealthy
   263  	tk.Register("11111101")
   264  	tk.checkHealth(false)
   265  
   266  	// four deepest of five peers connected
   267  	// healthy
   268  	tk.On("11111101")
   269  	tk.checkHealth(true)
   270  
   271  	// add additional peer in bin 0
   272  	// unhealthy: unsaturated bin 0, 2 known but 1 connected
   273  	tk.Register("00000001")
   274  	tk.checkHealth(false)
   275  
   276  	// Connect second in bin 0
   277  	// healthy
   278  	tk.On("00000001")
   279  	tk.checkHealth(true)
   280  
   281  	// add peer in bin 1
   282  	// unhealthy, as it is known but not connected
   283  	tk.Register("10000000")
   284  	tk.checkHealth(false)
   285  
   286  	// connect  peer in bin 1
   287  	// depth change, is now 1
   288  	// healthy, 1 peer in bin 1 known and connected
   289  	tk.On("10000000")
   290  	tk.checkHealth(true)
   291  
   292  	// add second peer in bin 1
   293  	// unhealthy, as it is known but not connected
   294  	tk.Register("10000001")
   295  	tk.checkHealth(false)
   296  
   297  	// connect second peer in bin 1
   298  	// healthy,
   299  	tk.On("10000001")
   300  	tk.checkHealth(true)
   301  
   302  	// connect third peer in bin 1
   303  	// healthy,
   304  	tk.On("10000011")
   305  	tk.checkHealth(true)
   306  
   307  	// add peer in bin 2
   308  	// unhealthy, no depth change
   309  	tk.Register("11000000")
   310  	tk.checkHealth(false)
   311  
   312  	// connect peer in bin 2
   313  	// depth change - as we already have peers in bin 3 and 4,
   314  	// we have contiguous bins, no bin < po 5 is empty -> depth 5
   315  	// healthy, every bin < depth has the max available peers,
   316  	// even if they are < MinBinSize
   317  	tk.On("11000000")
   318  	tk.checkHealth(true)
   319  
   320  	// add peer in bin 2
   321  	// unhealthy, peer bin is below depth 5 but
   322  	// has more available peers (2) than connected ones (1)
   323  	// --> unsaturated
   324  	tk.Register("11000011")
   325  	tk.checkHealth(false)
   326  }
   327  
   328  func (tk *testKademlia) checkHealth(expectHealthy bool) {
   329  	tk.t.Helper()
   330  	kid := common.Bytes2Hex(tk.BaseAddr())
   331  	addrs := [][]byte{tk.BaseAddr()}
   332  	tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool {
   333  		addrs = append(addrs, addr.Address())
   334  		return true
   335  	})
   336  
   337  	pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs)
   338  	healthParams := tk.GetHealthInfo(pp[kid])
   339  
   340  	// definition of health, all conditions but be true:
   341  	// - we at least know one peer
   342  	// - we know all neighbors
   343  	// - we are connected to all known neighbors
   344  	health := healthParams.Healthy()
   345  	if expectHealthy != health {
   346  		tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String())
   347  	}
   348  }
   349  
   350  func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) {
   351  	tk.t.Helper()
   352  	addr, depth, changed := tk.SuggestPeer()
   353  	log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed)
   354  	if binStr(addr) != expAddr {
   355  		tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr))
   356  	}
   357  	if depth != expDepth {
   358  		tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth)
   359  	}
   360  	if changed != expChanged {
   361  		tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed)
   362  	}
   363  }
   364  
   365  func binStr(a *BzzAddr) string {
   366  	if a == nil {
   367  		return "<nil>"
   368  	}
   369  	return pot.ToBin(a.Address())[:8]
   370  }
   371  
   372  func TestSuggestPeerFindPeers(t *testing.T) {
   373  	tk := newTestKademlia(t, "00000000")
   374  	tk.On("00100000")
   375  	tk.checkSuggestPeer("<nil>", 0, false)
   376  
   377  	tk.On("00010000")
   378  	tk.checkSuggestPeer("<nil>", 0, false)
   379  
   380  	tk.On("10000000", "10000001")
   381  	tk.checkSuggestPeer("<nil>", 0, false)
   382  
   383  	tk.On("01000000")
   384  	tk.Off("10000001")
   385  	tk.checkSuggestPeer("10000001", 0, true)
   386  
   387  	tk.On("00100001")
   388  	tk.Off("01000000")
   389  	tk.checkSuggestPeer("01000000", 0, false)
   390  
   391  	// second time disconnected peer not callable
   392  	// with reasonably set Interval
   393  	tk.checkSuggestPeer("<nil>", 0, false)
   394  
   395  	// on and off again, peer callable again
   396  	tk.On("01000000")
   397  	tk.Off("01000000")
   398  	tk.checkSuggestPeer("01000000", 0, false)
   399  
   400  	tk.On("01000000", "10000001")
   401  	tk.checkSuggestPeer("<nil>", 0, false)
   402  
   403  	tk.Register("00010001")
   404  	tk.checkSuggestPeer("00010001", 0, false)
   405  
   406  	tk.On("00010001")
   407  	tk.Off("01000000")
   408  	tk.checkSuggestPeer("01000000", 0, false)
   409  
   410  	tk.On("01000000")
   411  	tk.checkSuggestPeer("<nil>", 0, false)
   412  
   413  	tk.Register("01000001")
   414  	tk.checkSuggestPeer("01000001", 0, false)
   415  
   416  	tk.On("01000001")
   417  	tk.checkSuggestPeer("<nil>", 0, false)
   418  
   419  	tk.Register("10000010", "01000010", "00100010")
   420  	tk.checkSuggestPeer("<nil>", 0, false)
   421  
   422  	tk.Register("00010010")
   423  	tk.checkSuggestPeer("00010010", 0, false)
   424  
   425  	tk.Off("00100001")
   426  	tk.checkSuggestPeer("00100010", 2, true)
   427  
   428  	tk.Off("01000001")
   429  	tk.checkSuggestPeer("01000010", 1, true)
   430  
   431  	tk.checkSuggestPeer("01000001", 0, false)
   432  	tk.checkSuggestPeer("00100001", 0, false)
   433  	tk.checkSuggestPeer("<nil>", 0, false)
   434  
   435  	tk.On("01000001", "00100001")
   436  	tk.Register("10000100", "01000100", "00100100")
   437  	tk.Register("00000100", "00000101", "00000110")
   438  	tk.Register("00000010", "00000011", "00000001")
   439  
   440  	tk.checkSuggestPeer("00000110", 0, false)
   441  	tk.checkSuggestPeer("00000101", 0, false)
   442  	tk.checkSuggestPeer("00000100", 0, false)
   443  	tk.checkSuggestPeer("00000011", 0, false)
   444  	tk.checkSuggestPeer("00000010", 0, false)
   445  	tk.checkSuggestPeer("00000001", 0, false)
   446  	tk.checkSuggestPeer("<nil>", 0, false)
   447  
   448  }
   449  
   450  // a node should stay in the address book if it's removed from the kademlia
   451  func TestOffEffectingAddressBookNormalNode(t *testing.T) {
   452  	tk := newTestKademlia(t, "00000000")
   453  	// peer added to kademlia
   454  	tk.On("01000000")
   455  	// peer should be in the address book
   456  	if tk.addrs.Size() != 1 {
   457  		t.Fatal("known peer addresses should contain 1 entry")
   458  	}
   459  	// peer should be among live connections
   460  	if tk.conns.Size() != 1 {
   461  		t.Fatal("live peers should contain 1 entry")
   462  	}
   463  	// remove peer from kademlia
   464  	tk.Off("01000000")
   465  	// peer should be in the address book
   466  	if tk.addrs.Size() != 1 {
   467  		t.Fatal("known peer addresses should contain 1 entry")
   468  	}
   469  	// peer should not be among live connections
   470  	if tk.conns.Size() != 0 {
   471  		t.Fatal("live peers should contain 0 entry")
   472  	}
   473  }
   474  
   475  // a light node should not be in the address book
   476  func TestOffEffectingAddressBookLightNode(t *testing.T) {
   477  	tk := newTestKademlia(t, "00000000")
   478  	// light node peer added to kademlia
   479  	tk.Kademlia.On(tk.newTestKadPeer("01000000", true))
   480  	// peer should not be in the address book
   481  	if tk.addrs.Size() != 0 {
   482  		t.Fatal("known peer addresses should contain 0 entry")
   483  	}
   484  	// peer should be among live connections
   485  	if tk.conns.Size() != 1 {
   486  		t.Fatal("live peers should contain 1 entry")
   487  	}
   488  	// remove peer from kademlia
   489  	tk.Kademlia.Off(tk.newTestKadPeer("01000000", true))
   490  	// peer should not be in the address book
   491  	if tk.addrs.Size() != 0 {
   492  		t.Fatal("known peer addresses should contain 0 entry")
   493  	}
   494  	// peer should not be among live connections
   495  	if tk.conns.Size() != 0 {
   496  		t.Fatal("live peers should contain 0 entry")
   497  	}
   498  }
   499  
   500  func TestSuggestPeerRetries(t *testing.T) {
   501  	tk := newTestKademlia(t, "00000000")
   502  	tk.RetryInterval = int64(300 * time.Millisecond) // cycle
   503  	tk.MaxRetries = 50
   504  	tk.RetryExponent = 2
   505  	sleep := func(n int) {
   506  		ts := tk.RetryInterval
   507  		for i := 1; i < n; i++ {
   508  			ts *= int64(tk.RetryExponent)
   509  		}
   510  		time.Sleep(time.Duration(ts))
   511  	}
   512  
   513  	tk.Register("01000000")
   514  	tk.On("00000001", "00000010")
   515  	tk.checkSuggestPeer("01000000", 0, false)
   516  
   517  	tk.checkSuggestPeer("<nil>", 0, false)
   518  
   519  	sleep(1)
   520  	tk.checkSuggestPeer("01000000", 0, false)
   521  
   522  	tk.checkSuggestPeer("<nil>", 0, false)
   523  
   524  	sleep(1)
   525  	tk.checkSuggestPeer("01000000", 0, false)
   526  
   527  	tk.checkSuggestPeer("<nil>", 0, false)
   528  
   529  	sleep(2)
   530  	tk.checkSuggestPeer("01000000", 0, false)
   531  
   532  	tk.checkSuggestPeer("<nil>", 0, false)
   533  
   534  	sleep(2)
   535  	tk.checkSuggestPeer("<nil>", 0, false)
   536  }
   537  
   538  func TestKademliaHiveString(t *testing.T) {
   539  	tk := newTestKademlia(t, "00000000")
   540  	tk.On("01000000", "00100000")
   541  	tk.Register("10000000", "10000001")
   542  	tk.MaxProxDisplay = 8
   543  	h := tk.String()
   544  	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========================================================================="
   545  	if expH[104:] != h[104:] {
   546  		t.Fatalf("incorrect hive output. expected %v, got %v", expH, h)
   547  	}
   548  }
   549  
   550  func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer {
   551  	rw := &p2p.MsgPipeRW{}
   552  	p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{})
   553  	pp := protocols.NewPeer(p, rw, &protocols.Spec{})
   554  	bp := &BzzPeer{
   555  		Peer: pp,
   556  		BzzAddr: &BzzAddr{
   557  			OAddr: addr.Bytes(),
   558  			UAddr: []byte(fmt.Sprintf("%x", addr[:])),
   559  		},
   560  	}
   561  	return NewPeer(bp, kad)
   562  }