github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/network/discovery_test.go (about)

     1  // Copyright 2016 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  	"crypto/ecdsa"
    21  	crand "crypto/rand"
    22  	"encoding/binary"
    23  	"fmt"
    24  	"math/rand"
    25  	"net"
    26  	"sort"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/p2p"
    32  	"github.com/ethereum/go-ethereum/p2p/enode"
    33  	"github.com/ethereum/go-ethereum/p2p/protocols"
    34  	p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
    35  	"github.com/ethereum/go-ethereum/swarm/pot"
    36  )
    37  
    38  /***
    39   *
    40   * - after connect, that outgoing subpeersmsg is sent
    41   *
    42   */
    43  func TestSubPeersMsg(t *testing.T) {
    44  	params := NewHiveParams()
    45  	s, pp, err := newHiveTester(params, 1, nil)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	node := s.Nodes[0]
    51  	raddr := NewAddr(node)
    52  	pp.Register(raddr)
    53  
    54  	// start the hive and wait for the connection
    55  	pp.Start(s.Server)
    56  	defer pp.Stop()
    57  
    58  	// send subPeersMsg to the peer
    59  	err = s.TestExchanges(p2ptest.Exchange{
    60  		Label: "outgoing subPeersMsg",
    61  		Expects: []p2ptest.Expect{
    62  			{
    63  				Code: 1,
    64  				Msg:  &subPeersMsg{Depth: 0},
    65  				Peer: node.ID(),
    66  			},
    67  		},
    68  	})
    69  
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  }
    74  
    75  const (
    76  	maxPO         = 8 // PO of pivot and control; chosen to test enough cases but not run too long
    77  	maxPeerPO     = 6 // pivot has no peers closer than this to the control peer
    78  	maxPeersPerPO = 3
    79  )
    80  
    81  // TestInitialPeersMsg tests if peersMsg response to incoming subPeersMsg is correct
    82  func TestInitialPeersMsg(t *testing.T) {
    83  	for po := 0; po < maxPO; po++ {
    84  		for depth := 0; depth < maxPO; depth++ {
    85  			t.Run(fmt.Sprintf("PO=%d,advertised depth=%d", po, depth), func(t *testing.T) {
    86  				testInitialPeersMsg(t, po, depth)
    87  			})
    88  		}
    89  	}
    90  }
    91  
    92  // testInitialPeersMsg tests that the correct set of peer info is sent
    93  // to another peer after receiving their subPeersMsg request
    94  func testInitialPeersMsg(t *testing.T, peerPO, peerDepth int) {
    95  	// generate random pivot address
    96  	prvkey, err := crypto.GenerateKey()
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	defer func(orig func([]*BzzAddr) []*BzzAddr) {
   102  		sortPeers = orig
   103  	}(sortPeers)
   104  	sortPeers = testSortPeers
   105  	pivotAddr := pot.NewAddressFromBytes(PrivateKeyToBzzKey(prvkey))
   106  	// generate control peers address at peerPO wrt pivot
   107  	peerAddr := pot.RandomAddressAt(pivotAddr, peerPO)
   108  	// construct kademlia and hive
   109  	to := NewKademlia(pivotAddr[:], NewKadParams())
   110  	hive := NewHive(NewHiveParams(), to, nil)
   111  
   112  	// expected addrs in peersMsg response
   113  	var expBzzAddrs []*BzzAddr
   114  	connect := func(a pot.Address, po int) (addrs []*BzzAddr) {
   115  		n := rand.Intn(maxPeersPerPO)
   116  		for i := 0; i < n; i++ {
   117  			peer, err := newDiscPeer(pot.RandomAddressAt(a, po))
   118  			if err != nil {
   119  				t.Fatal(err)
   120  			}
   121  			hive.On(peer)
   122  			addrs = append(addrs, peer.BzzAddr)
   123  		}
   124  		return addrs
   125  	}
   126  	register := func(a pot.Address, po int) {
   127  		addr := pot.RandomAddressAt(a, po)
   128  		hive.Register(&BzzAddr{OAddr: addr[:]})
   129  	}
   130  
   131  	// generate connected and just registered peers
   132  	for po := maxPeerPO; po >= 0; po-- {
   133  		// create a fake connected peer at po from peerAddr
   134  		ons := connect(peerAddr, po)
   135  		// create a fake registered address at po from peerAddr
   136  		register(peerAddr, po)
   137  		// we collect expected peer addresses only up till peerPO
   138  		if po < peerDepth {
   139  			continue
   140  		}
   141  		expBzzAddrs = append(expBzzAddrs, ons...)
   142  	}
   143  
   144  	// add extra connections closer to pivot than control
   145  	for po := peerPO + 1; po < maxPO; po++ {
   146  		ons := connect(pivotAddr, po)
   147  		if peerDepth <= peerPO {
   148  			expBzzAddrs = append(expBzzAddrs, ons...)
   149  		}
   150  	}
   151  
   152  	// create a special bzzBaseTester in which we can associate `enode.ID` to the `bzzAddr` we created above
   153  	s, _, err := newBzzBaseTesterWithAddrs(prvkey, [][]byte{peerAddr[:]}, DiscoverySpec, hive.Run)
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  
   158  	// peerID to use in the protocol tester testExchange expect/trigger
   159  	peerID := s.Nodes[0].ID()
   160  	// block until control peer is found among hive peers
   161  	found := false
   162  	for attempts := 0; attempts < 20; attempts++ {
   163  		if _, found = hive.peers[peerID]; found {
   164  			break
   165  		}
   166  		time.Sleep(1 * time.Millisecond)
   167  	}
   168  
   169  	if !found {
   170  		t.Fatal("timeout waiting for peer connection to start")
   171  	}
   172  
   173  	// pivotDepth is the advertised depth of the pivot node we expect in the outgoing subPeersMsg
   174  	pivotDepth := hive.saturation()
   175  	// the test exchange is as follows:
   176  	// 1. pivot sends to the control peer a `subPeersMsg` advertising its depth (ignored)
   177  	// 2. peer sends to pivot a `subPeersMsg` advertising its own depth (arbitrarily chosen)
   178  	// 3. pivot responds with `peersMsg` with the set of expected peers
   179  	err = s.TestExchanges(
   180  		p2ptest.Exchange{
   181  			Label: "outgoing subPeersMsg",
   182  			Expects: []p2ptest.Expect{
   183  				{
   184  					Code: 1,
   185  					Msg:  &subPeersMsg{Depth: uint8(pivotDepth)},
   186  					Peer: peerID,
   187  				},
   188  			},
   189  		},
   190  		p2ptest.Exchange{
   191  			Label: "trigger subPeersMsg and expect peersMsg",
   192  			Triggers: []p2ptest.Trigger{
   193  				{
   194  					Code: 1,
   195  					Msg:  &subPeersMsg{Depth: uint8(peerDepth)},
   196  					Peer: peerID,
   197  				},
   198  			},
   199  			Expects: []p2ptest.Expect{
   200  				{
   201  					Code:    0,
   202  					Msg:     &peersMsg{Peers: testSortPeers(expBzzAddrs)},
   203  					Peer:    peerID,
   204  					Timeout: 100 * time.Millisecond,
   205  				},
   206  			},
   207  		})
   208  
   209  	// for values MaxPeerPO < peerPO < MaxPO the pivot has no peers to offer to the control peer
   210  	// in this case, no peersMsg will be sent out, and we would run into a time out
   211  	if len(expBzzAddrs) == 0 {
   212  		if err != nil {
   213  			if err.Error() != "exchange #1 \"trigger subPeersMsg and expect peersMsg\": timed out" {
   214  				t.Fatalf("expected timeout, got %v", err)
   215  			}
   216  			return
   217  		}
   218  		t.Fatalf("expected timeout, got no error")
   219  	}
   220  
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  }
   225  
   226  func testSortPeers(peers []*BzzAddr) []*BzzAddr {
   227  	comp := func(i, j int) bool {
   228  		vi := binary.BigEndian.Uint64(peers[i].OAddr)
   229  		vj := binary.BigEndian.Uint64(peers[j].OAddr)
   230  		return vi < vj
   231  	}
   232  	sort.Slice(peers, comp)
   233  	return peers
   234  }
   235  
   236  // as we are not creating a real node via the protocol,
   237  // we need to create the discovery peer objects for the additional kademlia
   238  // nodes manually
   239  func newDiscPeer(addr pot.Address) (*Peer, error) {
   240  	pKey, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	pubKey := pKey.PublicKey
   245  	nod := enode.NewV4(&pubKey, net.IPv4(127, 0, 0, 1), 0, 0)
   246  	bzzAddr := &BzzAddr{OAddr: addr[:], UAddr: []byte(nod.String())}
   247  	id := nod.ID()
   248  	p2pPeer := p2p.NewPeer(id, id.String(), nil)
   249  	return NewPeer(&BzzPeer{
   250  		Peer:    protocols.NewPeer(p2pPeer, &dummyMsgRW{}, DiscoverySpec),
   251  		BzzAddr: bzzAddr,
   252  	}, nil), nil
   253  }
   254  
   255  type dummyMsgRW struct{}
   256  
   257  func (d *dummyMsgRW) ReadMsg() (p2p.Msg, error) {
   258  	return p2p.Msg{}, nil
   259  }
   260  func (d *dummyMsgRW) WriteMsg(msg p2p.Msg) error {
   261  	return nil
   262  }