github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:41</date>
    10  //</624450106694832128>
    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/enode"
    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 enode.ID
    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 enode.ID) 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  		if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil {
   138  			return err
   139  		}
   140  	}
   141  
   142  	if confJSON.PrivateKey != "" {
   143  		key, err := hex.DecodeString(confJSON.PrivateKey)
   144  		if err != nil {
   145  			return err
   146  		}
   147  		privKey, err := crypto.ToECDSA(key)
   148  		if err != nil {
   149  			return err
   150  		}
   151  		n.PrivateKey = privKey
   152  	}
   153  
   154  	n.Name = confJSON.Name
   155  	n.Services = confJSON.Services
   156  	n.Port = confJSON.Port
   157  	n.EnableMsgEvents = confJSON.EnableMsgEvents
   158  
   159  	return nil
   160  }
   161  
   162  //node返回由配置表示的节点描述符。
   163  func (n *NodeConfig) Node() *enode.Node {
   164  	return enode.NewV4(&n.PrivateKey.PublicKey, net.IP{127, 0, 0, 1}, int(n.Port), int(n.Port))
   165  }
   166  
   167  //randomnodeconfig返回具有随机生成的ID和
   168  //私人钥匙
   169  func RandomNodeConfig() *NodeConfig {
   170  	key, err := crypto.GenerateKey()
   171  	if err != nil {
   172  		panic("unable to generate key")
   173  	}
   174  
   175  	id := enode.PubkeyToIDV4(&key.PublicKey)
   176  	port, err := assignTCPPort()
   177  	if err != nil {
   178  		panic("unable to assign tcp port")
   179  	}
   180  	return &NodeConfig{
   181  		ID:              id,
   182  		Name:            fmt.Sprintf("node_%s", id.String()),
   183  		PrivateKey:      key,
   184  		Port:            port,
   185  		EnableMsgEvents: true,
   186  	}
   187  }
   188  
   189  func assignTCPPort() (uint16, error) {
   190  	l, err := net.Listen("tcp", "127.0.0.1:0")
   191  	if err != nil {
   192  		return 0, err
   193  	}
   194  	l.Close()
   195  	_, port, err := net.SplitHostPort(l.Addr().String())
   196  	if err != nil {
   197  		return 0, err
   198  	}
   199  	p, err := strconv.ParseInt(port, 10, 32)
   200  	if err != nil {
   201  		return 0, err
   202  	}
   203  	return uint16(p), nil
   204  }
   205  
   206  //ServiceContext是可以使用的选项和方法的集合
   207  //启动服务时
   208  type ServiceContext struct {
   209  	RPCDialer
   210  
   211  	NodeContext *node.ServiceContext
   212  	Config      *NodeConfig
   213  	Snapshot    []byte
   214  }
   215  
   216  //rpcdialer用于初始化需要连接到的服务
   217  //网络中的其他节点(例如需要
   218  //连接到geth节点以解析ens名称)
   219  type RPCDialer interface {
   220  	DialRPC(id enode.ID) (*rpc.Client, error)
   221  }
   222  
   223  //服务是可以在模拟中运行的服务集合
   224  type Services map[string]ServiceFunc
   225  
   226  //servicefunc返回可用于引导devp2p节点的node.service
   227  type ServiceFunc func(ctx *ServiceContext) (node.Service, error)
   228  
   229  //servicefuncs是用于引导devp2p的已注册服务的映射
   230  //结点
   231  var serviceFuncs = make(Services)
   232  
   233  //RegisterServices注册给定的服务,然后可以使用这些服务
   234  //使用exec或docker适配器启动devp2p节点。
   235  //
   236  //应该在in it函数中调用它,这样它就有机会
   237  //在调用main()之前执行服务。
   238  func RegisterServices(services Services) {
   239  	for name, f := range services {
   240  		if _, exists := serviceFuncs[name]; exists {
   241  			panic(fmt.Sprintf("node service already exists: %q", name))
   242  		}
   243  		serviceFuncs[name] = f
   244  	}
   245  
   246  //现在我们已经注册了服务,运行reexec.init(),它将
   247  //如果当前二进制文件
   248  //已执行,argv[0]设置为“p2p节点”
   249  	if reexec.Init() {
   250  		os.Exit(0)
   251  	}
   252  }
   253