github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/p2psim/main.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 //p2psim为模拟HTTP API提供命令行客户端。 26 // 27 //下面是用第一个节点创建2节点网络的示例 28 //连接到第二个: 29 // 30 //$p2psim节点创建 31 //创建节点01 32 // 33 //$p2psim节点开始节点01 34 //启动NODE01 35 // 36 //$p2psim节点创建 37 //创建NoDE02 38 // 39 //$p2psim节点开始节点02 40 //启动NODE02 41 // 42 //$p2psim节点连接node01 node02 43 //已将node01连接到node02 44 // 45 package main 46 47 import ( 48 "context" 49 "encoding/json" 50 "fmt" 51 "io" 52 "os" 53 "strings" 54 "text/tabwriter" 55 56 "github.com/ethereum/go-ethereum/crypto" 57 "github.com/ethereum/go-ethereum/p2p" 58 "github.com/ethereum/go-ethereum/p2p/discover" 59 "github.com/ethereum/go-ethereum/p2p/simulations" 60 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 61 "github.com/ethereum/go-ethereum/rpc" 62 "gopkg.in/urfave/cli.v1" 63 ) 64 65 var client *simulations.Client 66 67 func main() { 68 app := cli.NewApp() 69 app.Usage = "devp2p simulation command-line client" 70 app.Flags = []cli.Flag{ 71 cli.StringFlag{ 72 Name: "api", 73 Value: "http://本地主机:8888“, 74 Usage: "simulation API URL", 75 EnvVar: "P2PSIM_API_URL", 76 }, 77 } 78 app.Before = func(ctx *cli.Context) error { 79 client = simulations.NewClient(ctx.GlobalString("api")) 80 return nil 81 } 82 app.Commands = []cli.Command{ 83 { 84 Name: "show", 85 Usage: "show network information", 86 Action: showNetwork, 87 }, 88 { 89 Name: "events", 90 Usage: "stream network events", 91 Action: streamNetwork, 92 Flags: []cli.Flag{ 93 cli.BoolFlag{ 94 Name: "current", 95 Usage: "get existing nodes and conns first", 96 }, 97 cli.StringFlag{ 98 Name: "filter", 99 Value: "", 100 Usage: "message filter", 101 }, 102 }, 103 }, 104 { 105 Name: "snapshot", 106 Usage: "create a network snapshot to stdout", 107 Action: createSnapshot, 108 }, 109 { 110 Name: "load", 111 Usage: "load a network snapshot from stdin", 112 Action: loadSnapshot, 113 }, 114 { 115 Name: "node", 116 Usage: "manage simulation nodes", 117 Action: listNodes, 118 Subcommands: []cli.Command{ 119 { 120 Name: "list", 121 Usage: "list nodes", 122 Action: listNodes, 123 }, 124 { 125 Name: "create", 126 Usage: "create a node", 127 Action: createNode, 128 Flags: []cli.Flag{ 129 cli.StringFlag{ 130 Name: "name", 131 Value: "", 132 Usage: "node name", 133 }, 134 cli.StringFlag{ 135 Name: "services", 136 Value: "", 137 Usage: "node services (comma separated)", 138 }, 139 cli.StringFlag{ 140 Name: "key", 141 Value: "", 142 Usage: "node private key (hex encoded)", 143 }, 144 }, 145 }, 146 { 147 Name: "show", 148 ArgsUsage: "<node>", 149 Usage: "show node information", 150 Action: showNode, 151 }, 152 { 153 Name: "start", 154 ArgsUsage: "<node>", 155 Usage: "start a node", 156 Action: startNode, 157 }, 158 { 159 Name: "stop", 160 ArgsUsage: "<node>", 161 Usage: "stop a node", 162 Action: stopNode, 163 }, 164 { 165 Name: "connect", 166 ArgsUsage: "<node> <peer>", 167 Usage: "connect a node to a peer node", 168 Action: connectNode, 169 }, 170 { 171 Name: "disconnect", 172 ArgsUsage: "<node> <peer>", 173 Usage: "disconnect a node from a peer node", 174 Action: disconnectNode, 175 }, 176 { 177 Name: "rpc", 178 ArgsUsage: "<node> <method> [<args>]", 179 Usage: "call a node RPC method", 180 Action: rpcNode, 181 Flags: []cli.Flag{ 182 cli.BoolFlag{ 183 Name: "subscribe", 184 Usage: "method is a subscription", 185 }, 186 }, 187 }, 188 }, 189 }, 190 } 191 if err := app.Run(os.Args); err != nil { 192 fmt.Fprintln(os.Stderr, err) 193 os.Exit(1) 194 } 195 } 196 197 func showNetwork(ctx *cli.Context) error { 198 if len(ctx.Args()) != 0 { 199 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 200 } 201 network, err := client.GetNetwork() 202 if err != nil { 203 return err 204 } 205 w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) 206 defer w.Flush() 207 fmt.Fprintf(w, "NODES\t%d\n", len(network.Nodes)) 208 fmt.Fprintf(w, "CONNS\t%d\n", len(network.Conns)) 209 return nil 210 } 211 212 func streamNetwork(ctx *cli.Context) error { 213 if len(ctx.Args()) != 0 { 214 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 215 } 216 events := make(chan *simulations.Event) 217 sub, err := client.SubscribeNetwork(events, simulations.SubscribeOpts{ 218 Current: ctx.Bool("current"), 219 Filter: ctx.String("filter"), 220 }) 221 if err != nil { 222 return err 223 } 224 defer sub.Unsubscribe() 225 enc := json.NewEncoder(ctx.App.Writer) 226 for { 227 select { 228 case event := <-events: 229 if err := enc.Encode(event); err != nil { 230 return err 231 } 232 case err := <-sub.Err(): 233 return err 234 } 235 } 236 } 237 238 func createSnapshot(ctx *cli.Context) error { 239 if len(ctx.Args()) != 0 { 240 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 241 } 242 snap, err := client.CreateSnapshot() 243 if err != nil { 244 return err 245 } 246 return json.NewEncoder(os.Stdout).Encode(snap) 247 } 248 249 func loadSnapshot(ctx *cli.Context) error { 250 if len(ctx.Args()) != 0 { 251 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 252 } 253 snap := &simulations.Snapshot{} 254 if err := json.NewDecoder(os.Stdin).Decode(snap); err != nil { 255 return err 256 } 257 return client.LoadSnapshot(snap) 258 } 259 260 func listNodes(ctx *cli.Context) error { 261 if len(ctx.Args()) != 0 { 262 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 263 } 264 nodes, err := client.GetNodes() 265 if err != nil { 266 return err 267 } 268 w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) 269 defer w.Flush() 270 fmt.Fprintf(w, "NAME\tPROTOCOLS\tID\n") 271 for _, node := range nodes { 272 fmt.Fprintf(w, "%s\t%s\t%s\n", node.Name, strings.Join(protocolList(node), ","), node.ID) 273 } 274 return nil 275 } 276 277 func protocolList(node *p2p.NodeInfo) []string { 278 protos := make([]string, 0, len(node.Protocols)) 279 for name := range node.Protocols { 280 protos = append(protos, name) 281 } 282 return protos 283 } 284 285 func createNode(ctx *cli.Context) error { 286 if len(ctx.Args()) != 0 { 287 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 288 } 289 config := adapters.RandomNodeConfig() 290 config.Name = ctx.String("name") 291 if key := ctx.String("key"); key != "" { 292 privKey, err := crypto.HexToECDSA(key) 293 if err != nil { 294 return err 295 } 296 config.ID = discover.PubkeyID(&privKey.PublicKey) 297 config.PrivateKey = privKey 298 } 299 if services := ctx.String("services"); services != "" { 300 config.Services = strings.Split(services, ",") 301 } 302 node, err := client.CreateNode(config) 303 if err != nil { 304 return err 305 } 306 fmt.Fprintln(ctx.App.Writer, "Created", node.Name) 307 return nil 308 } 309 310 func showNode(ctx *cli.Context) error { 311 args := ctx.Args() 312 if len(args) != 1 { 313 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 314 } 315 nodeName := args[0] 316 node, err := client.GetNode(nodeName) 317 if err != nil { 318 return err 319 } 320 w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) 321 defer w.Flush() 322 fmt.Fprintf(w, "NAME\t%s\n", node.Name) 323 fmt.Fprintf(w, "PROTOCOLS\t%s\n", strings.Join(protocolList(node), ",")) 324 fmt.Fprintf(w, "ID\t%s\n", node.ID) 325 fmt.Fprintf(w, "ENODE\t%s\n", node.Enode) 326 for name, proto := range node.Protocols { 327 fmt.Fprintln(w) 328 fmt.Fprintf(w, "--- PROTOCOL INFO: %s\n", name) 329 fmt.Fprintf(w, "%v\n", proto) 330 fmt.Fprintf(w, "---\n") 331 } 332 return nil 333 } 334 335 func startNode(ctx *cli.Context) error { 336 args := ctx.Args() 337 if len(args) != 1 { 338 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 339 } 340 nodeName := args[0] 341 if err := client.StartNode(nodeName); err != nil { 342 return err 343 } 344 fmt.Fprintln(ctx.App.Writer, "Started", nodeName) 345 return nil 346 } 347 348 func stopNode(ctx *cli.Context) error { 349 args := ctx.Args() 350 if len(args) != 1 { 351 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 352 } 353 nodeName := args[0] 354 if err := client.StopNode(nodeName); err != nil { 355 return err 356 } 357 fmt.Fprintln(ctx.App.Writer, "Stopped", nodeName) 358 return nil 359 } 360 361 func connectNode(ctx *cli.Context) error { 362 args := ctx.Args() 363 if len(args) != 2 { 364 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 365 } 366 nodeName := args[0] 367 peerName := args[1] 368 if err := client.ConnectNode(nodeName, peerName); err != nil { 369 return err 370 } 371 fmt.Fprintln(ctx.App.Writer, "Connected", nodeName, "to", peerName) 372 return nil 373 } 374 375 func disconnectNode(ctx *cli.Context) error { 376 args := ctx.Args() 377 if len(args) != 2 { 378 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 379 } 380 nodeName := args[0] 381 peerName := args[1] 382 if err := client.DisconnectNode(nodeName, peerName); err != nil { 383 return err 384 } 385 fmt.Fprintln(ctx.App.Writer, "Disconnected", nodeName, "from", peerName) 386 return nil 387 } 388 389 func rpcNode(ctx *cli.Context) error { 390 args := ctx.Args() 391 if len(args) < 2 { 392 return cli.ShowCommandHelp(ctx, ctx.Command.Name) 393 } 394 nodeName := args[0] 395 method := args[1] 396 rpcClient, err := client.RPCClient(context.Background(), nodeName) 397 if err != nil { 398 return err 399 } 400 if ctx.Bool("subscribe") { 401 return rpcSubscribe(rpcClient, ctx.App.Writer, method, args[3:]...) 402 } 403 var result interface{} 404 params := make([]interface{}, len(args[3:])) 405 for i, v := range args[3:] { 406 params[i] = v 407 } 408 if err := rpcClient.Call(&result, method, params...); err != nil { 409 return err 410 } 411 return json.NewEncoder(ctx.App.Writer).Encode(result) 412 } 413 414 func rpcSubscribe(client *rpc.Client, out io.Writer, method string, args ...string) error { 415 parts := strings.SplitN(method, "_", 2) 416 namespace := parts[0] 417 method = parts[1] 418 ch := make(chan interface{}) 419 subArgs := make([]interface{}, len(args)+1) 420 subArgs[0] = method 421 for i, v := range args { 422 subArgs[i+1] = v 423 } 424 sub, err := client.Subscribe(context.Background(), namespace, ch, subArgs...) 425 if err != nil { 426 return err 427 } 428 defer sub.Unsubscribe() 429 enc := json.NewEncoder(out) 430 for { 431 select { 432 case v := <-ch: 433 if err := enc.Encode(v); err != nil { 434 return err 435 } 436 case err := <-sub.Err(): 437 return err 438 } 439 } 440 }