github.com/aquanetwork/aquachain@v1.7.8/p2p/simulations/adapters/inproc.go (about)

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