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