github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:43</date>
    10  //</624450114949222400>
    11  
    12  
    13  package discovery
    14  
    15  import (
    16  	"context"
    17  	"flag"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"path"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/log"
    28  	"github.com/ethereum/go-ethereum/node"
    29  	"github.com/ethereum/go-ethereum/p2p"
    30  	"github.com/ethereum/go-ethereum/p2p/enode"
    31  	"github.com/ethereum/go-ethereum/p2p/simulations"
    32  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    33  	"github.com/ethereum/go-ethereum/swarm/network"
    34  	"github.com/ethereum/go-ethereum/swarm/state"
    35  	colorable "github.com/mattn/go-colorable"
    36  )
    37  
    38  //servicename与exec适配器一起使用,因此exec'd二进制文件知道
    39  //要执行的服务
    40  const serviceName = "discovery"
    41  const testNeighbourhoodSize = 2
    42  const discoveryPersistenceDatadir = "discovery_persistence_test_store"
    43  
    44  var discoveryPersistencePath = path.Join(os.TempDir(), discoveryPersistenceDatadir)
    45  var discoveryEnabled = true
    46  var persistenceEnabled = false
    47  
    48  var services = adapters.Services{
    49  	serviceName: newService,
    50  }
    51  
    52  func cleanDbStores() error {
    53  	entries, err := ioutil.ReadDir(os.TempDir())
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	for _, f := range entries {
    59  		if strings.HasPrefix(f.Name(), discoveryPersistenceDatadir) {
    60  			os.RemoveAll(path.Join(os.TempDir(), f.Name()))
    61  		}
    62  	}
    63  	return nil
    64  
    65  }
    66  
    67  func getDbStore(nodeID string) (*state.DBStore, error) {
    68  	if _, err := os.Stat(discoveryPersistencePath + "_" + nodeID); os.IsNotExist(err) {
    69  		log.Info(fmt.Sprintf("directory for nodeID %s does not exist. creating...", nodeID))
    70  		ioutil.TempDir("", discoveryPersistencePath+"_"+nodeID)
    71  	}
    72  	log.Info(fmt.Sprintf("opening storage directory for nodeID %s", nodeID))
    73  	store, err := state.NewDBStore(discoveryPersistencePath + "_" + nodeID)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	return store, nil
    78  }
    79  
    80  var (
    81  	nodeCount = flag.Int("nodes", 32, "number of nodes to create (default 32)")
    82  	initCount = flag.Int("conns", 1, "number of originally connected peers	 (default 1)")
    83  	loglevel  = flag.Int("loglevel", 3, "verbosity of logs")
    84  	rawlog    = flag.Bool("rawlog", false, "remove terminal formatting from logs")
    85  )
    86  
    87  func init() {
    88  	flag.Parse()
    89  //注册将作为devp2p运行的发现服务
    90  //使用Exec适配器时的协议
    91  	adapters.RegisterServices(services)
    92  
    93  	log.PrintOrigins(true)
    94  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(!*rawlog))))
    95  }
    96  
    97  //测试n节点环所需平均时间的基准
    98  //充分利用健康的卡德米利亚拓扑
    99  func BenchmarkDiscovery_8_1(b *testing.B)   { benchmarkDiscovery(b, 8, 1) }
   100  func BenchmarkDiscovery_16_1(b *testing.B)  { benchmarkDiscovery(b, 16, 1) }
   101  func BenchmarkDiscovery_32_1(b *testing.B)  { benchmarkDiscovery(b, 32, 1) }
   102  func BenchmarkDiscovery_64_1(b *testing.B)  { benchmarkDiscovery(b, 64, 1) }
   103  func BenchmarkDiscovery_128_1(b *testing.B) { benchmarkDiscovery(b, 128, 1) }
   104  func BenchmarkDiscovery_256_1(b *testing.B) { benchmarkDiscovery(b, 256, 1) }
   105  
   106  func BenchmarkDiscovery_8_2(b *testing.B)   { benchmarkDiscovery(b, 8, 2) }
   107  func BenchmarkDiscovery_16_2(b *testing.B)  { benchmarkDiscovery(b, 16, 2) }
   108  func BenchmarkDiscovery_32_2(b *testing.B)  { benchmarkDiscovery(b, 32, 2) }
   109  func BenchmarkDiscovery_64_2(b *testing.B)  { benchmarkDiscovery(b, 64, 2) }
   110  func BenchmarkDiscovery_128_2(b *testing.B) { benchmarkDiscovery(b, 128, 2) }
   111  func BenchmarkDiscovery_256_2(b *testing.B) { benchmarkDiscovery(b, 256, 2) }
   112  
   113  func BenchmarkDiscovery_8_4(b *testing.B)   { benchmarkDiscovery(b, 8, 4) }
   114  func BenchmarkDiscovery_16_4(b *testing.B)  { benchmarkDiscovery(b, 16, 4) }
   115  func BenchmarkDiscovery_32_4(b *testing.B)  { benchmarkDiscovery(b, 32, 4) }
   116  func BenchmarkDiscovery_64_4(b *testing.B)  { benchmarkDiscovery(b, 64, 4) }
   117  func BenchmarkDiscovery_128_4(b *testing.B) { benchmarkDiscovery(b, 128, 4) }
   118  func BenchmarkDiscovery_256_4(b *testing.B) { benchmarkDiscovery(b, 256, 4) }
   119  
   120  func TestDiscoverySimulationExecAdapter(t *testing.T) {
   121  	testDiscoverySimulationExecAdapter(t, *nodeCount, *initCount)
   122  }
   123  
   124  func testDiscoverySimulationExecAdapter(t *testing.T, nodes, conns int) {
   125  	baseDir, err := ioutil.TempDir("", "swarm-test")
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	defer os.RemoveAll(baseDir)
   130  	testDiscoverySimulation(t, nodes, conns, adapters.NewExecAdapter(baseDir))
   131  }
   132  
   133  func TestDiscoverySimulationSimAdapter(t *testing.T) {
   134  	testDiscoverySimulationSimAdapter(t, *nodeCount, *initCount)
   135  }
   136  
   137  func TestDiscoveryPersistenceSimulationSimAdapter(t *testing.T) {
   138  	testDiscoveryPersistenceSimulationSimAdapter(t, *nodeCount, *initCount)
   139  }
   140  
   141  func testDiscoveryPersistenceSimulationSimAdapter(t *testing.T, nodes, conns int) {
   142  	testDiscoveryPersistenceSimulation(t, nodes, conns, adapters.NewSimAdapter(services))
   143  }
   144  
   145  func testDiscoverySimulationSimAdapter(t *testing.T, nodes, conns int) {
   146  	testDiscoverySimulation(t, nodes, conns, adapters.NewSimAdapter(services))
   147  }
   148  
   149  func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) {
   150  	startedAt := time.Now()
   151  	result, err := discoverySimulation(nodes, conns, adapter)
   152  	if err != nil {
   153  		t.Fatalf("Setting up simulation failed: %v", err)
   154  	}
   155  	if result.Error != nil {
   156  		t.Fatalf("Simulation failed: %s", result.Error)
   157  	}
   158  	t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt))
   159  	var min, max time.Duration
   160  	var sum int
   161  	for _, pass := range result.Passes {
   162  		duration := pass.Sub(result.StartedAt)
   163  		if sum == 0 || duration < min {
   164  			min = duration
   165  		}
   166  		if duration > max {
   167  			max = duration
   168  		}
   169  		sum += int(duration.Nanoseconds())
   170  	}
   171  	t.Logf("Min: %s, Max: %s, Average: %s", min, max, time.Duration(sum/len(result.Passes))*time.Nanosecond)
   172  	finishedAt := time.Now()
   173  	t.Logf("Setup: %s, shutdown: %s", result.StartedAt.Sub(startedAt), finishedAt.Sub(result.FinishedAt))
   174  }
   175  
   176  func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte {
   177  	persistenceEnabled = true
   178  	discoveryEnabled = true
   179  
   180  	result, err := discoveryPersistenceSimulation(nodes, conns, adapter)
   181  
   182  	if err != nil {
   183  		t.Fatalf("Setting up simulation failed: %v", err)
   184  	}
   185  	if result.Error != nil {
   186  		t.Fatalf("Simulation failed: %s", result.Error)
   187  	}
   188  	t.Logf("Simulation with %d nodes passed in %s", nodes, result.FinishedAt.Sub(result.StartedAt))
   189  //再次将发现和持久性标志设置为默认值,以便
   190  //测试不会受到影响
   191  	discoveryEnabled = true
   192  	persistenceEnabled = false
   193  	return nil
   194  }
   195  
   196  func benchmarkDiscovery(b *testing.B, nodes, conns int) {
   197  	for i := 0; i < b.N; i++ {
   198  		result, err := discoverySimulation(nodes, conns, adapters.NewSimAdapter(services))
   199  		if err != nil {
   200  			b.Fatalf("setting up simulation failed: %v", err)
   201  		}
   202  		if result.Error != nil {
   203  			b.Logf("simulation failed: %s", result.Error)
   204  		}
   205  	}
   206  }
   207  
   208  func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) {
   209  //创建网络
   210  	net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
   211  		ID:             "0",
   212  		DefaultService: serviceName,
   213  	})
   214  	defer net.Shutdown()
   215  	trigger := make(chan enode.ID)
   216  	ids := make([]enode.ID, nodes)
   217  	for i := 0; i < nodes; i++ {
   218  		conf := adapters.RandomNodeConfig()
   219  		node, err := net.NewNodeWithConfig(conf)
   220  		if err != nil {
   221  			return nil, fmt.Errorf("error starting node: %s", err)
   222  		}
   223  		if err := net.Start(node.ID()); err != nil {
   224  			return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   225  		}
   226  		if err := triggerChecks(trigger, net, node.ID()); err != nil {
   227  			return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   228  		}
   229  		ids[i] = node.ID()
   230  	}
   231  
   232  //运行一个模拟,将一个环中的10个节点连接起来并等待
   233  //用于完全对等机发现
   234  	var addrs [][]byte
   235  	action := func(ctx context.Context) error {
   236  		return nil
   237  	}
   238  	for i := range ids {
   239  //收集覆盖地址,至
   240  		addrs = append(addrs, ids[i].Bytes())
   241  	}
   242  	err := net.ConnectNodesChain(nil)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	log.Debug(fmt.Sprintf("nodes: %v", len(addrs)))
   247  //建造对等壶,以便检查卡德米利亚的健康状况。
   248  	ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs)
   249  	check := func(ctx context.Context, id enode.ID) (bool, error) {
   250  		select {
   251  		case <-ctx.Done():
   252  			return false, ctx.Err()
   253  		default:
   254  		}
   255  
   256  		node := net.GetNode(id)
   257  		if node == nil {
   258  			return false, fmt.Errorf("unknown node: %s", id)
   259  		}
   260  		client, err := node.Client()
   261  		if err != nil {
   262  			return false, fmt.Errorf("error getting node client: %s", err)
   263  		}
   264  
   265  		healthy := &network.Health{}
   266  		if err := client.Call(&healthy, "hive_healthy", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil {
   267  			return false, fmt.Errorf("error getting node health: %s", err)
   268  		}
   269  		log.Debug(fmt.Sprintf("node %4s healthy: connected nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.ConnectNN, healthy.KnowNN, healthy.Hive))
   270  		return healthy.KnowNN && healthy.ConnectNN, nil
   271  	}
   272  
   273  //64节点~1min
   274  //128节点~
   275  	timeout := 300 * time.Second
   276  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   277  	defer cancel()
   278  	result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{
   279  		Action:  action,
   280  		Trigger: trigger,
   281  		Expect: &simulations.Expectation{
   282  			Nodes: ids,
   283  			Check: check,
   284  		},
   285  	})
   286  	if result.Error != nil {
   287  		return result, nil
   288  	}
   289  	return result, nil
   290  }
   291  
   292  func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simulations.StepResult, error) {
   293  	cleanDbStores()
   294  	defer cleanDbStores()
   295  
   296  //创建网络
   297  	net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
   298  		ID:             "0",
   299  		DefaultService: serviceName,
   300  	})
   301  	defer net.Shutdown()
   302  	trigger := make(chan enode.ID)
   303  	ids := make([]enode.ID, nodes)
   304  	var addrs [][]byte
   305  
   306  	for i := 0; i < nodes; i++ {
   307  		conf := adapters.RandomNodeConfig()
   308  		node, err := net.NewNodeWithConfig(conf)
   309  		if err != nil {
   310  			panic(err)
   311  		}
   312  		if err != nil {
   313  			return nil, fmt.Errorf("error starting node: %s", err)
   314  		}
   315  		if err := net.Start(node.ID()); err != nil {
   316  			return nil, fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   317  		}
   318  		if err := triggerChecks(trigger, net, node.ID()); err != nil {
   319  			return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   320  		}
   321  //Todo我们不应该这样把underddr和overddr等同起来,因为它们在生产中是不一样的。
   322  		ids[i] = node.ID()
   323  		a := ids[i].Bytes()
   324  
   325  		addrs = append(addrs, a)
   326  	}
   327  
   328  //运行一个模拟,将一个环中的10个节点连接起来并等待
   329  //用于完全对等机发现
   330  
   331  	var restartTime time.Time
   332  
   333  	action := func(ctx context.Context) error {
   334  		ticker := time.NewTicker(500 * time.Millisecond)
   335  
   336  		for range ticker.C {
   337  			isHealthy := true
   338  			for _, id := range ids {
   339  //调用健康的RPC
   340  				node := net.GetNode(id)
   341  				if node == nil {
   342  					return fmt.Errorf("unknown node: %s", id)
   343  				}
   344  				client, err := node.Client()
   345  				if err != nil {
   346  					return fmt.Errorf("error getting node client: %s", err)
   347  				}
   348  				healthy := &network.Health{}
   349  				addr := id.String()
   350  				ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs)
   351  				if err := client.Call(&healthy, "hive_healthy", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil {
   352  					return fmt.Errorf("error getting node health: %s", err)
   353  				}
   354  
   355  				log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.ConnectNN && healthy.KnowNN && healthy.CountKnowNN > 0))
   356  				var nodeStr string
   357  				if err := client.Call(&nodeStr, "hive_string"); err != nil {
   358  					return fmt.Errorf("error getting node string %s", err)
   359  				}
   360  				log.Info(nodeStr)
   361  				for _, a := range addrs {
   362  					log.Info(common.Bytes2Hex(a))
   363  				}
   364  				if !healthy.ConnectNN || healthy.CountKnowNN == 0 {
   365  					isHealthy = false
   366  					break
   367  				}
   368  			}
   369  			if isHealthy {
   370  				break
   371  			}
   372  		}
   373  		ticker.Stop()
   374  
   375  		log.Info("reached healthy kademlia. starting to shutdown nodes.")
   376  		shutdownStarted := time.Now()
   377  //停止所有ID,然后重新启动它们
   378  		for _, id := range ids {
   379  			node := net.GetNode(id)
   380  
   381  			if err := net.Stop(node.ID()); err != nil {
   382  				return fmt.Errorf("error stopping node %s: %s", node.ID().TerminalString(), err)
   383  			}
   384  		}
   385  		log.Info(fmt.Sprintf("shutting down nodes took: %s", time.Since(shutdownStarted)))
   386  		persistenceEnabled = true
   387  		discoveryEnabled = false
   388  		restartTime = time.Now()
   389  		for _, id := range ids {
   390  			node := net.GetNode(id)
   391  			if err := net.Start(node.ID()); err != nil {
   392  				return fmt.Errorf("error starting node %s: %s", node.ID().TerminalString(), err)
   393  			}
   394  			if err := triggerChecks(trigger, net, node.ID()); err != nil {
   395  				return fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
   396  			}
   397  		}
   398  
   399  		log.Info(fmt.Sprintf("restarting nodes took: %s", time.Since(restartTime)))
   400  
   401  		return nil
   402  	}
   403  	net.ConnectNodesChain(nil)
   404  	log.Debug(fmt.Sprintf("nodes: %v", len(addrs)))
   405  //建造对等壶,以便检查卡德米利亚的健康状况。
   406  	check := func(ctx context.Context, id enode.ID) (bool, error) {
   407  		select {
   408  		case <-ctx.Done():
   409  			return false, ctx.Err()
   410  		default:
   411  		}
   412  
   413  		node := net.GetNode(id)
   414  		if node == nil {
   415  			return false, fmt.Errorf("unknown node: %s", id)
   416  		}
   417  		client, err := node.Client()
   418  		if err != nil {
   419  			return false, fmt.Errorf("error getting node client: %s", err)
   420  		}
   421  		healthy := &network.Health{}
   422  		ppmap := network.NewPeerPotMap(network.NewKadParams().NeighbourhoodSize, addrs)
   423  
   424  		if err := client.Call(&healthy, "hive_healthy", ppmap[common.Bytes2Hex(id.Bytes())]); err != nil {
   425  			return false, fmt.Errorf("error getting node health: %s", err)
   426  		}
   427  		log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v", id, healthy.ConnectNN, healthy.KnowNN))
   428  
   429  		return healthy.KnowNN && healthy.ConnectNN, nil
   430  	}
   431  
   432  //64节点~1min
   433  //128节点~
   434  	timeout := 300 * time.Second
   435  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   436  	defer cancel()
   437  	result := simulations.NewSimulation(net).Run(ctx, &simulations.Step{
   438  		Action:  action,
   439  		Trigger: trigger,
   440  		Expect: &simulations.Expectation{
   441  			Nodes: ids,
   442  			Check: check,
   443  		},
   444  	})
   445  	if result.Error != nil {
   446  		return result, nil
   447  	}
   448  
   449  	return result, nil
   450  }
   451  
   452  //每当添加对等机或
   453  //从给定的节点中删除,并且每隔一秒删除一次,以避免
   454  //同伴活动和卡德米利亚变得健康
   455  func triggerChecks(trigger chan enode.ID, net *simulations.Network, id enode.ID) error {
   456  	node := net.GetNode(id)
   457  	if node == nil {
   458  		return fmt.Errorf("unknown node: %s", id)
   459  	}
   460  	client, err := node.Client()
   461  	if err != nil {
   462  		return err
   463  	}
   464  	events := make(chan *p2p.PeerEvent)
   465  	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents")
   466  	if err != nil {
   467  		return fmt.Errorf("error getting peer events for node %v: %s", id, err)
   468  	}
   469  	go func() {
   470  		defer sub.Unsubscribe()
   471  
   472  		tick := time.NewTicker(time.Second)
   473  		defer tick.Stop()
   474  
   475  		for {
   476  			select {
   477  			case <-events:
   478  				trigger <- id
   479  			case <-tick.C:
   480  				trigger <- id
   481  			case err := <-sub.Err():
   482  				if err != nil {
   483  					log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err)
   484  				}
   485  				return
   486  			}
   487  		}
   488  	}()
   489  	return nil
   490  }
   491  
   492  func newService(ctx *adapters.ServiceContext) (node.Service, error) {
   493  	addr := network.NewAddr(ctx.Config.Node())
   494  
   495  	kp := network.NewKadParams()
   496  	kp.NeighbourhoodSize = testNeighbourhoodSize
   497  
   498  	if ctx.Config.Reachable != nil {
   499  		kp.Reachable = func(o *network.BzzAddr) bool {
   500  			return ctx.Config.Reachable(o.ID())
   501  		}
   502  	}
   503  	kad := network.NewKademlia(addr.Over(), kp)
   504  	hp := network.NewHiveParams()
   505  	hp.KeepAliveInterval = time.Duration(200) * time.Millisecond
   506  	hp.Discovery = discoveryEnabled
   507  
   508  	log.Info(fmt.Sprintf("discovery for nodeID %s is %t", ctx.Config.ID.String(), hp.Discovery))
   509  
   510  	config := &network.BzzConfig{
   511  		OverlayAddr:  addr.Over(),
   512  		UnderlayAddr: addr.Under(),
   513  		HiveParams:   hp,
   514  	}
   515  
   516  	if persistenceEnabled {
   517  		log.Info(fmt.Sprintf("persistence enabled for nodeID %s", ctx.Config.ID.String()))
   518  		store, err := getDbStore(ctx.Config.ID.String())
   519  		if err != nil {
   520  			return nil, err
   521  		}
   522  		return network.NewBzz(config, kad, store, nil, nil), nil
   523  	}
   524  
   525  	return network.NewBzz(config, kad, nil, nil, nil), nil
   526  }
   527