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