gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/p2p/simulations/adapters/inproc.go (about)

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