github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/swarm/network/networkid_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 "bytes" 21 "context" 22 "flag" 23 "fmt" 24 "math/rand" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/ShyftNetwork/go-empyrean/log" 30 "github.com/ShyftNetwork/go-empyrean/node" 31 "github.com/ShyftNetwork/go-empyrean/p2p" 32 "github.com/ShyftNetwork/go-empyrean/p2p/enode" 33 "github.com/ShyftNetwork/go-empyrean/p2p/simulations" 34 "github.com/ShyftNetwork/go-empyrean/p2p/simulations/adapters" 35 "github.com/ShyftNetwork/go-empyrean/rpc" 36 ) 37 38 var ( 39 currentNetworkID int 40 cnt int 41 nodeMap map[int][]enode.ID 42 kademlias map[enode.ID]*Kademlia 43 ) 44 45 const ( 46 NumberOfNets = 4 47 MaxTimeout = 6 48 ) 49 50 func init() { 51 flag.Parse() 52 rand.Seed(time.Now().Unix()) 53 } 54 55 /* 56 Run the network ID test. 57 The test creates one simulations.Network instance, 58 a number of nodes, then connects nodes with each other in this network. 59 60 Each node gets a network ID assigned according to the number of networks. 61 Having more network IDs is just arbitrary in order to exclude 62 false positives. 63 64 Nodes should only connect with other nodes with the same network ID. 65 After the setup phase, the test checks on each node if it has the 66 expected node connections (excluding those not sharing the network ID). 67 */ 68 func TestNetworkID(t *testing.T) { 69 log.Debug("Start test") 70 //arbitrarily set the number of nodes. It could be any number 71 numNodes := 24 72 //the nodeMap maps all nodes (slice value) with the same network ID (key) 73 nodeMap = make(map[int][]enode.ID) 74 //set up the network and connect nodes 75 net, err := setupNetwork(numNodes) 76 if err != nil { 77 t.Fatalf("Error setting up network: %v", err) 78 } 79 defer func() { 80 //shutdown the snapshot network 81 log.Trace("Shutting down network") 82 net.Shutdown() 83 }() 84 //let's sleep to ensure all nodes are connected 85 time.Sleep(1 * time.Second) 86 //for each group sharing the same network ID... 87 for _, netIDGroup := range nodeMap { 88 log.Trace("netIDGroup size", "size", len(netIDGroup)) 89 //...check that their size of the kademlia is of the expected size 90 //the assumption is that it should be the size of the group minus 1 (the node itself) 91 for _, node := range netIDGroup { 92 if kademlias[node].addrs.Size() != len(netIDGroup)-1 { 93 t.Fatalf("Kademlia size has not expected peer size. Kademlia size: %d, expected size: %d", kademlias[node].addrs.Size(), len(netIDGroup)-1) 94 } 95 kademlias[node].EachAddr(nil, 0, func(addr *BzzAddr, _ int) bool { 96 found := false 97 for _, nd := range netIDGroup { 98 if bytes.Equal(kademlias[nd].BaseAddr(), addr.Address()) { 99 found = true 100 } 101 } 102 if !found { 103 t.Fatalf("Expected node not found for node %s", node.String()) 104 } 105 return true 106 }) 107 } 108 } 109 log.Info("Test terminated successfully") 110 } 111 112 // setup simulated network with bzz/discovery and pss services. 113 // connects nodes in a circle 114 // if allowRaw is set, omission of builtin pss encryption is enabled (see PssParams) 115 func setupNetwork(numnodes int) (net *simulations.Network, err error) { 116 log.Debug("Setting up network") 117 quitC := make(chan struct{}) 118 errc := make(chan error) 119 nodes := make([]*simulations.Node, numnodes) 120 if numnodes < 16 { 121 return nil, fmt.Errorf("Minimum sixteen nodes in network") 122 } 123 adapter := adapters.NewSimAdapter(newServices()) 124 //create the network 125 net = simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 126 ID: "NetworkIdTestNet", 127 DefaultService: "bzz", 128 }) 129 log.Debug("Creating networks and nodes") 130 131 var connCount int 132 133 //create nodes and connect them to each other 134 for i := 0; i < numnodes; i++ { 135 log.Trace("iteration: ", "i", i) 136 nodeconf := adapters.RandomNodeConfig() 137 nodes[i], err = net.NewNodeWithConfig(nodeconf) 138 if err != nil { 139 return nil, fmt.Errorf("error creating node %d: %v", i, err) 140 } 141 err = net.Start(nodes[i].ID()) 142 if err != nil { 143 return nil, fmt.Errorf("error starting node %d: %v", i, err) 144 } 145 client, err := nodes[i].Client() 146 if err != nil { 147 return nil, fmt.Errorf("create node %d rpc client fail: %v", i, err) 148 } 149 //now setup and start event watching in order to know when we can upload 150 ctx, watchCancel := context.WithTimeout(context.Background(), MaxTimeout*time.Second) 151 defer watchCancel() 152 watchSubscriptionEvents(ctx, nodes[i].ID(), client, errc, quitC) 153 //on every iteration we connect to all previous ones 154 for k := i - 1; k >= 0; k-- { 155 connCount++ 156 log.Debug(fmt.Sprintf("Connecting node %d with node %d; connection count is %d", i, k, connCount)) 157 err = net.Connect(nodes[i].ID(), nodes[k].ID()) 158 if err != nil { 159 if !strings.Contains(err.Error(), "already connected") { 160 return nil, fmt.Errorf("error connecting nodes: %v", err) 161 } 162 } 163 } 164 } 165 //now wait until the number of expected subscriptions has been finished 166 //`watchSubscriptionEvents` will write with a `nil` value to errc 167 for err := range errc { 168 if err != nil { 169 return nil, err 170 } 171 //`nil` received, decrement count 172 connCount-- 173 log.Trace("count down", "cnt", connCount) 174 //all subscriptions received 175 if connCount == 0 { 176 close(quitC) 177 break 178 } 179 } 180 log.Debug("Network setup phase terminated") 181 return net, nil 182 } 183 184 func newServices() adapters.Services { 185 kademlias = make(map[enode.ID]*Kademlia) 186 kademlia := func(id enode.ID) *Kademlia { 187 if k, ok := kademlias[id]; ok { 188 return k 189 } 190 params := NewKadParams() 191 params.NeighbourhoodSize = 2 192 params.MaxBinSize = 3 193 params.MinBinSize = 1 194 params.MaxRetries = 1000 195 params.RetryExponent = 2 196 params.RetryInterval = 1000000 197 kademlias[id] = NewKademlia(id[:], params) 198 return kademlias[id] 199 } 200 return adapters.Services{ 201 "bzz": func(ctx *adapters.ServiceContext) (node.Service, error) { 202 addr := NewAddr(ctx.Config.Node()) 203 hp := NewHiveParams() 204 hp.Discovery = false 205 cnt++ 206 //assign the network ID 207 currentNetworkID = cnt % NumberOfNets 208 if ok := nodeMap[currentNetworkID]; ok == nil { 209 nodeMap[currentNetworkID] = make([]enode.ID, 0) 210 } 211 //add this node to the group sharing the same network ID 212 nodeMap[currentNetworkID] = append(nodeMap[currentNetworkID], ctx.Config.ID) 213 log.Debug("current network ID:", "id", currentNetworkID) 214 config := &BzzConfig{ 215 OverlayAddr: addr.Over(), 216 UnderlayAddr: addr.Under(), 217 HiveParams: hp, 218 NetworkID: uint64(currentNetworkID), 219 } 220 return NewBzz(config, kademlia(ctx.Config.ID), nil, nil, nil), nil 221 }, 222 } 223 } 224 225 func watchSubscriptionEvents(ctx context.Context, id enode.ID, client *rpc.Client, errc chan error, quitC chan struct{}) { 226 events := make(chan *p2p.PeerEvent) 227 sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") 228 if err != nil { 229 log.Error(err.Error()) 230 errc <- fmt.Errorf("error getting peer events for node %v: %s", id, err) 231 return 232 } 233 go func() { 234 defer func() { 235 sub.Unsubscribe() 236 log.Trace("watch subscription events: unsubscribe", "id", id) 237 }() 238 239 for { 240 select { 241 case <-quitC: 242 return 243 case <-ctx.Done(): 244 select { 245 case errc <- ctx.Err(): 246 case <-quitC: 247 } 248 return 249 case e := <-events: 250 if e.Type == p2p.PeerEventTypeAdd { 251 errc <- nil 252 } 253 case err := <-sub.Err(): 254 if err != nil { 255 select { 256 case errc <- fmt.Errorf("error getting peer events for node %v: %v", id, err): 257 case <-quitC: 258 } 259 return 260 } 261 } 262 } 263 }() 264 }