diff options
Diffstat (limited to 'swarm/network/kademlia_test.go')
-rw-r--r-- | swarm/network/kademlia_test.go | 672 |
1 files changed, 0 insertions, 672 deletions
diff --git a/swarm/network/kademlia_test.go b/swarm/network/kademlia_test.go deleted file mode 100644 index 035879cd3..000000000 --- a/swarm/network/kademlia_test.go +++ /dev/null @@ -1,672 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package network - -import ( - "fmt" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/protocols" - "github.com/ethereum/go-ethereum/swarm/pot" -) - -func init() { - h := log.LvlFilterHandler(log.LvlWarn, log.StreamHandler(os.Stderr, log.TerminalFormat(true))) - log.Root().SetHandler(h) -} - -func testKadPeerAddr(s string) *BzzAddr { - a := pot.NewAddressFromString(s) - return &BzzAddr{OAddr: a, UAddr: a} -} - -func newTestKademliaParams() *KadParams { - params := NewKadParams() - params.MinBinSize = 2 - params.NeighbourhoodSize = 2 - return params -} - -type testKademlia struct { - *Kademlia - t *testing.T -} - -func newTestKademlia(t *testing.T, b string) *testKademlia { - base := pot.NewAddressFromString(b) - return &testKademlia{ - Kademlia: NewKademlia(base, newTestKademliaParams()), - t: t, - } -} - -func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { - return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) -} - -func (tk *testKademlia) On(ons ...string) { - for _, s := range ons { - tk.Kademlia.On(tk.newTestKadPeer(s, false)) - } -} - -func (tk *testKademlia) Off(offs ...string) { - for _, s := range offs { - tk.Kademlia.Off(tk.newTestKadPeer(s, false)) - } -} - -func (tk *testKademlia) Register(regs ...string) { - var as []*BzzAddr - for _, s := range regs { - as = append(as, testKadPeerAddr(s)) - } - err := tk.Kademlia.Register(as...) - if err != nil { - panic(err.Error()) - } -} - -// tests the validity of neighborhood depth calculations -// -// in particular, it tests that if there are one or more consecutive -// empty bins above the farthest "nearest neighbor-peer" then -// the depth should be set at the farthest of those empty bins -// -// TODO: Make test adapt to change in NeighbourhoodSize -func TestNeighbourhoodDepth(t *testing.T) { - baseAddressBytes := RandomAddr().OAddr - kad := NewKademlia(baseAddressBytes, NewKadParams()) - - baseAddress := pot.NewAddressFromBytes(baseAddressBytes) - - // generate the peers - var peers []*Peer - for i := 0; i < 7; i++ { - addr := pot.RandomAddressAt(baseAddress, i) - peers = append(peers, newTestDiscoveryPeer(addr, kad)) - } - var sevenPeers []*Peer - for i := 0; i < 2; i++ { - addr := pot.RandomAddressAt(baseAddress, 7) - sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad)) - } - - testNum := 0 - // first try with empty kademlia - depth := kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add one peer on 7 - kad.On(sevenPeers[0]) - depth = kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add a second on 7 - kad.On(sevenPeers[1]) - depth = kad.NeighbourhoodDepth() - if depth != 0 { - t.Fatalf("%d expected depth 0, was %d", testNum, depth) - } - testNum++ - - // add from 0 to 6 - for i, p := range peers { - kad.On(p) - depth = kad.NeighbourhoodDepth() - if depth != i+1 { - t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth) - } - } - testNum++ - - kad.Off(sevenPeers[1]) - depth = kad.NeighbourhoodDepth() - if depth != 6 { - t.Fatalf("%d expected depth 6, was %d", testNum, depth) - } - testNum++ - - kad.Off(peers[4]) - depth = kad.NeighbourhoodDepth() - if depth != 4 { - t.Fatalf("%d expected depth 4, was %d", testNum, depth) - } - testNum++ - - kad.Off(peers[3]) - depth = kad.NeighbourhoodDepth() - if depth != 3 { - t.Fatalf("%d expected depth 3, was %d", testNum, depth) - } - testNum++ -} - -// TestHighMinBinSize tests that the saturation function also works -// if MinBinSize is > 2, the connection count is < k.MinBinSize -// and there are more peers available than connected -func TestHighMinBinSize(t *testing.T) { - // a function to test for different MinBinSize values - testKad := func(minBinSize int) { - // create a test kademlia - tk := newTestKademlia(t, "11111111") - // set its MinBinSize to desired value - tk.KadParams.MinBinSize = minBinSize - - // add a couple of peers (so we have NN and depth) - tk.On("00000000") // bin 0 - tk.On("11100000") // bin 3 - tk.On("11110000") // bin 4 - - first := "10000000" // add a first peer at bin 1 - tk.Register(first) // register it - // we now have one registered peer at bin 1; - // iterate and connect one peer at each iteration; - // should be unhealthy until at minBinSize - 1 - // we connect the unconnected but registered peer - for i := 1; i < minBinSize; i++ { - peer := fmt.Sprintf("1000%b", 8|i) - tk.On(peer) - if i == minBinSize-1 { - tk.On(first) - tk.checkHealth(true) - return - } - tk.checkHealth(false) - } - } - // test MinBinSizes of 3 to 5 - testMinBinSizes := []int{3, 4, 5} - for _, k := range testMinBinSizes { - testKad(k) - } -} - -// TestHealthStrict tests the simplest definition of health -// Which means whether we are connected to all neighbors we know of -func TestHealthStrict(t *testing.T) { - - // base address is all zeros - // no peers - // unhealthy (and lonely) - tk := newTestKademlia(t, "11111111") - tk.checkHealth(false) - - // know one peer but not connected - // unhealthy - tk.Register("11100000") - tk.checkHealth(false) - - // know one peer and connected - // unhealthy: not saturated - tk.On("11100000") - tk.checkHealth(true) - - // know two peers, only one connected - // unhealthy - tk.Register("11111100") - tk.checkHealth(false) - - // know two peers and connected to both - // healthy - tk.On("11111100") - tk.checkHealth(true) - - // know three peers, connected to the two deepest - // healthy - tk.Register("00000000") - tk.checkHealth(false) - - // know three peers, connected to all three - // healthy - tk.On("00000000") - tk.checkHealth(true) - - // add fourth peer deeper than current depth - // unhealthy - tk.Register("11110000") - tk.checkHealth(false) - - // connected to three deepest peers - // healthy - tk.On("11110000") - tk.checkHealth(true) - - // add additional peer in same bin as deepest peer - // unhealthy - tk.Register("11111101") - tk.checkHealth(false) - - // four deepest of five peers connected - // healthy - tk.On("11111101") - tk.checkHealth(true) - - // add additional peer in bin 0 - // unhealthy: unsaturated bin 0, 2 known but 1 connected - tk.Register("00000001") - tk.checkHealth(false) - - // Connect second in bin 0 - // healthy - tk.On("00000001") - tk.checkHealth(true) - - // add peer in bin 1 - // unhealthy, as it is known but not connected - tk.Register("10000000") - tk.checkHealth(false) - - // connect peer in bin 1 - // depth change, is now 1 - // healthy, 1 peer in bin 1 known and connected - tk.On("10000000") - tk.checkHealth(true) - - // add second peer in bin 1 - // unhealthy, as it is known but not connected - tk.Register("10000001") - tk.checkHealth(false) - - // connect second peer in bin 1 - // healthy, - tk.On("10000001") - tk.checkHealth(true) - - // connect third peer in bin 1 - // healthy, - tk.On("10000011") - tk.checkHealth(true) - - // add peer in bin 2 - // unhealthy, no depth change - tk.Register("11000000") - tk.checkHealth(false) - - // connect peer in bin 2 - // depth change - as we already have peers in bin 3 and 4, - // we have contiguous bins, no bin < po 5 is empty -> depth 5 - // healthy, every bin < depth has the max available peers, - // even if they are < MinBinSize - tk.On("11000000") - tk.checkHealth(true) - - // add peer in bin 2 - // unhealthy, peer bin is below depth 5 but - // has more available peers (2) than connected ones (1) - // --> unsaturated - tk.Register("11000011") - tk.checkHealth(false) -} - -func (tk *testKademlia) checkHealth(expectHealthy bool) { - tk.t.Helper() - kid := common.Bytes2Hex(tk.BaseAddr()) - addrs := [][]byte{tk.BaseAddr()} - tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool { - addrs = append(addrs, addr.Address()) - return true - }) - - pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs) - healthParams := tk.GetHealthInfo(pp[kid]) - - // definition of health, all conditions but be true: - // - we at least know one peer - // - we know all neighbors - // - we are connected to all known neighbors - health := healthParams.Healthy() - if expectHealthy != health { - tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String()) - } -} - -func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) { - tk.t.Helper() - addr, depth, changed := tk.SuggestPeer() - log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed) - if binStr(addr) != expAddr { - tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) - } - if depth != expDepth { - tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth) - } - if changed != expChanged { - tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed) - } -} - -func binStr(a *BzzAddr) string { - if a == nil { - return "<nil>" - } - return pot.ToBin(a.Address())[:8] -} - -func TestSuggestPeerFindPeers(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.On("00100000") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.On("00010000") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.On("10000000", "10000001") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.On("01000000") - tk.Off("10000001") - tk.checkSuggestPeer("10000001", 0, true) - - tk.On("00100001") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - // second time disconnected peer not callable - // with reasonably set Interval - tk.checkSuggestPeer("<nil>", 0, false) - - // on and off again, peer callable again - tk.On("01000000") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - tk.On("01000000", "10000001") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.Register("00010001") - tk.checkSuggestPeer("00010001", 0, false) - - tk.On("00010001") - tk.Off("01000000") - tk.checkSuggestPeer("01000000", 0, false) - - tk.On("01000000") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.Register("01000001") - tk.checkSuggestPeer("01000001", 0, false) - - tk.On("01000001") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.Register("10000010", "01000010", "00100010") - tk.checkSuggestPeer("<nil>", 0, false) - - tk.Register("00010010") - tk.checkSuggestPeer("00010010", 0, false) - - tk.Off("00100001") - tk.checkSuggestPeer("00100010", 2, true) - - tk.Off("01000001") - tk.checkSuggestPeer("01000010", 1, true) - - tk.checkSuggestPeer("01000001", 0, false) - tk.checkSuggestPeer("00100001", 0, false) - tk.checkSuggestPeer("<nil>", 0, false) - - tk.On("01000001", "00100001") - tk.Register("10000100", "01000100", "00100100") - tk.Register("00000100", "00000101", "00000110") - tk.Register("00000010", "00000011", "00000001") - - tk.checkSuggestPeer("00000110", 0, false) - tk.checkSuggestPeer("00000101", 0, false) - tk.checkSuggestPeer("00000100", 0, false) - tk.checkSuggestPeer("00000011", 0, false) - tk.checkSuggestPeer("00000010", 0, false) - tk.checkSuggestPeer("00000001", 0, false) - tk.checkSuggestPeer("<nil>", 0, false) - -} - -// a node should stay in the address book if it's removed from the kademlia -func TestOffEffectingAddressBookNormalNode(t *testing.T) { - tk := newTestKademlia(t, "00000000") - // peer added to kademlia - tk.On("01000000") - // peer should be in the address book - if tk.addrs.Size() != 1 { - t.Fatal("known peer addresses should contain 1 entry") - } - // peer should be among live connections - if tk.conns.Size() != 1 { - t.Fatal("live peers should contain 1 entry") - } - // remove peer from kademlia - tk.Off("01000000") - // peer should be in the address book - if tk.addrs.Size() != 1 { - t.Fatal("known peer addresses should contain 1 entry") - } - // peer should not be among live connections - if tk.conns.Size() != 0 { - t.Fatal("live peers should contain 0 entry") - } -} - -// a light node should not be in the address book -func TestOffEffectingAddressBookLightNode(t *testing.T) { - tk := newTestKademlia(t, "00000000") - // light node peer added to kademlia - tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should be among live connections - if tk.conns.Size() != 1 { - t.Fatal("live peers should contain 1 entry") - } - // remove peer from kademlia - tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) - // peer should not be in the address book - if tk.addrs.Size() != 0 { - t.Fatal("known peer addresses should contain 0 entry") - } - // peer should not be among live connections - if tk.conns.Size() != 0 { - t.Fatal("live peers should contain 0 entry") - } -} - -func TestSuggestPeerRetries(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.RetryInterval = int64(300 * time.Millisecond) // cycle - tk.MaxRetries = 50 - tk.RetryExponent = 2 - sleep := func(n int) { - ts := tk.RetryInterval - for i := 1; i < n; i++ { - ts *= int64(tk.RetryExponent) - } - time.Sleep(time.Duration(ts)) - } - - tk.Register("01000000") - tk.On("00000001", "00000010") - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("<nil>", 0, false) - - sleep(1) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("<nil>", 0, false) - - sleep(1) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("<nil>", 0, false) - - sleep(2) - tk.checkSuggestPeer("01000000", 0, false) - - tk.checkSuggestPeer("<nil>", 0, false) - - sleep(2) - tk.checkSuggestPeer("<nil>", 0, false) -} - -func TestKademliaHiveString(t *testing.T) { - tk := newTestKademlia(t, "00000000") - tk.On("01000000", "00100000") - tk.Register("10000000", "10000001") - tk.MaxProxDisplay = 8 - h := tk.String() - expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 0000000000000000000000000000000000000000000000000000000000000000\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=========================================================================" - if expH[104:] != h[104:] { - t.Fatalf("incorrect hive output. expected %v, got %v", expH, h) - } -} - -func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer { - rw := &p2p.MsgPipeRW{} - p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{}) - pp := protocols.NewPeer(p, rw, &protocols.Spec{}) - bp := &BzzPeer{ - Peer: pp, - BzzAddr: &BzzAddr{ - OAddr: addr.Bytes(), - UAddr: []byte(fmt.Sprintf("%x", addr[:])), - }, - } - return NewPeer(bp, kad) -} - -// TestKademlia_SubscribeToNeighbourhoodDepthChange checks if correct -// signaling over SubscribeToNeighbourhoodDepthChange channels are made -// when neighbourhood depth is changed. -func TestKademlia_SubscribeToNeighbourhoodDepthChange(t *testing.T) { - - testSignal := func(t *testing.T, k *testKademlia, prevDepth int, c <-chan struct{}) (newDepth int) { - t.Helper() - - select { - case _, ok := <-c: - if !ok { - t.Error("closed signal channel") - } - newDepth = k.NeighbourhoodDepth() - if prevDepth == newDepth { - t.Error("depth not changed") - } - return newDepth - case <-time.After(2 * time.Second): - t.Error("timeout") - } - return newDepth - } - - t.Run("single subscription", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - testSignal(t, k, depth, c) - }) - - t.Run("multiple subscriptions", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c1, u1 := k.SubscribeToNeighbourhoodDepthChange() - defer u1() - - c2, u2 := k.SubscribeToNeighbourhoodDepthChange() - defer u2() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - testSignal(t, k, depth, c1) - - testSignal(t, k, depth, c2) - }) - - t.Run("multiple changes", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - depth := k.NeighbourhoodDepth() - - k.On("11111101", "01000000", "10000000", "00000010") - - depth = testSignal(t, k, depth, c) - - k.On("11111101", "01000010", "10000010", "00000110") - - testSignal(t, k, depth, c) - }) - - t.Run("no depth change", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - c, u := k.SubscribeToNeighbourhoodDepthChange() - defer u() - - // does not trigger the depth change - k.On("11111101") - - select { - case _, ok := <-c: - if !ok { - t.Error("closed signal channel") - } - t.Error("signal received") - case <-time.After(1 * time.Second): - // all fine - } - }) - - t.Run("no new peers", func(t *testing.T) { - k := newTestKademlia(t, "00000000") - - changeC, unsubscribe := k.SubscribeToNeighbourhoodDepthChange() - defer unsubscribe() - - select { - case _, ok := <-changeC: - if !ok { - t.Error("closed signal channel") - } - t.Error("signal received") - case <-time.After(1 * time.Second): - // all fine - } - }) -} |