github.com/gnattishness/bazel-go-ethereum@v0.0.0-20190929123618-7022a154f56d/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 // Enode 105 node *enode.Node 106 107 // ENR Record with entries to overwrite 108 Record enr.Record 109 110 // function to sanction or prevent suggesting a peer 111 Reachable func(id enode.ID) bool 112 113 Port uint16 114 } 115 116 // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding 117 // all fields as strings 118 type nodeConfigJSON struct { 119 ID string `json:"id"` 120 PrivateKey string `json:"private_key"` 121 Name string `json:"name"` 122 Services []string `json:"services"` 123 EnableMsgEvents bool `json:"enable_msg_events"` 124 Port uint16 `json:"port"` 125 } 126 127 // MarshalJSON implements the json.Marshaler interface by encoding the config 128 // fields as strings 129 func (n *NodeConfig) MarshalJSON() ([]byte, error) { 130 confJSON := nodeConfigJSON{ 131 ID: n.ID.String(), 132 Name: n.Name, 133 Services: n.Services, 134 Port: n.Port, 135 EnableMsgEvents: n.EnableMsgEvents, 136 } 137 if n.PrivateKey != nil { 138 confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) 139 } 140 return json.Marshal(confJSON) 141 } 142 143 // UnmarshalJSON implements the json.Unmarshaler interface by decoding the json 144 // string values into the config fields 145 func (n *NodeConfig) UnmarshalJSON(data []byte) error { 146 var confJSON nodeConfigJSON 147 if err := json.Unmarshal(data, &confJSON); err != nil { 148 return err 149 } 150 151 if confJSON.ID != "" { 152 if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil { 153 return err 154 } 155 } 156 157 if confJSON.PrivateKey != "" { 158 key, err := hex.DecodeString(confJSON.PrivateKey) 159 if err != nil { 160 return err 161 } 162 privKey, err := crypto.ToECDSA(key) 163 if err != nil { 164 return err 165 } 166 n.PrivateKey = privKey 167 } 168 169 n.Name = confJSON.Name 170 n.Services = confJSON.Services 171 n.Port = confJSON.Port 172 n.EnableMsgEvents = confJSON.EnableMsgEvents 173 174 return nil 175 } 176 177 // Node returns the node descriptor represented by the config. 178 func (n *NodeConfig) Node() *enode.Node { 179 return n.node 180 } 181 182 // RandomNodeConfig returns node configuration with a randomly generated ID and 183 // PrivateKey 184 func RandomNodeConfig() *NodeConfig { 185 prvkey, err := crypto.GenerateKey() 186 if err != nil { 187 panic("unable to generate key") 188 } 189 190 port, err := assignTCPPort() 191 if err != nil { 192 panic("unable to assign tcp port") 193 } 194 195 enodId := enode.PubkeyToIDV4(&prvkey.PublicKey) 196 return &NodeConfig{ 197 PrivateKey: prvkey, 198 ID: enodId, 199 Name: fmt.Sprintf("node_%s", enodId.String()), 200 Port: port, 201 EnableMsgEvents: true, 202 } 203 } 204 205 func assignTCPPort() (uint16, error) { 206 l, err := net.Listen("tcp", "127.0.0.1:0") 207 if err != nil { 208 return 0, err 209 } 210 l.Close() 211 _, port, err := net.SplitHostPort(l.Addr().String()) 212 if err != nil { 213 return 0, err 214 } 215 p, err := strconv.ParseInt(port, 10, 32) 216 if err != nil { 217 return 0, err 218 } 219 return uint16(p), nil 220 } 221 222 // ServiceContext is a collection of options and methods which can be utilised 223 // when starting services 224 type ServiceContext struct { 225 RPCDialer 226 227 NodeContext *node.ServiceContext 228 Config *NodeConfig 229 Snapshot []byte 230 } 231 232 // RPCDialer is used when initialising services which need to connect to 233 // other nodes in the network (for example a simulated Swarm node which needs 234 // to connect to a Geth node to resolve ENS names) 235 type RPCDialer interface { 236 DialRPC(id enode.ID) (*rpc.Client, error) 237 } 238 239 // Services is a collection of services which can be run in a simulation 240 type Services map[string]ServiceFunc 241 242 // ServiceFunc returns a node.Service which can be used to boot a devp2p node 243 type ServiceFunc func(ctx *ServiceContext) (node.Service, error) 244 245 // serviceFuncs is a map of registered services which are used to boot devp2p 246 // nodes 247 var serviceFuncs = make(Services) 248 249 // RegisterServices registers the given Services which can then be used to 250 // start devp2p nodes using either the Exec or Docker adapters. 251 // 252 // It should be called in an init function so that it has the opportunity to 253 // execute the services before main() is called. 254 func RegisterServices(services Services) { 255 for name, f := range services { 256 if _, exists := serviceFuncs[name]; exists { 257 panic(fmt.Sprintf("node service already exists: %q", name)) 258 } 259 serviceFuncs[name] = f 260 } 261 262 // now we have registered the services, run reexec.Init() which will 263 // potentially start one of the services if the current binary has 264 // been exec'd with argv[0] set to "p2p-node" 265 if reexec.Init() { 266 os.Exit(0) 267 } 268 } 269 270 // adds the host part to the configuration's ENR, signs it 271 // creates and the corresponding enode object to the configuration 272 func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { 273 enrIp := enr.IP(ip) 274 n.Record.Set(&enrIp) 275 enrTcpPort := enr.TCP(tcpport) 276 n.Record.Set(&enrTcpPort) 277 enrUdpPort := enr.UDP(udpport) 278 n.Record.Set(&enrUdpPort) 279 280 err := enode.SignV4(&n.Record, n.PrivateKey) 281 if err != nil { 282 return fmt.Errorf("unable to generate ENR: %v", err) 283 } 284 nod, err := enode.New(enode.V4ID{}, &n.Record) 285 if err != nil { 286 return fmt.Errorf("unable to create enode: %v", err) 287 } 288 log.Trace("simnode new", "record", n.Record) 289 n.node = nod 290 return nil 291 } 292 293 func (n *NodeConfig) initDummyEnode() error { 294 return n.initEnode(net.IPv4(127, 0, 0, 1), 0, 0) 295 }