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