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