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