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