github.com/ebceco/ebc@v1.8.19-0.20190309150932-8cb0b9e06484/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/ebceco/ebc/log"
    30  	"github.com/ebceco/ebc/node"
    31  	"github.com/ebceco/ebc/p2p"
    32  	"github.com/ebceco/ebc/p2p/enode"
    33  	"github.com/ebceco/ebc/p2p/simulations"
    34  	"github.com/ebceco/ebc/p2p/simulations/adapters"
    35  	"github.com/ebceco/ebc/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  }