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