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