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