github.com/csquan/dpos-go-ethereum@v1.9.7/p2p/simulations/adapters/inproc.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 "errors" 21 "fmt" 22 "math" 23 "net" 24 "sync" 25 26 "github.com/ethereum/go-ethereum/event" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/node" 29 "github.com/ethereum/go-ethereum/p2p" 30 "github.com/ethereum/go-ethereum/p2p/enode" 31 "github.com/ethereum/go-ethereum/p2p/simulations/pipes" 32 "github.com/ethereum/go-ethereum/rpc" 33 ) 34 35 // SimAdapter is a NodeAdapter which creates in-memory simulation nodes and 36 // connects them using net.Pipe 37 type SimAdapter struct { 38 pipe func() (net.Conn, net.Conn, error) 39 mtx sync.RWMutex 40 nodes map[enode.ID]*SimNode 41 services map[string]ServiceFunc 42 } 43 44 // NewSimAdapter creates a SimAdapter which is capable of running in-memory 45 // simulation nodes running any of the given services (the services to run on a 46 // particular node are passed to the NewNode function in the NodeConfig) 47 // the adapter uses a net.Pipe for in-memory simulated network connections 48 func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter { 49 return &SimAdapter{ 50 pipe: pipes.NetPipe, 51 nodes: make(map[enode.ID]*SimNode), 52 services: services, 53 } 54 } 55 56 func NewTCPAdapter(services map[string]ServiceFunc) *SimAdapter { 57 return &SimAdapter{ 58 pipe: pipes.TCPPipe, 59 nodes: make(map[enode.ID]*SimNode), 60 services: services, 61 } 62 } 63 64 // Name returns the name of the adapter for logging purposes 65 func (s *SimAdapter) Name() string { 66 return "sim-adapter" 67 } 68 69 // NewNode returns a new SimNode using the given config 70 func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { 71 s.mtx.Lock() 72 defer s.mtx.Unlock() 73 74 id := config.ID 75 // verify that the node has a private key in the config 76 if config.PrivateKey == nil { 77 return nil, fmt.Errorf("node is missing private key: %s", id) 78 } 79 80 // check a node with the ID doesn't already exist 81 if _, exists := s.nodes[id]; exists { 82 return nil, fmt.Errorf("node already exists: %s", id) 83 } 84 85 // check the services are valid 86 if len(config.Services) == 0 { 87 return nil, errors.New("node must have at least one service") 88 } 89 for _, service := range config.Services { 90 if _, exists := s.services[service]; !exists { 91 return nil, fmt.Errorf("unknown node service %q", service) 92 } 93 } 94 95 err := config.initDummyEnode() 96 if err != nil { 97 return nil, err 98 } 99 100 n, err := node.New(&node.Config{ 101 P2P: p2p.Config{ 102 PrivateKey: config.PrivateKey, 103 MaxPeers: math.MaxInt32, 104 NoDiscovery: true, 105 Dialer: s, 106 EnableMsgEvents: config.EnableMsgEvents, 107 }, 108 NoUSB: true, 109 Logger: log.New("node.id", id.String()), 110 }) 111 if err != nil { 112 return nil, err 113 } 114 115 simNode := &SimNode{ 116 ID: id, 117 config: config, 118 node: n, 119 adapter: s, 120 running: make(map[string]node.Service), 121 } 122 s.nodes[id] = simNode 123 return simNode, nil 124 } 125 126 // Dial implements the p2p.NodeDialer interface by connecting to the node using 127 // an in-memory net.Pipe 128 func (s *SimAdapter) Dial(dest *enode.Node) (conn net.Conn, err error) { 129 node, ok := s.GetNode(dest.ID()) 130 if !ok { 131 return nil, fmt.Errorf("unknown node: %s", dest.ID()) 132 } 133 srv := node.Server() 134 if srv == nil { 135 return nil, fmt.Errorf("node not running: %s", dest.ID()) 136 } 137 // SimAdapter.pipe is net.Pipe (NewSimAdapter) 138 pipe1, pipe2, err := s.pipe() 139 if err != nil { 140 return nil, err 141 } 142 // this is simulated 'listening' 143 // asynchronously call the dialed destination node's p2p server 144 // to set up connection on the 'listening' side 145 go srv.SetupConn(pipe1, 0, nil) 146 return pipe2, nil 147 } 148 149 // DialRPC implements the RPCDialer interface by creating an in-memory RPC 150 // client of the given node 151 func (s *SimAdapter) DialRPC(id enode.ID) (*rpc.Client, error) { 152 node, ok := s.GetNode(id) 153 if !ok { 154 return nil, fmt.Errorf("unknown node: %s", id) 155 } 156 handler, err := node.node.RPCHandler() 157 if err != nil { 158 return nil, err 159 } 160 return rpc.DialInProc(handler), nil 161 } 162 163 // GetNode returns the node with the given ID if it exists 164 func (s *SimAdapter) GetNode(id enode.ID) (*SimNode, bool) { 165 s.mtx.RLock() 166 defer s.mtx.RUnlock() 167 node, ok := s.nodes[id] 168 return node, ok 169 } 170 171 // SimNode is an in-memory simulation node which connects to other nodes using 172 // net.Pipe (see SimAdapter.Dial), running devp2p protocols directly over that 173 // pipe 174 type SimNode struct { 175 lock sync.RWMutex 176 ID enode.ID 177 config *NodeConfig 178 adapter *SimAdapter 179 node *node.Node 180 running map[string]node.Service 181 client *rpc.Client 182 registerOnce sync.Once 183 } 184 185 // Close closes the underlaying node.Node to release 186 // acquired resources. 187 func (sn *SimNode) Close() error { 188 return sn.node.Close() 189 } 190 191 // Addr returns the node's discovery address 192 func (sn *SimNode) Addr() []byte { 193 return []byte(sn.Node().String()) 194 } 195 196 // Node returns a node descriptor representing the SimNode 197 func (sn *SimNode) Node() *enode.Node { 198 return sn.config.Node() 199 } 200 201 // Client returns an rpc.Client which can be used to communicate with the 202 // underlying services (it is set once the node has started) 203 func (sn *SimNode) Client() (*rpc.Client, error) { 204 sn.lock.RLock() 205 defer sn.lock.RUnlock() 206 if sn.client == nil { 207 return nil, errors.New("node not started") 208 } 209 return sn.client, nil 210 } 211 212 // ServeRPC serves RPC requests over the given connection by creating an 213 // in-memory client to the node's RPC server 214 func (sn *SimNode) ServeRPC(conn net.Conn) error { 215 handler, err := sn.node.RPCHandler() 216 if err != nil { 217 return err 218 } 219 handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) 220 return nil 221 } 222 223 // Snapshots creates snapshots of the services by calling the 224 // simulation_snapshot RPC method 225 func (sn *SimNode) Snapshots() (map[string][]byte, error) { 226 sn.lock.RLock() 227 services := make(map[string]node.Service, len(sn.running)) 228 for name, service := range sn.running { 229 services[name] = service 230 } 231 sn.lock.RUnlock() 232 if len(services) == 0 { 233 return nil, errors.New("no running services") 234 } 235 snapshots := make(map[string][]byte) 236 for name, service := range services { 237 if s, ok := service.(interface { 238 Snapshot() ([]byte, error) 239 }); ok { 240 snap, err := s.Snapshot() 241 if err != nil { 242 return nil, err 243 } 244 snapshots[name] = snap 245 } 246 } 247 return snapshots, nil 248 } 249 250 // Start registers the services and starts the underlying devp2p node 251 func (sn *SimNode) Start(snapshots map[string][]byte) error { 252 newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) { 253 return func(nodeCtx *node.ServiceContext) (node.Service, error) { 254 ctx := &ServiceContext{ 255 RPCDialer: sn.adapter, 256 NodeContext: nodeCtx, 257 Config: sn.config, 258 } 259 if snapshots != nil { 260 ctx.Snapshot = snapshots[name] 261 } 262 serviceFunc := sn.adapter.services[name] 263 service, err := serviceFunc(ctx) 264 if err != nil { 265 return nil, err 266 } 267 sn.running[name] = service 268 return service, nil 269 } 270 } 271 272 // ensure we only register the services once in the case of the node 273 // being stopped and then started again 274 var regErr error 275 sn.registerOnce.Do(func() { 276 for _, name := range sn.config.Services { 277 if err := sn.node.Register(newService(name)); err != nil { 278 regErr = err 279 break 280 } 281 } 282 }) 283 if regErr != nil { 284 return regErr 285 } 286 287 if err := sn.node.Start(); err != nil { 288 return err 289 } 290 291 // create an in-process RPC client 292 handler, err := sn.node.RPCHandler() 293 if err != nil { 294 return err 295 } 296 297 sn.lock.Lock() 298 sn.client = rpc.DialInProc(handler) 299 sn.lock.Unlock() 300 301 return nil 302 } 303 304 // Stop closes the RPC client and stops the underlying devp2p node 305 func (sn *SimNode) Stop() error { 306 sn.lock.Lock() 307 if sn.client != nil { 308 sn.client.Close() 309 sn.client = nil 310 } 311 sn.lock.Unlock() 312 return sn.node.Stop() 313 } 314 315 // Service returns a running service by name 316 func (sn *SimNode) Service(name string) node.Service { 317 sn.lock.RLock() 318 defer sn.lock.RUnlock() 319 return sn.running[name] 320 } 321 322 // Services returns a copy of the underlying services 323 func (sn *SimNode) Services() []node.Service { 324 sn.lock.RLock() 325 defer sn.lock.RUnlock() 326 services := make([]node.Service, 0, len(sn.running)) 327 for _, service := range sn.running { 328 services = append(services, service) 329 } 330 return services 331 } 332 333 // ServiceMap returns a map by names of the underlying services 334 func (sn *SimNode) ServiceMap() map[string]node.Service { 335 sn.lock.RLock() 336 defer sn.lock.RUnlock() 337 services := make(map[string]node.Service, len(sn.running)) 338 for name, service := range sn.running { 339 services[name] = service 340 } 341 return services 342 } 343 344 // Server returns the underlying p2p.Server 345 func (sn *SimNode) Server() *p2p.Server { 346 return sn.node.Server() 347 } 348 349 // SubscribeEvents subscribes the given channel to peer events from the 350 // underlying p2p.Server 351 func (sn *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { 352 srv := sn.Server() 353 if srv == nil { 354 panic("node not running") 355 } 356 return srv.SubscribeEvents(ch) 357 } 358 359 // NodeInfo returns information about the node 360 func (sn *SimNode) NodeInfo() *p2p.NodeInfo { 361 server := sn.Server() 362 if server == nil { 363 return &p2p.NodeInfo{ 364 ID: sn.ID.String(), 365 Enode: sn.Node().String(), 366 } 367 } 368 return server.NodeInfo() 369 }