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