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