github.com/chainopen/ethchaincode@v0.0.0-20190924072703-d975acdaa1c6/p2p/simulations/adapters/types.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  	"crypto/ecdsa"
    21  	"encoding/hex"
    22  	"encoding/json"
    23  	"fmt"
    24  	"net"
    25  	"os"
    26  	"strconv"
    27  
    28  	"github.com/docker/docker/pkg/reexec"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/node"
    32  	"github.com/ethereum/go-ethereum/p2p"
    33  	"github.com/ethereum/go-ethereum/p2p/enode"
    34  	"github.com/ethereum/go-ethereum/p2p/enr"
    35  	"github.com/ethereum/go-ethereum/rpc"
    36  )
    37  
    38  // Node represents a node in a simulation network which is created by a
    39  // NodeAdapter, for example:
    40  //
    41  // * SimNode    - An in-memory node
    42  // * ExecNode   - A child process node
    43  // * DockerNode - A Docker container node
    44  //
    45  type Node interface {
    46  	// Addr returns the node's address (e.g. an Enode URL)
    47  	Addr() []byte
    48  
    49  	// Client returns the RPC client which is created once the node is
    50  	// up and running
    51  	Client() (*rpc.Client, error)
    52  
    53  	// ServeRPC serves RPC requests over the given connection
    54  	ServeRPC(net.Conn) error
    55  
    56  	// Start starts the node with the given snapshots
    57  	Start(snapshots map[string][]byte) error
    58  
    59  	// Stop stops the node
    60  	Stop() error
    61  
    62  	// NodeInfo returns information about the node
    63  	NodeInfo() *p2p.NodeInfo
    64  
    65  	// Snapshots creates snapshots of the running services
    66  	Snapshots() (map[string][]byte, error)
    67  }
    68  
    69  // NodeAdapter is used to create Nodes in a simulation network
    70  type NodeAdapter interface {
    71  	// Name returns the name of the adapter for logging purposes
    72  	Name() string
    73  
    74  	// NewNode creates a new node with the given configuration
    75  	NewNode(config *NodeConfig) (Node, error)
    76  }
    77  
    78  // NodeConfig is the configuration used to start a node in a simulation
    79  // network
    80  type NodeConfig struct {
    81  	// ID is the node's ID which is used to identify the node in the
    82  	// simulation network
    83  	ID enode.ID
    84  
    85  	// PrivateKey is the node's private key which is used by the devp2p
    86  	// stack to encrypt communications
    87  	PrivateKey *ecdsa.PrivateKey
    88  
    89  	// Enable peer events for Msgs
    90  	EnableMsgEvents bool
    91  
    92  	// Name is a human friendly name for the node like "node01"
    93  	Name string
    94  
    95  	// Use an existing database instead of a temporary one if non-empty
    96  	DataDir string
    97  
    98  	// Services are the names of the services which should be run when
    99  	// starting the node (for SimNodes it should be the names of services
   100  	// contained in SimAdapter.services, for other nodes it should be
   101  	// services registered by calling the RegisterService function)
   102  	Services []string
   103  
   104  	// Enode
   105  	node *enode.Node
   106  
   107  	// ENR Record with entries to overwrite
   108  	Record enr.Record
   109  
   110  	// function to sanction or prevent suggesting a peer
   111  	Reachable func(id enode.ID) bool
   112  
   113  	Port uint16
   114  }
   115  
   116  // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding
   117  // all fields as strings
   118  type nodeConfigJSON struct {
   119  	ID              string   `json:"id"`
   120  	PrivateKey      string   `json:"private_key"`
   121  	Name            string   `json:"name"`
   122  	Services        []string `json:"services"`
   123  	EnableMsgEvents bool     `json:"enable_msg_events"`
   124  	Port            uint16   `json:"port"`
   125  }
   126  
   127  // MarshalJSON implements the json.Marshaler interface by encoding the config
   128  // fields as strings
   129  func (n *NodeConfig) MarshalJSON() ([]byte, error) {
   130  	confJSON := nodeConfigJSON{
   131  		ID:              n.ID.String(),
   132  		Name:            n.Name,
   133  		Services:        n.Services,
   134  		Port:            n.Port,
   135  		EnableMsgEvents: n.EnableMsgEvents,
   136  	}
   137  	if n.PrivateKey != nil {
   138  		confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey))
   139  	}
   140  	return json.Marshal(confJSON)
   141  }
   142  
   143  // UnmarshalJSON implements the json.Unmarshaler interface by decoding the json
   144  // string values into the config fields
   145  func (n *NodeConfig) UnmarshalJSON(data []byte) error {
   146  	var confJSON nodeConfigJSON
   147  	if err := json.Unmarshal(data, &confJSON); err != nil {
   148  		return err
   149  	}
   150  
   151  	if confJSON.ID != "" {
   152  		if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil {
   153  			return err
   154  		}
   155  	}
   156  
   157  	if confJSON.PrivateKey != "" {
   158  		key, err := hex.DecodeString(confJSON.PrivateKey)
   159  		if err != nil {
   160  			return err
   161  		}
   162  		privKey, err := crypto.ToECDSA(key)
   163  		if err != nil {
   164  			return err
   165  		}
   166  		n.PrivateKey = privKey
   167  	}
   168  
   169  	n.Name = confJSON.Name
   170  	n.Services = confJSON.Services
   171  	n.Port = confJSON.Port
   172  	n.EnableMsgEvents = confJSON.EnableMsgEvents
   173  
   174  	return nil
   175  }
   176  
   177  // Node returns the node descriptor represented by the config.
   178  func (n *NodeConfig) Node() *enode.Node {
   179  	return n.node
   180  }
   181  
   182  // RandomNodeConfig returns node configuration with a randomly generated ID and
   183  // PrivateKey
   184  func RandomNodeConfig() *NodeConfig {
   185  	prvkey, err := crypto.GenerateKey()
   186  	if err != nil {
   187  		panic("unable to generate key")
   188  	}
   189  
   190  	port, err := assignTCPPort()
   191  	if err != nil {
   192  		panic("unable to assign tcp port")
   193  	}
   194  
   195  	enodId := enode.PubkeyToIDV4(&prvkey.PublicKey)
   196  	return &NodeConfig{
   197  		PrivateKey:      prvkey,
   198  		ID:              enodId,
   199  		Name:            fmt.Sprintf("node_%s", enodId.String()),
   200  		Port:            port,
   201  		EnableMsgEvents: true,
   202  	}
   203  }
   204  
   205  func assignTCPPort() (uint16, error) {
   206  	l, err := net.Listen("tcp", "127.0.0.1:0")
   207  	if err != nil {
   208  		return 0, err
   209  	}
   210  	l.Close()
   211  	_, port, err := net.SplitHostPort(l.Addr().String())
   212  	if err != nil {
   213  		return 0, err
   214  	}
   215  	p, err := strconv.ParseInt(port, 10, 32)
   216  	if err != nil {
   217  		return 0, err
   218  	}
   219  	return uint16(p), nil
   220  }
   221  
   222  // ServiceContext is a collection of options and methods which can be utilised
   223  // when starting services
   224  type ServiceContext struct {
   225  	RPCDialer
   226  
   227  	NodeContext *node.ServiceContext
   228  	Config      *NodeConfig
   229  	Snapshot    []byte
   230  }
   231  
   232  // RPCDialer is used when initialising services which need to connect to
   233  // other nodes in the network (for example a simulated Swarm node which needs
   234  // to connect to a Geth node to resolve ENS names)
   235  type RPCDialer interface {
   236  	DialRPC(id enode.ID) (*rpc.Client, error)
   237  }
   238  
   239  // Services is a collection of services which can be run in a simulation
   240  type Services map[string]ServiceFunc
   241  
   242  // ServiceFunc returns a node.Service which can be used to boot a devp2p node
   243  type ServiceFunc func(ctx *ServiceContext) (node.Service, error)
   244  
   245  // serviceFuncs is a map of registered services which are used to boot devp2p
   246  // nodes
   247  var serviceFuncs = make(Services)
   248  
   249  // RegisterServices registers the given Services which can then be used to
   250  // start devp2p nodes using either the Exec or Docker adapters.
   251  //
   252  // It should be called in an init function so that it has the opportunity to
   253  // execute the services before main() is called.
   254  func RegisterServices(services Services) {
   255  	for name, f := range services {
   256  		if _, exists := serviceFuncs[name]; exists {
   257  			panic(fmt.Sprintf("node service already exists: %q", name))
   258  		}
   259  		serviceFuncs[name] = f
   260  	}
   261  
   262  	// now we have registered the services, run reexec.Init() which will
   263  	// potentially start one of the services if the current binary has
   264  	// been exec'd with argv[0] set to "p2p-node"
   265  	if reexec.Init() {
   266  		os.Exit(0)
   267  	}
   268  }
   269  
   270  // adds the host part to the configuration's ENR, signs it
   271  // creates and  the corresponding enode object to the configuration
   272  func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error {
   273  	enrIp := enr.IP(ip)
   274  	n.Record.Set(&enrIp)
   275  	enrTcpPort := enr.TCP(tcpport)
   276  	n.Record.Set(&enrTcpPort)
   277  	enrUdpPort := enr.UDP(udpport)
   278  	n.Record.Set(&enrUdpPort)
   279  
   280  	err := enode.SignV4(&n.Record, n.PrivateKey)
   281  	if err != nil {
   282  		return fmt.Errorf("unable to generate ENR: %v", err)
   283  	}
   284  	nod, err := enode.New(enode.V4ID{}, &n.Record)
   285  	if err != nil {
   286  		return fmt.Errorf("unable to create enode: %v", err)
   287  	}
   288  	log.Trace("simnode new", "record", n.Record)
   289  	n.node = nod
   290  	return nil
   291  }
   292  
   293  func (n *NodeConfig) initDummyEnode() error {
   294  	return n.initEnode(net.IPv4(127, 0, 0, 1), 0, 0)
   295  }