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 }