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