github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/simulations/discovery/discovery_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:48</date>
    10  //</624342674702340096>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package discovery
    29  
    30  import (
    31  	"context"
    32  	"encoding/json"
    33  	"errors"
    34  	"flag"
    35  	"fmt"
    36  	"io/ioutil"
    37  	"math/rand"
    38  	"os"
    39  	"path"
    40  	"strings"
    41  	"sync"
    42  	"testing"
    43  	"time"
    44  
    45  	"github.com/ethereum/go-ethereum/common"
    46  	"github.com/ethereum/go-ethereum/log"
    47  	"github.com/ethereum/go-ethereum/node"
    48  	"github.com/ethereum/go-ethereum/p2p"
    49  	"github.com/ethereum/go-ethereum/p2p/discover"
    50  	"github.com/ethereum/go-ethereum/p2p/simulations"
    51  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    52  	"github.com/ethereum/go-ethereum/swarm/network"
    53  	"github.com/ethereum/go-ethereum/swarm/state"
    54  	colorable "github.com/mattn/go-colorable"
    55  )
    56  
    57  //
    58  //
    59  const serviceName = "discovery"
    60  const testMinProxBinSize = 2
    61  const discoveryPersistenceDatadir = "discovery_persistence_test_store"
    62  
    63  var discoveryPersistencePath = path.Join(os.TempDir(), discoveryPersistenceDatadir)
    64  var discoveryEnabled = true
    65  var persistenceEnabled = false
    66  
    67  var services = adapters.Services{
    68  	serviceName: newService,
    69  }
    70  
    71  func cleanDbStores() error {
    72  	entries, err := ioutil.ReadDir(os.TempDir())
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	for _, f := range entries {
    78  		if strings.HasPrefix(f.Name(), discoveryPersistenceDatadir) {
    79  			os.RemoveAll(path.Join(os.TempDir(), f.Name()))
    80  		}
    81  	}
    82  	return nil
    83  
    84  }
    85  
    86  func getDbStore(nodeID string) (*state.DBStore, error) {
    87  	if _, err := os.Stat(discoveryPersistencePath + "_" + nodeID); os.IsNotExist(err) {
    88  		log.Info(fmt.Sprintf("directory for nodeID %s does not exist. creating...", nodeID))
    89  		ioutil.TempDir("", discoveryPersistencePath+"_"+nodeID)
    90  	}
    91  	log.Info(fmt.Sprintf("opening storage directory for nodeID %s", nodeID))
    92  	store, err := state.NewDBStore(discoveryPersistencePath + "_" + nodeID)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return store, nil
    97  }
    98  
    99  var (
   100  	nodeCount    = flag.Int("nodes", 10, "number of nodes to create (default 10)")
   101  	initCount    = flag.Int("conns", 1, "number of originally connected peers	 (default 1)")
   102  	snapshotFile = flag.String("snapshot", "", "create snapshot")
   103  	loglevel     = flag.Int("loglevel", 3, "verbosity of logs")
   104  	rawlog       = flag.Bool("rawlog", false, "remove terminal formatting from logs")
   105  )
   106  
   107  func init() {
   108  	flag.Parse()
   109  //
   110  //
   111  	adapters.RegisterServices(services)
   112  
   113  	log.PrintOrigins(true)
   114  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog))))
   115  }
   116  
   117  //
   118  //
   119  func BenchmarkDiscovery_8_1(b *testing.B)   { benchmarkDiscovery(b, 8, 1) }
   120  func BenchmarkDiscovery_16_1(b *testing.B)  { benchmarkDiscovery(b, 16, 1) }
   121  func BenchmarkDiscovery_32_1(b *testing.B)  { benchmarkDiscovery(b, 32, 1) }
   122  func BenchmarkDiscovery_64_1(b *testing.B)  { benchmarkDiscovery(b, 64, 1) }
   123  func BenchmarkDiscovery_128_1(b *testing.B) { benchmarkDiscovery(b, 128, 1) }
   124  func BenchmarkDiscovery_256_1(b *testing.B) { benchmarkDiscovery(b, 256, 1) }
   125  
   126  func BenchmarkDiscovery_8_2(b *testing.B)   { benchmarkDiscovery(b, 8, 2) }
   127  func BenchmarkDiscovery_16_2(b *testing.B)  { benchmarkDiscovery(b, 16, 2) }
   128  func BenchmarkDiscovery_32_2(b *testing.B)  { benchmarkDiscovery(b, 32, 2) }
   129  func BenchmarkDiscovery_64_2(b *testing.B)  { benchmarkDiscovery(b, 64, 2) }
   130  func BenchmarkDiscovery_128_2(b *testing.B) { benchmarkDiscovery(b, 128, 2) }
   131  func BenchmarkDiscovery_256_2(b *testing.B) { benchmarkDiscovery(b, 256, 2) }
   132  
   133  func BenchmarkDiscovery_8_4(b *testing.B)   { benchmarkDiscovery(b, 8, 4) }
   134  func BenchmarkDiscovery_16_4(b *testing.B)  { benchmarkDiscovery(b, 16, 4) }
   135  func BenchmarkDiscovery_32_4(b *testing.B)  { benchmarkDiscovery(b, 32, 4) }
   136  func BenchmarkDiscovery_64_4(b *testing.B)  { benchmarkDiscovery(b, 64, 4) }
   137  func BenchmarkDiscovery_128_4(b *testing.B) { benchmarkDiscovery(b, 128, 4) }
   138  func BenchmarkDiscovery_256_4(b *testing.B) { benchmarkDiscovery(b, 256, 4) }
   139  
   140  func TestDiscoverySimulationDockerAdapter(t *testing.T) {
   141  	testDiscoverySimulationDockerAdapter(t, *nodeCount, *initCount)
   142  }
   143  
   144  func testDiscoverySimulationDockerAdapter(t *testing.T, nodes, conns int) {
   145  	adapter, err := adapters.NewDockerAdapter()
   146  	if err != nil {
   147  		if err == adapters.ErrLinuxOnly {
   148  			t.Skip(err)
   149  		} else {
   150  			t.Fatal(err)
   151  		}
   152  	}
   153  	testDiscoverySimulation(t, nodes, conns, adapter)
   154  }
   155  
   156  func TestDiscoverySimulationExecAdapter(t *testing.T) {
   157  	testDiscoverySimulationExecAdapter(t, *nodeCount, *initCount)
   158  }
   159  
   160  func testDiscoverySimulationExecAdapter(t *testing.T, nodes, conns int) {
   161  	baseDir, err := ioutil.TempDir("", "swarm-test")
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	defer os.RemoveAll(baseDir)
   166  	testDiscoverySimulation(t, nodes, conns, adapters.NewExecAdapter(baseDir))
   167  }
   168  
   169  func TestDiscoverySimulationSimAdapter(t *testing.T) {
   170  	testDiscoverySimulationSimAdapter(t, *nodeCount, *initCount)
   171  }
   172  
   173  func TestDiscoveryPersistenceSimulationSimAdapter(t *testing.T) {
   174  	testDiscoveryPersistenceSimulationSimAdapter(t, *nodeCount, *initCount)
   175  }
   176  
   177  func testDiscoveryPersistenceSimulationSimAdapter(t *testing.T, nodes, conns int) {
   178  	testDiscoveryPersistenceSimulation(t, nodes, conns, adapters.NewSimAdapter(services))
   179  }
   180  
   181  func testDiscoverySimulationSimAdapter(t *testing.T, nodes, conns int) {
   182  	testDiscoverySimulation(t, nodes, conns, adapters.NewSimAdapter(services))
   183  }
   184  
   185  func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) {
   186  	startedAt := time.Now()
   187  	result, err := discoverySimulation(nodes, conns, adapter)
   188  	if err != nil {
   189  		t.Fatalf("Setting up simulation failed: %v", err)
   190  	}
   191  	if result.Error != nil {
   192  		t.Fatalf("Simulation failed: %s", result.Error)
   193  	}
   194  	t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt))
   195  	var min, max time.Duration
   196  	var sum int
   197  	for _, pass := range result.Passes {
   198  		duration := pass.Sub(result.StartedAt)
   199  		if sum == 0 || duration < min {
   200  			min = duration
   201  		}
   202  		if duration > max {
   203  			max = duration
   204  		}
   205  		sum += int(duration.Nanoseconds())
   206  	}
   207  	t.Logf("Min: %s, Max: %s, Average: %s", min, max, time.Duration(sum/len(result.Passes))*time.Nanosecond)
   208  	finishedAt := time.Now()
   209  	t.Logf("Setup: %s, shutdown: %s", result.StartedAt.Sub(startedAt), finishedAt.Sub(result.FinishedAt))
   210  }
   211  
   212  func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte {
   213  	persistenceEnabled = true
   214  	discoveryEnabled = true
   215  
   216  	result, err := discoveryPersistenceSimulation(nodes, conns, adapter)
   217  
   218  	if err != nil {
   219  		t.Fatalf("Setting up simulation failed: %v", err)
   220  	}
   221  	if result.Error != nil {
   222  		t.Fatalf("Simulation failed: %s", result.Error)
   223  	}
   224  	t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt))
   225  //
   226  //
   227  	discoveryEnabled = true
   228  	persistenceEnabled = false
   229  	return nil
   230  }
   231  
   232  func benchmarkDiscovery(b *testing.B, nodes, conns int) {
   233  	for i := 0; i < b.N; i++ {
   234  		result, err := discoverySimulation(nodes, conns, adapters.NewSimAdapter(services))
   235  		if err != nil {
   236  			b.Fatalf("setting up simulation failed: %v", err)
   237  		}
   238  		if result.Error != nil {
   239  			b.Logf("simulation failed: %s", result.Error)
   240  		}
   241  	}
   242  }
   243  
   244  func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) {
   245  //
   246  	net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
   247  		ID:             "0",
   248  		DefaultService: serviceName,
   249  	})
   250  	defer net.Shutdown()
   251  	trigger := make(chan discover.NodeID)
   252  	ids := make([]discover.NodeID, nodes)
   253  	for i := 0; i < nodes; i++ {
   254  		conf := adapters.RandomNodeConfig()
   255  		node, err := net.NewNodeWithConfig(conf)
   256  		if err != nil {
   257  			return nil, fmt.Errorf("error starting node: %s", err)
   258  		}
   259  		if err := net.Start(node.ID()); err != nil {
   260  			return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   261  		}
   262  		if err := triggerChecks(trigger, net, node.ID()); err != nil {
   263  			return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   264  		}
   265  		ids[i] = node.ID()
   266  	}
   267  
   268  //
   269  //
   270  	var addrs [][]byte
   271  	action := func(ctx context.Context) error {
   272  		return nil
   273  	}
   274  	wg := sync.WaitGroup{}
   275  	for i := range ids {
   276  //
   277  		addrs = append(addrs, network.ToOverlayAddr(ids[i].Bytes()))
   278  		for j := 0; j < conns; j++ {
   279  			var k int
   280  			if j == 0 {
   281  				k = (i + 1) % len(ids)
   282  			} else {
   283  				k = rand.Intn(len(ids))
   284  			}
   285  			wg.Add(1)
   286  			go func(i, k int) {
   287  				defer wg.Done()
   288  				net.Connect(ids[i], ids[k])
   289  			}(i, k)
   290  		}
   291  	}
   292  	wg.Wait()
   293  	log.Debug(fmt.Sprintf("nodes: %v", len(addrs)))
   294  //
   295  	ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs)
   296  	check := func(ctx context.Context, id discover.NodeID) (bool, error) {
   297  		select {
   298  		case <-ctx.Done():
   299  			return false, ctx.Err()
   300  		default:
   301  		}
   302  
   303  		node := net.GetNode(id)
   304  		if node == nil {
   305  			return false, fmt.Errorf("unknown node: %s", id)
   306  		}
   307  		client, err := node.Client()
   308  		if err != nil {
   309  			return false, fmt.Errorf("error getting node client: %s", err)
   310  		}
   311  		healthy := &network.Health{}
   312  		addr := common.Bytes2Hex(network.ToOverlayAddr(id.Bytes()))
   313  		if err := client.Call(&healthy, "hive_healthy", ppmap[addr]); err != nil {
   314  			return false, fmt.Errorf("error getting node health: %s", err)
   315  		}
   316  		log.Debug(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v\n%v", id, healthy.GotNN, healthy.KnowNN, healthy.Full, healthy.Hive))
   317  		return healthy.KnowNN && healthy.GotNN && healthy.Full, nil
   318  	}
   319  
   320  //
   321  //
   322  	timeout := 300 * time.Second
   323  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   324  	defer cancel()
   325  	result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{
   326  		Action:  action,
   327  		Trigger: trigger,
   328  		Expect: &simulations.Expectation{
   329  			Nodes: ids,
   330  			Check: check,
   331  		},
   332  	})
   333  	if result.Error != nil {
   334  		return result, nil
   335  	}
   336  
   337  	if *snapshotFile != "" {
   338  		snap, err := net.Snapshot()
   339  		if err != nil {
   340  			return nil, errors.New("no shapshot dude")
   341  		}
   342  		jsonsnapshot, err := json.Marshal(snap)
   343  		if err != nil {
   344  			return nil, fmt.Errorf("corrupt json snapshot: %v", err)
   345  		}
   346  		log.Info("writing snapshot", "file", *snapshotFile)
   347  		err = ioutil.WriteFile(*snapshotFile, jsonsnapshot, 0755)
   348  		if err != nil {
   349  			return nil, err
   350  		}
   351  	}
   352  	return result, nil
   353  }
   354  
   355  func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) {
   356  	cleanDbStores()
   357  	defer cleanDbStores()
   358  
   359  //
   360  	net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
   361  		ID:             "0",
   362  		DefaultService: serviceName,
   363  	})
   364  	defer net.Shutdown()
   365  	trigger := make(chan discover.NodeID)
   366  	ids := make([]discover.NodeID, nodes)
   367  	var addrs [][]byte
   368  
   369  	for i := 0; i < nodes; i++ {
   370  		conf := adapters.RandomNodeConfig()
   371  		node, err := net.NewNodeWithConfig(conf)
   372  		if err != nil {
   373  			panic(err)
   374  		}
   375  		if err != nil {
   376  			return nil, fmt.Errorf("error starting node: %s", err)
   377  		}
   378  		if err := net.Start(node.ID()); err != nil {
   379  			return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   380  		}
   381  		if err := triggerChecks(trigger, net, node.ID()); err != nil {
   382  			return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   383  		}
   384  		ids[i] = node.ID()
   385  		a := network.ToOverlayAddr(ids[i].Bytes())
   386  
   387  		addrs = append(addrs, a)
   388  	}
   389  
   390  //
   391  //
   392  	ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs)
   393  
   394  	var restartTime time.Time
   395  
   396  	action := func(ctx context.Context) error {
   397  		ticker := time.NewTicker(500 * time.Millisecond)
   398  
   399  		for range ticker.C {
   400  			isHealthy := true
   401  			for _, id := range ids {
   402  //
   403  				node := net.GetNode(id)
   404  				if node == nil {
   405  					return fmt.Errorf("unknown node: %s", id)
   406  				}
   407  				client, err := node.Client()
   408  				if err != nil {
   409  					return fmt.Errorf("error getting node client: %s", err)
   410  				}
   411  				healthy := &network.Health{}
   412  				addr := common.Bytes2Hex(network.ToOverlayAddr(id.Bytes()))
   413  				if err := client.Call(&healthy, "hive_healthy", ppmap[addr]); err != nil {
   414  					return fmt.Errorf("error getting node health: %s", err)
   415  				}
   416  
   417  				log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", id.String(), healthy.GotNN && healthy.KnowNN && healthy.Full))
   418  				if !healthy.GotNN || !healthy.Full {
   419  					isHealthy = false
   420  					break
   421  				}
   422  			}
   423  			if isHealthy {
   424  				break
   425  			}
   426  		}
   427  		ticker.Stop()
   428  
   429  		log.Info("reached healthy kademlia. starting to shutdown nodes.")
   430  		shutdownStarted := time.Now()
   431  //
   432  		for _, id := range ids {
   433  			node := net.GetNode(id)
   434  
   435  			if err := net.Stop(node.ID()); err != nil {
   436  				return fmt.Errorf("error stopping node %s: %s", node.ID().TerminalString(), err)
   437  			}
   438  		}
   439  		log.Info(fmt.Sprintf("shutting down nodes took: %s", time.Since(shutdownStarted)))
   440  		persistenceEnabled = true
   441  		discoveryEnabled = false
   442  		restartTime = time.Now()
   443  		for _, id := range ids {
   444  			node := net.GetNode(id)
   445  			if err := net.Start(node.ID()); err != nil {
   446  				return fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   447  			}
   448  			if err := triggerChecks(trigger, net, node.ID()); err != nil {
   449  				return fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   450  			}
   451  		}
   452  
   453  		log.Info(fmt.Sprintf("restarting nodes took: %s", time.Since(restartTime)))
   454  
   455  		return nil
   456  	}
   457  //
   458  	wg := sync.WaitGroup{}
   459  //
   460  	for i := range ids {
   461  		for j := 1; j <= conns; j++ {
   462  			k := (i + j) % len(ids)
   463  			if k == i {
   464  				k = (k + 1) % len(ids)
   465  			}
   466  			wg.Add(1)
   467  			go func(i, k int) {
   468  				defer wg.Done()
   469  				net.Connect(ids[i], ids[k])
   470  			}(i, k)
   471  		}
   472  	}
   473  	wg.Wait()
   474  	log.Debug(fmt.Sprintf("nodes: %v", len(addrs)))
   475  //
   476  	check := func(ctx context.Context, id discover.NodeID) (bool, error) {
   477  		select {
   478  		case <-ctx.Done():
   479  			return false, ctx.Err()
   480  		default:
   481  		}
   482  
   483  		node := net.GetNode(id)
   484  		if node == nil {
   485  			return false, fmt.Errorf("unknown node: %s", id)
   486  		}
   487  		client, err := node.Client()
   488  		if err != nil {
   489  			return false, fmt.Errorf("error getting node client: %s", err)
   490  		}
   491  		healthy := &network.Health{}
   492  		addr := common.Bytes2Hex(network.ToOverlayAddr(id.Bytes()))
   493  		if err := client.Call(&healthy, "hive_healthy", ppmap[addr]); err != nil {
   494  			return false, fmt.Errorf("error getting node health: %s", err)
   495  		}
   496  		log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v", id, healthy.GotNN, healthy.KnowNN, healthy.Full))
   497  
   498  		return healthy.KnowNN && healthy.GotNN && healthy.Full, nil
   499  	}
   500  
   501  //
   502  //
   503  	timeout := 300 * time.Second
   504  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   505  	defer cancel()
   506  	result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{
   507  		Action:  action,
   508  		Trigger: trigger,
   509  		Expect: &simulations.Expectation{
   510  			Nodes: ids,
   511  			Check: check,
   512  		},
   513  	})
   514  	if result.Error != nil {
   515  		return result, nil
   516  	}
   517  
   518  	return result, nil
   519  }
   520  
   521  //
   522  //
   523  //
   524  func triggerChecks(trigger chan discover.NodeID, net *simulations.Network, id discover.NodeID) error {
   525  	node := net.GetNode(id)
   526  	if node == nil {
   527  		return fmt.Errorf("unknown node: %s", id)
   528  	}
   529  	client, err := node.Client()
   530  	if err != nil {
   531  		return err
   532  	}
   533  	events := make(chan *p2p.PeerEvent)
   534  	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents")
   535  	if err != nil {
   536  		return fmt.Errorf("error getting peer events for node %v: %s", id, err)
   537  	}
   538  	go func() {
   539  		defer sub.Unsubscribe()
   540  
   541  		tick := time.NewTicker(time.Second)
   542  		defer tick.Stop()
   543  
   544  		for {
   545  			select {
   546  			case <-events:
   547  				trigger <- id
   548  			case <-tick.C:
   549  				trigger <- id
   550  			case err := <-sub.Err():
   551  				if err != nil {
   552  					log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err)
   553  				}
   554  				return
   555  			}
   556  		}
   557  	}()
   558  	return nil
   559  }
   560  
   561  func newService(ctx *adapters.ServiceContext) (node.Service, error) {
   562  	host := adapters.ExternalIP()
   563  
   564  	addr := network.NewAddrFromNodeIDAndPort(ctx.Config.ID, host, ctx.Config.Port)
   565  
   566  	kp := network.NewKadParams()
   567  	kp.MinProxBinSize = testMinProxBinSize
   568  
   569  	if ctx.Config.Reachable != nil {
   570  		kp.Reachable = func(o network.OverlayAddr) bool {
   571  			return ctx.Config.Reachable(o.(*network.BzzAddr).ID())
   572  		}
   573  	}
   574  	kad := network.NewKademlia(addr.Over(), kp)
   575  	hp := network.NewHiveParams()
   576  	hp.KeepAliveInterval = time.Duration(200) * time.Millisecond
   577  	hp.Discovery = discoveryEnabled
   578  
   579  	log.Info(fmt.Sprintf("discovery for nodeID %s is %t", ctx.Config.ID.String(), hp.Discovery))
   580  
   581  	config := &network.BzzConfig{
   582  		OverlayAddr:  addr.Over(),
   583  		UnderlayAddr: addr.Under(),
   584  		HiveParams:   hp,
   585  	}
   586  
   587  	if persistenceEnabled {
   588  		log.Info(fmt.Sprintf("persistence enabled for nodeID %s", ctx.Config.ID.String()))
   589  		store, err := getDbStore(ctx.Config.ID.String())
   590  		if err != nil {
   591  			return nil, err
   592  		}
   593  		return network.NewBzz(config, kad, store, nil, nil), nil
   594  	}
   595  
   596  	return network.NewBzz(config, kad, nil, nil, nil), nil
   597  }
   598