github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/simulations/adapters/inproc.go (about)

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