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