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