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  }