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