github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/swarm/network/simulation/node.go (about)

     1  // Copyright 2018 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 simulation
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"crypto/ecdsa"
    23  	"encoding/json"
    24  	"errors"
    25  	"io/ioutil"
    26  	"math/rand"
    27  	"os"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  	"github.com/ethereum/go-ethereum/p2p/enode"
    33  	"github.com/ethereum/go-ethereum/p2p/simulations"
    34  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    35  	"github.com/ethereum/go-ethereum/swarm/network"
    36  )
    37  
    38  var (
    39  	BucketKeyBzzPrivateKey BucketKey = "bzzprivkey"
    40  )
    41  
    42  // NodeIDs returns NodeIDs for all nodes in the network.
    43  func (s *Simulation) NodeIDs() (ids []enode.ID) {
    44  	nodes := s.Net.GetNodes()
    45  	ids = make([]enode.ID, len(nodes))
    46  	for i, node := range nodes {
    47  		ids[i] = node.ID()
    48  	}
    49  	return ids
    50  }
    51  
    52  // UpNodeIDs returns NodeIDs for nodes that are up in the network.
    53  func (s *Simulation) UpNodeIDs() (ids []enode.ID) {
    54  	nodes := s.Net.GetNodes()
    55  	for _, node := range nodes {
    56  		if node.Up() {
    57  			ids = append(ids, node.ID())
    58  		}
    59  	}
    60  	return ids
    61  }
    62  
    63  // DownNodeIDs returns NodeIDs for nodes that are stopped in the network.
    64  func (s *Simulation) DownNodeIDs() (ids []enode.ID) {
    65  	nodes := s.Net.GetNodes()
    66  	for _, node := range nodes {
    67  		if !node.Up() {
    68  			ids = append(ids, node.ID())
    69  		}
    70  	}
    71  	return ids
    72  }
    73  
    74  // AddNodeOption defines the option that can be passed
    75  // to Simulation.AddNode method.
    76  type AddNodeOption func(*adapters.NodeConfig)
    77  
    78  // AddNodeWithMsgEvents sets the EnableMsgEvents option
    79  // to NodeConfig.
    80  func AddNodeWithMsgEvents(enable bool) AddNodeOption {
    81  	return func(o *adapters.NodeConfig) {
    82  		o.EnableMsgEvents = enable
    83  	}
    84  }
    85  
    86  // AddNodeWithService specifies a service that should be
    87  // started on a node. This option can be repeated as variadic
    88  // argument toe AddNode and other add node related methods.
    89  // If AddNodeWithService is not specified, all services will be started.
    90  func AddNodeWithService(serviceName string) AddNodeOption {
    91  	return func(o *adapters.NodeConfig) {
    92  		o.Services = append(o.Services, serviceName)
    93  	}
    94  }
    95  
    96  // AddNode creates a new node with random configuration,
    97  // applies provided options to the config and adds the node to network.
    98  // By default all services will be started on a node. If one or more
    99  // AddNodeWithService option are provided, only specified services will be started.
   100  func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) {
   101  	conf := adapters.RandomNodeConfig()
   102  	for _, o := range opts {
   103  		o(conf)
   104  	}
   105  	if len(conf.Services) == 0 {
   106  		conf.Services = s.serviceNames
   107  	}
   108  
   109  	// add ENR records to the underlying node
   110  	// most importantly the bzz overlay address
   111  	//
   112  	// for now we have no way of setting bootnodes or lightnodes in sims
   113  	// so we just let them be set to false
   114  	// they should perhaps be possible to override them with AddNodeOption
   115  	bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf)
   116  	if err != nil {
   117  		return enode.ID{}, err
   118  	}
   119  
   120  	enodeParams := &network.EnodeParams{
   121  		PrivateKey: bzzPrivateKey,
   122  	}
   123  	record, err := network.NewEnodeRecord(enodeParams)
   124  	conf.Record = *record
   125  
   126  	// Add the bzz address to the node config
   127  	node, err := s.Net.NewNodeWithConfig(conf)
   128  	if err != nil {
   129  		return id, err
   130  	}
   131  	s.buckets[node.ID()] = new(sync.Map)
   132  	s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey)
   133  
   134  	return node.ID(), s.Net.Start(node.ID())
   135  }
   136  
   137  // AddNodes creates new nodes with random configurations,
   138  // applies provided options to the config and adds nodes to network.
   139  func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
   140  	ids = make([]enode.ID, 0, count)
   141  	for i := 0; i < count; i++ {
   142  		id, err := s.AddNode(opts...)
   143  		if err != nil {
   144  			return nil, err
   145  		}
   146  		ids = append(ids, id)
   147  	}
   148  	return ids, nil
   149  }
   150  
   151  // AddNodesAndConnectFull is a helpper method that combines
   152  // AddNodes and ConnectNodesFull. Only new nodes will be connected.
   153  func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
   154  	if count < 2 {
   155  		return nil, errors.New("count of nodes must be at least 2")
   156  	}
   157  	ids, err = s.AddNodes(count, opts...)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	err = s.Net.ConnectNodesFull(ids)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	return ids, nil
   166  }
   167  
   168  // AddNodesAndConnectChain is a helpper method that combines
   169  // AddNodes and ConnectNodesChain. The chain will be continued from the last
   170  // added node, if there is one in simulation using ConnectToLastNode method.
   171  func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
   172  	if count < 2 {
   173  		return nil, errors.New("count of nodes must be at least 2")
   174  	}
   175  	id, err := s.AddNode(opts...)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	err = s.Net.ConnectToLastNode(id)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	ids, err = s.AddNodes(count-1, opts...)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	ids = append([]enode.ID{id}, ids...)
   188  	err = s.Net.ConnectNodesChain(ids)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	return ids, nil
   193  }
   194  
   195  // AddNodesAndConnectRing is a helpper method that combines
   196  // AddNodes and ConnectNodesRing.
   197  func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
   198  	if count < 2 {
   199  		return nil, errors.New("count of nodes must be at least 2")
   200  	}
   201  	ids, err = s.AddNodes(count, opts...)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	err = s.Net.ConnectNodesRing(ids)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	return ids, nil
   210  }
   211  
   212  // AddNodesAndConnectStar is a helpper method that combines
   213  // AddNodes and ConnectNodesStar.
   214  func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
   215  	if count < 2 {
   216  		return nil, errors.New("count of nodes must be at least 2")
   217  	}
   218  	ids, err = s.AddNodes(count, opts...)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	err = s.Net.ConnectNodesStar(ids[1:], ids[0])
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	return ids, nil
   227  }
   228  
   229  // UploadSnapshot uploads a snapshot to the simulation
   230  // This method tries to open the json file provided, applies the config to all nodes
   231  // and then loads the snapshot into the Simulation network
   232  func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error {
   233  	f, err := os.Open(snapshotFile)
   234  	if err != nil {
   235  		return err
   236  	}
   237  	defer f.Close()
   238  
   239  	jsonbyte, err := ioutil.ReadAll(f)
   240  	if err != nil {
   241  		return err
   242  	}
   243  	var snap simulations.Snapshot
   244  	if err := json.Unmarshal(jsonbyte, &snap); err != nil {
   245  		return err
   246  	}
   247  
   248  	//the snapshot probably has the property EnableMsgEvents not set
   249  	//set it to true (we need this to wait for messages before uploading)
   250  	for i := range snap.Nodes {
   251  		snap.Nodes[i].Node.Config.EnableMsgEvents = true
   252  		snap.Nodes[i].Node.Config.Services = s.serviceNames
   253  		for _, o := range opts {
   254  			o(snap.Nodes[i].Node.Config)
   255  		}
   256  	}
   257  
   258  	if err := s.Net.Load(&snap); err != nil {
   259  		return err
   260  	}
   261  	return s.WaitTillSnapshotRecreated(ctx, &snap)
   262  }
   263  
   264  // StartNode starts a node by NodeID.
   265  func (s *Simulation) StartNode(id enode.ID) (err error) {
   266  	return s.Net.Start(id)
   267  }
   268  
   269  // StartRandomNode starts a random node.
   270  func (s *Simulation) StartRandomNode() (id enode.ID, err error) {
   271  	n := s.Net.GetRandomDownNode()
   272  	if n == nil {
   273  		return id, ErrNodeNotFound
   274  	}
   275  	return n.ID(), s.Net.Start(n.ID())
   276  }
   277  
   278  // StartRandomNodes starts random nodes.
   279  func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) {
   280  	ids = make([]enode.ID, 0, count)
   281  	for i := 0; i < count; i++ {
   282  		n := s.Net.GetRandomDownNode()
   283  		if n == nil {
   284  			return nil, ErrNodeNotFound
   285  		}
   286  		err = s.Net.Start(n.ID())
   287  		if err != nil {
   288  			return nil, err
   289  		}
   290  		ids = append(ids, n.ID())
   291  	}
   292  	return ids, nil
   293  }
   294  
   295  // StopNode stops a node by NodeID.
   296  func (s *Simulation) StopNode(id enode.ID) (err error) {
   297  	return s.Net.Stop(id)
   298  }
   299  
   300  // StopRandomNode stops a random node.
   301  func (s *Simulation) StopRandomNode() (id enode.ID, err error) {
   302  	n := s.Net.GetRandomUpNode()
   303  	if n == nil {
   304  		return id, ErrNodeNotFound
   305  	}
   306  	return n.ID(), s.Net.Stop(n.ID())
   307  }
   308  
   309  // StopRandomNodes stops random nodes.
   310  func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) {
   311  	ids = make([]enode.ID, 0, count)
   312  	for i := 0; i < count; i++ {
   313  		n := s.Net.GetRandomUpNode()
   314  		if n == nil {
   315  			return nil, ErrNodeNotFound
   316  		}
   317  		err = s.Net.Stop(n.ID())
   318  		if err != nil {
   319  			return nil, err
   320  		}
   321  		ids = append(ids, n.ID())
   322  	}
   323  	return ids, nil
   324  }
   325  
   326  // seed the random generator for Simulation.randomNode.
   327  func init() {
   328  	rand.Seed(time.Now().UnixNano())
   329  }
   330  
   331  // derive a private key for swarm for the node key
   332  // returns the private key used to generate the bzz key
   333  func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) {
   334  	// pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data
   335  	privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...)
   336  	bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf))
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	return bzzPrivateKey, nil
   341  }