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  }*/