github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/simulations/adapters/types.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:44</date>
    10  //</624342660869525504>
    11  
    12  
    13  package adapters
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"encoding/hex"
    18  	"encoding/json"
    19  	"fmt"
    20  	"net"
    21  	"os"
    22  	"strconv"
    23  
    24  	"github.com/docker/docker/pkg/reexec"
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/ethereum/go-ethereum/node"
    27  	"github.com/ethereum/go-ethereum/p2p"
    28  	"github.com/ethereum/go-ethereum/p2p/discover"
    29  	"github.com/ethereum/go-ethereum/rpc"
    30  )
    31  
    32  //节点表示模拟网络中由
    33  //节点适配器,例如:
    34  //
    35  //*simnode-内存中的节点
    36  //*execnode-子进程节点
    37  //*DockerNode-Docker容器节点
    38  //
    39  type Node interface {
    40  //addr返回节点的地址(例如e node url)
    41  	Addr() []byte
    42  
    43  //客户端返回在节点
    44  //启动和运行
    45  	Client() (*rpc.Client, error)
    46  
    47  //serverpc通过给定的连接提供RPC请求
    48  	ServeRPC(net.Conn) error
    49  
    50  //Start用给定的快照启动节点
    51  	Start(snapshots map[string][]byte) error
    52  
    53  //停止停止节点
    54  	Stop() error
    55  
    56  //nodeinfo返回有关节点的信息
    57  	NodeInfo() *p2p.NodeInfo
    58  
    59  //快照创建正在运行的服务的快照
    60  	Snapshots() (map[string][]byte, error)
    61  }
    62  
    63  //节点适配器用于在仿真网络中创建节点。
    64  type NodeAdapter interface {
    65  //name返回用于日志记录的适配器的名称
    66  	Name() string
    67  
    68  //new node创建具有给定配置的新节点
    69  	NewNode(config *NodeConfig) (Node, error)
    70  }
    71  
    72  //nodeconfig是用于在模拟中启动节点的配置
    73  //网络
    74  type NodeConfig struct {
    75  //ID是节点的ID,用于标识
    76  //仿真网络
    77  	ID discover.NodeID
    78  
    79  //private key是节点的私钥,由devp2p使用
    80  //用于加密通信的堆栈
    81  	PrivateKey *ecdsa.PrivateKey
    82  
    83  //为MSG启用对等事件
    84  	EnableMsgEvents bool
    85  
    86  //名称是节点的友好名称,如“node01”
    87  	Name string
    88  
    89  //服务是在以下情况下应该运行的服务的名称:
    90  //启动节点(对于Simnodes,它应该是服务的名称
    91  //包含在simadapter.services中,对于其他节点,它应该
    92  //通过调用registerservice函数注册的服务)
    93  	Services []string
    94  
    95  //制裁或阻止建议同伴的职能
    96  	Reachable func(id discover.NodeID) bool
    97  
    98  	Port uint16
    99  }
   100  
   101  //nodeconfig json用于通过编码将nodeconfig编码和解码为json。
   102  //所有字段作为字符串
   103  type nodeConfigJSON struct {
   104  	ID              string   `json:"id"`
   105  	PrivateKey      string   `json:"private_key"`
   106  	Name            string   `json:"name"`
   107  	Services        []string `json:"services"`
   108  	EnableMsgEvents bool     `json:"enable_msg_events"`
   109  	Port            uint16   `json:"port"`
   110  }
   111  
   112  //marshaljson通过编码配置来实现json.marshaler接口
   113  //字段作为字符串
   114  func (n *NodeConfig) MarshalJSON() ([]byte, error) {
   115  	confJSON := nodeConfigJSON{
   116  		ID:              n.ID.String(),
   117  		Name:            n.Name,
   118  		Services:        n.Services,
   119  		Port:            n.Port,
   120  		EnableMsgEvents: n.EnableMsgEvents,
   121  	}
   122  	if n.PrivateKey != nil {
   123  		confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey))
   124  	}
   125  	return json.Marshal(confJSON)
   126  }
   127  
   128  //unmashaljson通过解码json来实现json.unmasheler接口
   129  //在配置字段中字符串值
   130  func (n *NodeConfig) UnmarshalJSON(data []byte) error {
   131  	var confJSON nodeConfigJSON
   132  	if err := json.Unmarshal(data, &confJSON); err != nil {
   133  		return err
   134  	}
   135  
   136  	if confJSON.ID != "" {
   137  		nodeID, err := discover.HexID(confJSON.ID)
   138  		if err != nil {
   139  			return err
   140  		}
   141  		n.ID = nodeID
   142  	}
   143  
   144  	if confJSON.PrivateKey != "" {
   145  		key, err := hex.DecodeString(confJSON.PrivateKey)
   146  		if err != nil {
   147  			return err
   148  		}
   149  		privKey, err := crypto.ToECDSA(key)
   150  		if err != nil {
   151  			return err
   152  		}
   153  		n.PrivateKey = privKey
   154  	}
   155  
   156  	n.Name = confJSON.Name
   157  	n.Services = confJSON.Services
   158  	n.Port = confJSON.Port
   159  	n.EnableMsgEvents = confJSON.EnableMsgEvents
   160  
   161  	return nil
   162  }
   163  
   164  //randomnodeconfig返回具有随机生成的ID和
   165  //私人钥匙
   166  func RandomNodeConfig() *NodeConfig {
   167  	key, err := crypto.GenerateKey()
   168  	if err != nil {
   169  		panic("unable to generate key")
   170  	}
   171  
   172  	id := discover.PubkeyID(&key.PublicKey)
   173  	port, err := assignTCPPort()
   174  	if err != nil {
   175  		panic("unable to assign tcp port")
   176  	}
   177  	return &NodeConfig{
   178  		ID:              id,
   179  		Name:            fmt.Sprintf("node_%s", id.String()),
   180  		PrivateKey:      key,
   181  		Port:            port,
   182  		EnableMsgEvents: true,
   183  	}
   184  }
   185  
   186  func assignTCPPort() (uint16, error) {
   187  	l, err := net.Listen("tcp", "127.0.0.1:0")
   188  	if err != nil {
   189  		return 0, err
   190  	}
   191  	l.Close()
   192  	_, port, err := net.SplitHostPort(l.Addr().String())
   193  	if err != nil {
   194  		return 0, err
   195  	}
   196  	p, err := strconv.ParseInt(port, 10, 32)
   197  	if err != nil {
   198  		return 0, err
   199  	}
   200  	return uint16(p), nil
   201  }
   202  
   203  //ServiceContext是可以使用的选项和方法的集合
   204  //启动服务时
   205  type ServiceContext struct {
   206  	RPCDialer
   207  
   208  	NodeContext *node.ServiceContext
   209  	Config      *NodeConfig
   210  	Snapshot    []byte
   211  }
   212  
   213  //rpcdialer用于初始化需要连接到的服务
   214  //网络中的其他节点(例如需要
   215  //连接到geth节点以解析ens名称)
   216  type RPCDialer interface {
   217  	DialRPC(id discover.NodeID) (*rpc.Client, error)
   218  }
   219  
   220  //服务是可以在模拟中运行的服务集合
   221  type Services map[string]ServiceFunc
   222  
   223  //servicefunc返回可用于引导devp2p节点的node.service
   224  type ServiceFunc func(ctx *ServiceContext) (node.Service, error)
   225  
   226  //servicefuncs是用于引导devp2p的已注册服务的映射
   227  //结点
   228  var serviceFuncs = make(Services)
   229  
   230  //RegisterServices注册给定的服务,然后可以使用这些服务
   231  //使用exec或docker适配器启动devp2p节点。
   232  //
   233  //应该在in it函数中调用它,这样它就有机会
   234  //在调用main()之前执行服务。
   235  func RegisterServices(services Services) {
   236  	for name, f := range services {
   237  		if _, exists := serviceFuncs[name]; exists {
   238  			panic(fmt.Sprintf("node service already exists: %q", name))
   239  		}
   240  		serviceFuncs[name] = f
   241  	}
   242  
   243  //现在我们已经注册了服务,运行reexec.init(),它将
   244  //如果当前二进制文件
   245  //已执行,argv[0]设置为“p2p节点”
   246  	if reexec.Init() {
   247  		os.Exit(0)
   248  	}
   249  }
   250