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  }