github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/p2p/simulations/adapters/inproc.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum 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 "github.com/neatlab/neatio/chain/log" 27 "github.com/neatlab/neatio/network/node" 28 "github.com/neatlab/neatio/network/p2p" 29 "github.com/neatlab/neatio/network/p2p/discover" 30 "github.com/neatlab/neatio/network/rpc" 31 "github.com/neatlab/neatio/utilities/event" 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 NoUSB: true, 87 Logger: log.New("node.id", id.String()), 88 }) 89 if err != nil { 90 return nil, err 91 } 92 93 simNode := &SimNode{ 94 ID: id, 95 config: config, 96 node: n, 97 adapter: s, 98 running: make(map[string]node.Service), 99 } 100 s.nodes[id] = simNode 101 return simNode, nil 102 } 103 104 // Dial implements the p2p.NodeDialer interface by connecting to the node using 105 // an in-memory net.Pipe connection 106 func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) { 107 node, ok := s.GetNode(dest.ID) 108 if !ok { 109 return nil, fmt.Errorf("unknown node: %s", dest.ID) 110 } 111 srv := node.Server() 112 if srv == nil { 113 return nil, fmt.Errorf("node not running: %s", dest.ID) 114 } 115 pipe1, pipe2 := net.Pipe() 116 go srv.SetupConn(pipe1, 0, nil) 117 return pipe2, nil 118 } 119 120 // DialRPC implements the RPCDialer interface by creating an in-memory RPC 121 // client of the given node 122 func (s *SimAdapter) DialRPC(id discover.NodeID) (*rpc.Client, error) { 123 node, ok := s.GetNode(id) 124 if !ok { 125 return nil, fmt.Errorf("unknown node: %s", id) 126 } 127 handler, err := node.node.RPCHandler() 128 if err != nil { 129 return nil, err 130 } 131 return rpc.DialInProc(handler), nil 132 } 133 134 // GetNode returns the node with the given ID if it exists 135 func (s *SimAdapter) GetNode(id discover.NodeID) (*SimNode, bool) { 136 s.mtx.RLock() 137 defer s.mtx.RUnlock() 138 node, ok := s.nodes[id] 139 return node, ok 140 } 141 142 // SimNode is an in-memory simulation node which connects to other nodes using 143 // an in-memory net.Pipe connection (see SimAdapter.Dial), running devp2p 144 // protocols directly over that pipe 145 type SimNode struct { 146 lock sync.RWMutex 147 ID discover.NodeID 148 config *NodeConfig 149 adapter *SimAdapter 150 node *node.Node 151 running map[string]node.Service 152 client *rpc.Client 153 registerOnce sync.Once 154 } 155 156 // Close closes the underlaying node.Node to release 157 // acquired resources. 158 func (sn *SimNode) Close() error { 159 return sn.node.Close() 160 } 161 162 // Addr returns the node's discovery address 163 func (self *SimNode) Addr() []byte { 164 return []byte(self.Node().String()) 165 } 166 167 // Node returns a discover.Node representing the SimNode 168 func (self *SimNode) Node() *discover.Node { 169 return discover.NewNode(self.ID, net.IP{127, 0, 0, 1}, 30303, 30303) 170 } 171 172 // Client returns an rpc.Client which can be used to communicate with the 173 // underlying services (it is set once the node has started) 174 func (self *SimNode) Client() (*rpc.Client, error) { 175 self.lock.RLock() 176 defer self.lock.RUnlock() 177 if self.client == nil { 178 return nil, errors.New("node not started") 179 } 180 return self.client, nil 181 } 182 183 // ServeRPC serves RPC requests over the given connection by creating an 184 // in-memory client to the node's RPC server 185 func (self *SimNode) ServeRPC(conn net.Conn) error { 186 handler, err := self.node.RPCHandler() 187 if err != nil { 188 return err 189 } 190 handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) 191 return nil 192 } 193 194 // Snapshots creates snapshots of the services by calling the 195 // simulation_snapshot RPC method 196 func (self *SimNode) Snapshots() (map[string][]byte, error) { 197 self.lock.RLock() 198 services := make(map[string]node.Service, len(self.running)) 199 for name, service := range self.running { 200 services[name] = service 201 } 202 self.lock.RUnlock() 203 if len(services) == 0 { 204 return nil, errors.New("no running services") 205 } 206 snapshots := make(map[string][]byte) 207 for name, service := range services { 208 if s, ok := service.(interface { 209 Snapshot() ([]byte, error) 210 }); ok { 211 snap, err := s.Snapshot() 212 if err != nil { 213 return nil, err 214 } 215 snapshots[name] = snap 216 } 217 } 218 return snapshots, nil 219 } 220 221 // Start registers the services and starts the underlying devp2p node 222 func (self *SimNode) Start(snapshots map[string][]byte) error { 223 newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) { 224 return func(nodeCtx *node.ServiceContext) (node.Service, error) { 225 ctx := &ServiceContext{ 226 RPCDialer: self.adapter, 227 NodeContext: nodeCtx, 228 Config: self.config, 229 } 230 if snapshots != nil { 231 ctx.Snapshot = snapshots[name] 232 } 233 serviceFunc := self.adapter.services[name] 234 service, err := serviceFunc(ctx) 235 if err != nil { 236 return nil, err 237 } 238 self.running[name] = service 239 return service, nil 240 } 241 } 242 243 // ensure we only register the services once in the case of the node 244 // being stopped and then started again 245 var regErr error 246 self.registerOnce.Do(func() { 247 for _, name := range self.config.Services { 248 if err := self.node.Register(newService(name)); err != nil { 249 regErr = err 250 return 251 } 252 } 253 }) 254 if regErr != nil { 255 return regErr 256 } 257 258 if err := self.node.Start(); err != nil { 259 return err 260 } 261 262 // create an in-process RPC client 263 handler, err := self.node.RPCHandler() 264 if err != nil { 265 return err 266 } 267 268 self.lock.Lock() 269 self.client = rpc.DialInProc(handler) 270 self.lock.Unlock() 271 272 return nil 273 } 274 275 // Stop closes the RPC client and stops the underlying devp2p node 276 func (self *SimNode) Stop() error { 277 self.lock.Lock() 278 if self.client != nil { 279 self.client.Close() 280 self.client = nil 281 } 282 self.lock.Unlock() 283 return self.node.Stop() 284 } 285 286 // Services returns a copy of the underlying services 287 func (self *SimNode) Services() []node.Service { 288 self.lock.RLock() 289 defer self.lock.RUnlock() 290 services := make([]node.Service, 0, len(self.running)) 291 for _, service := range self.running { 292 services = append(services, service) 293 } 294 return services 295 } 296 297 // Server returns the underlying p2p.Server 298 func (self *SimNode) Server() *p2p.Server { 299 return self.node.Server() 300 } 301 302 // SubscribeEvents subscribes the given channel to peer events from the 303 // underlying p2p.Server 304 func (self *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { 305 srv := self.Server() 306 if srv == nil { 307 panic("node not running") 308 } 309 return srv.SubscribeEvents(ch) 310 } 311 312 // NodeInfo returns information about the node 313 func (self *SimNode) NodeInfo() *p2p.NodeInfo { 314 server := self.Server() 315 if server == nil { 316 return &p2p.NodeInfo{ 317 ID: self.ID.String(), 318 Enode: self.Node().String(), 319 } 320 } 321 return server.NodeInfo() 322 }