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 }