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