github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/swarm/run_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 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊的一部分。 11 // 12 //Go以太坊是免费软件:您可以重新发布和/或修改它 13 //根据GNU通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊的分布希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU通用公共许可证了解更多详细信息。 21 // 22 //你应该已经收到一份GNU通用公共许可证的副本 23 //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package main 26 27 import ( 28 "context" 29 "crypto/ecdsa" 30 "fmt" 31 "io/ioutil" 32 "net" 33 "os" 34 "path" 35 "path/filepath" 36 "runtime" 37 "sync" 38 "syscall" 39 "testing" 40 "time" 41 42 "github.com/docker/docker/pkg/reexec" 43 "github.com/ethereum/go-ethereum/accounts" 44 "github.com/ethereum/go-ethereum/accounts/keystore" 45 "github.com/ethereum/go-ethereum/internal/cmdtest" 46 "github.com/ethereum/go-ethereum/node" 47 "github.com/ethereum/go-ethereum/p2p" 48 "github.com/ethereum/go-ethereum/rpc" 49 "github.com/ethereum/go-ethereum/swarm" 50 ) 51 52 func init() { 53 //如果我们在run swarm中被执行为“swarm测试”,就运行这个应用程序。 54 reexec.Register("swarm-test", func() { 55 if err := app.Run(os.Args); err != nil { 56 fmt.Fprintln(os.Stderr, err) 57 os.Exit(1) 58 } 59 os.Exit(0) 60 }) 61 } 62 63 func TestMain(m *testing.M) { 64 //检查我们是否被重新执行了 65 if reexec.Init() { 66 return 67 } 68 os.Exit(m.Run()) 69 } 70 71 func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { 72 tt := cmdtest.NewTestCmd(t, nil) 73 74 // 75 //函数将阻止任何测试运行。 76 tt.Run("swarm-test", args...) 77 78 return tt 79 } 80 81 type testCluster struct { 82 Nodes []*testNode 83 TmpDir string 84 } 85 86 // 87 // 88 // 89 //它。 90 // 91 // 92 // 93 // 94 // 95 // 96 // 97 98 func newTestCluster(t *testing.T, size int) *testCluster { 99 cluster := &testCluster{} 100 defer func() { 101 if t.Failed() { 102 cluster.Shutdown() 103 } 104 }() 105 106 tmpdir, err := ioutil.TempDir("", "swarm-test") 107 if err != nil { 108 t.Fatal(err) 109 } 110 cluster.TmpDir = tmpdir 111 112 // 113 cluster.StartNewNodes(t, size) 114 115 if size == 1 { 116 return cluster 117 } 118 119 // 120 for _, node := range cluster.Nodes { 121 if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { 122 t.Fatal(err) 123 } 124 } 125 126 // 127 outer: 128 for _, node := range cluster.Nodes { 129 var peers []*p2p.PeerInfo 130 for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(50 * time.Millisecond) { 131 if err := node.Client.Call(&peers, "admin_peers"); err != nil { 132 t.Fatal(err) 133 } 134 if len(peers) == len(cluster.Nodes)-1 { 135 continue outer 136 } 137 } 138 t.Fatalf("%s only has %d / %d peers", node.Name, len(peers), len(cluster.Nodes)-1) 139 } 140 141 return cluster 142 } 143 144 func (c *testCluster) Shutdown() { 145 for _, node := range c.Nodes { 146 node.Shutdown() 147 } 148 os.RemoveAll(c.TmpDir) 149 } 150 151 func (c *testCluster) Stop() { 152 for _, node := range c.Nodes { 153 node.Shutdown() 154 } 155 } 156 157 func (c *testCluster) StartNewNodes(t *testing.T, size int) { 158 c.Nodes = make([]*testNode, 0, size) 159 for i := 0; i < size; i++ { 160 dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) 161 if err := os.Mkdir(dir, 0700); err != nil { 162 t.Fatal(err) 163 } 164 165 node := newTestNode(t, dir) 166 node.Name = fmt.Sprintf("swarm%02d", i) 167 168 c.Nodes = append(c.Nodes, node) 169 } 170 } 171 172 func (c *testCluster) StartExistingNodes(t *testing.T, size int, bzzaccount string) { 173 c.Nodes = make([]*testNode, 0, size) 174 for i := 0; i < size; i++ { 175 dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) 176 node := existingTestNode(t, dir, bzzaccount) 177 node.Name = fmt.Sprintf("swarm%02d", i) 178 179 c.Nodes = append(c.Nodes, node) 180 } 181 } 182 183 func (c *testCluster) Cleanup() { 184 os.RemoveAll(c.TmpDir) 185 } 186 187 type testNode struct { 188 Name string 189 Addr string 190 URL string 191 Enode string 192 Dir string 193 IpcPath string 194 PrivateKey *ecdsa.PrivateKey 195 Client *rpc.Client 196 Cmd *cmdtest.TestCmd 197 } 198 199 const testPassphrase = "swarm-test-passphrase" 200 201 func getTestAccount(t *testing.T, dir string) (conf *node.Config, account accounts.Account) { 202 //创建密钥 203 conf = &node.Config{ 204 DataDir: dir, 205 IPCPath: "bzzd.ipc", 206 NoUSB: true, 207 } 208 n, err := node.New(conf) 209 if err != nil { 210 t.Fatal(err) 211 } 212 account, err = n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore).NewAccount(testPassphrase) 213 if err != nil { 214 t.Fatal(err) 215 } 216 217 //在Windows上运行测试时使用唯一的ipcpath 218 if runtime.GOOS == "windows" { 219 conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", account.Address.String()) 220 } 221 222 return conf, account 223 } 224 225 func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode { 226 conf, _ := getTestAccount(t, dir) 227 node := &testNode{Dir: dir} 228 229 //在Windows上运行测试时使用唯一的ipcpath 230 if runtime.GOOS == "windows" { 231 conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", bzzaccount) 232 } 233 234 //指定端口 235 ports, err := getAvailableTCPPorts(2) 236 if err != nil { 237 t.Fatal(err) 238 } 239 p2pPort := ports[0] 240 httpPort := ports[1] 241 242 //启动节点 243 node.Cmd = runSwarm(t, 244 "--port", p2pPort, 245 "--nodiscover", 246 "--datadir", dir, 247 "--ipcpath", conf.IPCPath, 248 "--ens-api", "", 249 "--bzzaccount", bzzaccount, 250 "--bzznetworkid", "321", 251 "--bzzport", httpPort, 252 "--verbosity", "6", 253 ) 254 node.Cmd.InputLine(testPassphrase) 255 defer func() { 256 if t.Failed() { 257 node.Shutdown() 258 } 259 }() 260 261 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 262 defer cancel() 263 264 //确保所有端口都有活动的侦听器 265 //这样下一个节点就不会得到相同的 266 //调用GetAvailableTCPPorts时 267 err = waitTCPPorts(ctx, ports...) 268 if err != nil { 269 t.Fatal(err) 270 } 271 272 //等待节点启动 273 for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { 274 node.Client, err = rpc.Dial(conf.IPCEndpoint()) 275 if err == nil { 276 break 277 } 278 } 279 if node.Client == nil { 280 t.Fatal(err) 281 } 282 283 //加载信息 284 var info swarm.Info 285 if err := node.Client.Call(&info, "bzz_info"); err != nil { 286 t.Fatal(err) 287 } 288 node.Addr = net.JoinHostPort("127.0.0.1", info.Port) 289 node.URL = "http://“+No.ADDR” 290 291 var nodeInfo p2p.NodeInfo 292 if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { 293 t.Fatal(err) 294 } 295 node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s”,nodeinfo.id,p2pport) 296 297 return node 298 } 299 300 func newTestNode(t *testing.T, dir string) *testNode { 301 302 conf, account := getTestAccount(t, dir) 303 ks := keystore.NewKeyStore(path.Join(dir, "keystore"), 1<<18, 1) 304 305 pk := decryptStoreAccount(ks, account.Address.Hex(), []string{testPassphrase}) 306 307 node := &testNode{Dir: dir, PrivateKey: pk} 308 309 //指定端口 310 ports, err := getAvailableTCPPorts(2) 311 if err != nil { 312 t.Fatal(err) 313 } 314 p2pPort := ports[0] 315 httpPort := ports[1] 316 317 //启动节点 318 node.Cmd = runSwarm(t, 319 "--port", p2pPort, 320 "--nodiscover", 321 "--datadir", dir, 322 "--ipcpath", conf.IPCPath, 323 "--ens-api", "", 324 "--bzzaccount", account.Address.String(), 325 "--bzznetworkid", "321", 326 "--bzzport", httpPort, 327 "--verbosity", "6", 328 ) 329 node.Cmd.InputLine(testPassphrase) 330 defer func() { 331 if t.Failed() { 332 node.Shutdown() 333 } 334 }() 335 336 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 337 defer cancel() 338 339 //确保所有端口都有活动的侦听器 340 //这样下一个节点就不会得到相同的 341 //调用GetAvailableTCPPorts时 342 err = waitTCPPorts(ctx, ports...) 343 if err != nil { 344 t.Fatal(err) 345 } 346 347 //等待节点启动 348 for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { 349 node.Client, err = rpc.Dial(conf.IPCEndpoint()) 350 if err == nil { 351 break 352 } 353 } 354 if node.Client == nil { 355 t.Fatal(err) 356 } 357 358 //加载信息 359 var info swarm.Info 360 if err := node.Client.Call(&info, "bzz_info"); err != nil { 361 t.Fatal(err) 362 } 363 node.Addr = net.JoinHostPort("127.0.0.1", info.Port) 364 node.URL = "http://“+No.ADDR” 365 366 var nodeInfo p2p.NodeInfo 367 if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { 368 t.Fatal(err) 369 } 370 node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s”,nodeinfo.id,p2pport) 371 node.IpcPath = conf.IPCPath 372 373 return node 374 } 375 376 func (n *testNode) Shutdown() { 377 if n.Cmd != nil { 378 n.Cmd.Kill() 379 } 380 } 381 382 // 383 // 384 // 385 // 386 //并保证同一港口将被运回 387 //不同的调用,因为侦听器在函数内关闭, 388 // 389 //可用端口。 390 func getAvailableTCPPorts(count int) (ports []string, err error) { 391 for i := 0; i < count; i++ { 392 l, err := net.Listen("tcp", "127.0.0.1:0") 393 if err != nil { 394 return nil, err 395 } 396 //在循环中延迟关闭以确保同一端口不会 397 //在下一个迭代中被选择 398 defer l.Close() 399 400 _, port, err := net.SplitHostPort(l.Addr().String()) 401 if err != nil { 402 return nil, err 403 } 404 ports = append(ports, port) 405 } 406 return ports, nil 407 } 408 409 // 410 // 411 // 412 //遇到错误。 413 //另请参见waitcpport。 414 func waitTCPPorts(ctx context.Context, ports ...string) error { 415 var err error 416 //在中分配的mu locks err变量 417 //其他Goroutines 418 var mu sync.Mutex 419 420 // 421 // 422 //防止不必要的等待 423 ctx, cancel := context.WithCancel(ctx) 424 defer cancel() 425 426 var wg sync.WaitGroup 427 for _, port := range ports { 428 wg.Add(1) 429 go func(port string) { 430 defer wg.Done() 431 432 e := waitTCPPort(ctx, port) 433 434 mu.Lock() 435 defer mu.Unlock() 436 if e != nil && err == nil { 437 err = e 438 cancel() 439 } 440 }(port) 441 } 442 wg.Wait() 443 444 return err 445 } 446 447 // 448 //ONA提供的端口。它最多有3分钟的超时时间, 449 // 450 //提供的上下文实例。拨号程序超时10秒 451 //在每次迭代中,连接被拒绝的错误将 452 //在100毫秒内重试。 453 func waitTCPPort(ctx context.Context, port string) error { 454 ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) 455 defer cancel() 456 457 for { 458 c, err := (&net.Dialer{Timeout: 10 * time.Second}).DialContext(ctx, "tcp", "127.0.0.1:"+port) 459 if err != nil { 460 if operr, ok := err.(*net.OpError); ok { 461 if syserr, ok := operr.Err.(*os.SyscallError); ok && syserr.Err == syscall.ECONNREFUSED { 462 time.Sleep(100 * time.Millisecond) 463 continue 464 } 465 } 466 return err 467 } 468 return c.Close() 469 } 470 }