github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/simulations/adapters/types.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package adapters 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/hex" 22 "encoding/json" 23 "fmt" 24 "net" 25 "os" 26 "strconv" 27 28 "github.com/docker/docker/pkg/reexec" 29 "github.com/gorilla/websocket" 30 "github.com/zhiqiangxu/go-ethereum/crypto" 31 "github.com/zhiqiangxu/go-ethereum/log" 32 "github.com/zhiqiangxu/go-ethereum/node" 33 "github.com/zhiqiangxu/go-ethereum/p2p" 34 "github.com/zhiqiangxu/go-ethereum/p2p/enode" 35 "github.com/zhiqiangxu/go-ethereum/p2p/enr" 36 "github.com/zhiqiangxu/go-ethereum/rpc" 37 ) 38 39 // Node represents a node in a simulation network which is created by a 40 // NodeAdapter, for example: 41 // 42 // * SimNode - An in-memory node 43 // * ExecNode - A child process node 44 // * DockerNode - A Docker container node 45 // 46 type Node interface { 47 // Addr returns the node's address (e.g. an Enode URL) 48 Addr() []byte 49 50 // Client returns the RPC client which is created once the node is 51 // up and running 52 Client() (*rpc.Client, error) 53 54 // ServeRPC serves RPC requests over the given connection 55 ServeRPC(*websocket.Conn) error 56 57 // Start starts the node with the given snapshots 58 Start(snapshots map[string][]byte) error 59 60 // Stop stops the node 61 Stop() error 62 63 // NodeInfo returns information about the node 64 NodeInfo() *p2p.NodeInfo 65 66 // Snapshots creates snapshots of the running services 67 Snapshots() (map[string][]byte, error) 68 } 69 70 // NodeAdapter is used to create Nodes in a simulation network 71 type NodeAdapter interface { 72 // Name returns the name of the adapter for logging purposes 73 Name() string 74 75 // NewNode creates a new node with the given configuration 76 NewNode(config *NodeConfig) (Node, error) 77 } 78 79 // NodeConfig is the configuration used to start a node in a simulation 80 // network 81 type NodeConfig struct { 82 // ID is the node's ID which is used to identify the node in the 83 // simulation network 84 ID enode.ID 85 86 // PrivateKey is the node's private key which is used by the devp2p 87 // stack to encrypt communications 88 PrivateKey *ecdsa.PrivateKey 89 90 // Enable peer events for Msgs 91 EnableMsgEvents bool 92 93 // Name is a human friendly name for the node like "node01" 94 Name string 95 96 // Use an existing database instead of a temporary one if non-empty 97 DataDir string 98 99 // Services are the names of the services which should be run when 100 // starting the node (for SimNodes it should be the names of services 101 // contained in SimAdapter.services, for other nodes it should be 102 // services registered by calling the RegisterService function) 103 Services []string 104 105 // Properties are the names of the properties this node should hold 106 // within running services (e.g. "bootnode", "lightnode" or any custom values) 107 // These values need to be checked and acted upon by node Services 108 Properties []string 109 110 // Enode 111 node *enode.Node 112 113 // ENR Record with entries to overwrite 114 Record enr.Record 115 116 // function to sanction or prevent suggesting a peer 117 Reachable func(id enode.ID) bool 118 119 Port uint16 120 } 121 122 // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding 123 // all fields as strings 124 type nodeConfigJSON struct { 125 ID string `json:"id"` 126 PrivateKey string `json:"private_key"` 127 Name string `json:"name"` 128 Services []string `json:"services"` 129 Properties []string `json:"properties"` 130 EnableMsgEvents bool `json:"enable_msg_events"` 131 Port uint16 `json:"port"` 132 } 133 134 // MarshalJSON implements the json.Marshaler interface by encoding the config 135 // fields as strings 136 func (n *NodeConfig) MarshalJSON() ([]byte, error) { 137 confJSON := nodeConfigJSON{ 138 ID: n.ID.String(), 139 Name: n.Name, 140 Services: n.Services, 141 Properties: n.Properties, 142 Port: n.Port, 143 EnableMsgEvents: n.EnableMsgEvents, 144 } 145 if n.PrivateKey != nil { 146 confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) 147 } 148 return json.Marshal(confJSON) 149 } 150 151 // UnmarshalJSON implements the json.Unmarshaler interface by decoding the json 152 // string values into the config fields 153 func (n *NodeConfig) UnmarshalJSON(data []byte) error { 154 var confJSON nodeConfigJSON 155 if err := json.Unmarshal(data, &confJSON); err != nil { 156 return err 157 } 158 159 if confJSON.ID != "" { 160 if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil { 161 return err 162 } 163 } 164 165 if confJSON.PrivateKey != "" { 166 key, err := hex.DecodeString(confJSON.PrivateKey) 167 if err != nil { 168 return err 169 } 170 privKey, err := crypto.ToECDSA(key) 171 if err != nil { 172 return err 173 } 174 n.PrivateKey = privKey 175 } 176 177 n.Name = confJSON.Name 178 n.Services = confJSON.Services 179 n.Properties = confJSON.Properties 180 n.Port = confJSON.Port 181 n.EnableMsgEvents = confJSON.EnableMsgEvents 182 183 return nil 184 } 185 186 // Node returns the node descriptor represented by the config. 187 func (n *NodeConfig) Node() *enode.Node { 188 return n.node 189 } 190 191 // RandomNodeConfig returns node configuration with a randomly generated ID and 192 // PrivateKey 193 func RandomNodeConfig() *NodeConfig { 194 prvkey, err := crypto.GenerateKey() 195 if err != nil { 196 panic("unable to generate key") 197 } 198 199 port, err := assignTCPPort() 200 if err != nil { 201 panic("unable to assign tcp port") 202 } 203 204 enodId := enode.PubkeyToIDV4(&prvkey.PublicKey) 205 return &NodeConfig{ 206 PrivateKey: prvkey, 207 ID: enodId, 208 Name: fmt.Sprintf("node_%s", enodId.String()), 209 Port: port, 210 EnableMsgEvents: true, 211 } 212 } 213 214 func assignTCPPort() (uint16, error) { 215 l, err := net.Listen("tcp", "127.0.0.1:0") 216 if err != nil { 217 return 0, err 218 } 219 l.Close() 220 _, port, err := net.SplitHostPort(l.Addr().String()) 221 if err != nil { 222 return 0, err 223 } 224 p, err := strconv.ParseInt(port, 10, 32) 225 if err != nil { 226 return 0, err 227 } 228 return uint16(p), nil 229 } 230 231 // ServiceContext is a collection of options and methods which can be utilised 232 // when starting services 233 type ServiceContext struct { 234 RPCDialer 235 236 NodeContext *node.ServiceContext 237 Config *NodeConfig 238 Snapshot []byte 239 } 240 241 // RPCDialer is used when initialising services which need to connect to 242 // other nodes in the network (for example a simulated Swarm node which needs 243 // to connect to a Geth node to resolve ENS names) 244 type RPCDialer interface { 245 DialRPC(id enode.ID) (*rpc.Client, error) 246 } 247 248 // Services is a collection of services which can be run in a simulation 249 type Services map[string]ServiceFunc 250 251 // ServiceFunc returns a node.Service which can be used to boot a devp2p node 252 type ServiceFunc func(ctx *ServiceContext) (node.Service, error) 253 254 // serviceFuncs is a map of registered services which are used to boot devp2p 255 // nodes 256 var serviceFuncs = make(Services) 257 258 // RegisterServices registers the given Services which can then be used to 259 // start devp2p nodes using either the Exec or Docker adapters. 260 // 261 // It should be called in an init function so that it has the opportunity to 262 // execute the services before main() is called. 263 func RegisterServices(services Services) { 264 for name, f := range services { 265 if _, exists := serviceFuncs[name]; exists { 266 panic(fmt.Sprintf("node service already exists: %q", name)) 267 } 268 serviceFuncs[name] = f 269 } 270 271 // now we have registered the services, run reexec.Init() which will 272 // potentially start one of the services if the current binary has 273 // been exec'd with argv[0] set to "p2p-node" 274 if reexec.Init() { 275 os.Exit(0) 276 } 277 } 278 279 // adds the host part to the configuration's ENR, signs it 280 // creates and the corresponding enode object to the configuration 281 func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { 282 enrIp := enr.IP(ip) 283 n.Record.Set(&enrIp) 284 enrTcpPort := enr.TCP(tcpport) 285 n.Record.Set(&enrTcpPort) 286 enrUdpPort := enr.UDP(udpport) 287 n.Record.Set(&enrUdpPort) 288 289 err := enode.SignV4(&n.Record, n.PrivateKey) 290 if err != nil { 291 return fmt.Errorf("unable to generate ENR: %v", err) 292 } 293 nod, err := enode.New(enode.V4ID{}, &n.Record) 294 if err != nil { 295 return fmt.Errorf("unable to create enode: %v", err) 296 } 297 log.Trace("simnode new", "record", n.Record) 298 n.node = nod 299 return nil 300 } 301 302 func (n *NodeConfig) initDummyEnode() error { 303 return n.initEnode(net.IPv4(127, 0, 0, 1), int(n.Port), 0) 304 }