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