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