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