github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/p2p/simulations/network.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 simulations
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/event"
    28  	"github.com/ethereum/go-ethereum/log"
    29  	"github.com/ethereum/go-ethereum/p2p"
    30  	"github.com/ethereum/go-ethereum/p2p/enode"
    31  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    32  )
    33  
    34  var DialBanTimeout = 200 * time.Millisecond
    35  
    36  // NetworkConfig defines configuration options for starting a Network
    37  type NetworkConfig struct {
    38  	ID             string `json:"id"`
    39  	DefaultService string `json:"default_service,omitempty"`
    40  }
    41  
    42  // Network models a p2p simulation network which consists of a collection of
    43  // simulated nodes and the connections which exist between them.
    44  //
    45  // The Network has a single NodeAdapter which is responsible for actually
    46  // starting nodes and connecting them together.
    47  //
    48  // The Network emits events when nodes are started and stopped, when they are
    49  // connected and disconnected, and also when messages are sent between nodes.
    50  type Network struct {
    51  	NetworkConfig
    52  
    53  	Nodes   []*Node `json:"nodes"`
    54  	nodeMap map[enode.ID]int
    55  
    56  	Conns   []*Conn `json:"conns"`
    57  	connMap map[string]int
    58  
    59  	nodeAdapter adapters.NodeAdapter
    60  	events      event.Feed
    61  	lock        sync.RWMutex
    62  	quitc       chan struct{}
    63  }
    64  
    65  // NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig
    66  func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network {
    67  	return &Network{
    68  		NetworkConfig: *conf,
    69  		nodeAdapter:   nodeAdapter,
    70  		nodeMap:       make(map[enode.ID]int),
    71  		connMap:       make(map[string]int),
    72  		quitc:         make(chan struct{}),
    73  	}
    74  }
    75  
    76  // Events returns the output event feed of the Network.
    77  func (net *Network) Events() *event.Feed {
    78  	return &net.events
    79  }
    80  
    81  // NewNodeWithConfig adds a new node to the network with the given config,
    82  // returning an error if a node with the same ID or name already exists
    83  func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) {
    84  	net.lock.Lock()
    85  	defer net.lock.Unlock()
    86  
    87  	if conf.Reachable == nil {
    88  		conf.Reachable = func(otherID enode.ID) bool {
    89  			_, err := net.InitConn(conf.ID, otherID)
    90  			if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 {
    91  				return false
    92  			}
    93  			return true
    94  		}
    95  	}
    96  
    97  	// check the node doesn't already exist
    98  	if node := net.getNode(conf.ID); node != nil {
    99  		return nil, fmt.Errorf("node with ID %q already exists", conf.ID)
   100  	}
   101  	if node := net.getNodeByName(conf.Name); node != nil {
   102  		return nil, fmt.Errorf("node with name %q already exists", conf.Name)
   103  	}
   104  
   105  	// if no services are configured, use the default service
   106  	if len(conf.Services) == 0 {
   107  		conf.Services = []string{net.DefaultService}
   108  	}
   109  
   110  	// use the NodeAdapter to create the node
   111  	adapterNode, err := net.nodeAdapter.NewNode(conf)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	node := &Node{
   116  		Node:   adapterNode,
   117  		Config: conf,
   118  	}
   119  	log.Trace("Node created", "id", conf.ID)
   120  	net.nodeMap[conf.ID] = len(net.Nodes)
   121  	net.Nodes = append(net.Nodes, node)
   122  
   123  	// emit a "control" event
   124  	net.events.Send(ControlEvent(node))
   125  
   126  	return node, nil
   127  }
   128  
   129  // Config returns the network configuration
   130  func (net *Network) Config() *NetworkConfig {
   131  	return &net.NetworkConfig
   132  }
   133  
   134  // StartAll starts all nodes in the network
   135  func (net *Network) StartAll() error {
   136  	for _, node := range net.Nodes {
   137  		if node.Up {
   138  			continue
   139  		}
   140  		if err := net.Start(node.ID()); err != nil {
   141  			return err
   142  		}
   143  	}
   144  	return nil
   145  }
   146  
   147  // StopAll stops all nodes in the network
   148  func (net *Network) StopAll() error {
   149  	for _, node := range net.Nodes {
   150  		if !node.Up {
   151  			continue
   152  		}
   153  		if err := net.Stop(node.ID()); err != nil {
   154  			return err
   155  		}
   156  	}
   157  	return nil
   158  }
   159  
   160  // Start starts the node with the given ID
   161  func (net *Network) Start(id enode.ID) error {
   162  	return net.startWithSnapshots(id, nil)
   163  }
   164  
   165  // startWithSnapshots starts the node with the given ID using the give
   166  // snapshots
   167  func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) error {
   168  	net.lock.Lock()
   169  	defer net.lock.Unlock()
   170  
   171  	node := net.getNode(id)
   172  	if node == nil {
   173  		return fmt.Errorf("node %v does not exist", id)
   174  	}
   175  	if node.Up {
   176  		return fmt.Errorf("node %v already up", id)
   177  	}
   178  	log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name())
   179  	if err := node.Start(snapshots); err != nil {
   180  		log.Warn("Node startup failed", "id", id, "err", err)
   181  		return err
   182  	}
   183  	node.Up = true
   184  	log.Info("Started node", "id", id)
   185  
   186  	net.events.Send(NewEvent(node))
   187  
   188  	// subscribe to peer events
   189  	client, err := node.Client()
   190  	if err != nil {
   191  		return fmt.Errorf("error getting rpc client  for node %v: %s", id, err)
   192  	}
   193  	events := make(chan *p2p.PeerEvent)
   194  	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents")
   195  	if err != nil {
   196  		return fmt.Errorf("error getting peer events for node %v: %s", id, err)
   197  	}
   198  	go net.watchPeerEvents(id, events, sub)
   199  	return nil
   200  }
   201  
   202  // watchPeerEvents reads peer events from the given channel and emits
   203  // corresponding network events
   204  func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub event.Subscription) {
   205  	defer func() {
   206  		sub.Unsubscribe()
   207  
   208  		// assume the node is now down
   209  		net.lock.Lock()
   210  		defer net.lock.Unlock()
   211  		node := net.getNode(id)
   212  		if node == nil {
   213  			return
   214  		}
   215  		node.Up = false
   216  		net.events.Send(NewEvent(node))
   217  	}()
   218  	for {
   219  		select {
   220  		case event, ok := <-events:
   221  			if !ok {
   222  				return
   223  			}
   224  			peer := event.Peer
   225  			switch event.Type {
   226  
   227  			case p2p.PeerEventTypeAdd:
   228  				net.DidConnect(id, peer)
   229  
   230  			case p2p.PeerEventTypeDrop:
   231  				net.DidDisconnect(id, peer)
   232  
   233  			case p2p.PeerEventTypeMsgSend:
   234  				net.DidSend(id, peer, event.Protocol, *event.MsgCode)
   235  
   236  			case p2p.PeerEventTypeMsgRecv:
   237  				net.DidReceive(peer, id, event.Protocol, *event.MsgCode)
   238  
   239  			}
   240  
   241  		case err := <-sub.Err():
   242  			if err != nil {
   243  				log.Error("Error in peer event subscription", "id", id, "err", err)
   244  			}
   245  			return
   246  		}
   247  	}
   248  }
   249  
   250  // Stop stops the node with the given ID
   251  func (net *Network) Stop(id enode.ID) error {
   252  	net.lock.Lock()
   253  	node := net.getNode(id)
   254  	if node == nil {
   255  		return fmt.Errorf("node %v does not exist", id)
   256  	}
   257  	if !node.Up {
   258  		return fmt.Errorf("node %v already down", id)
   259  	}
   260  	node.Up = false
   261  	net.lock.Unlock()
   262  
   263  	err := node.Stop()
   264  	if err != nil {
   265  		net.lock.Lock()
   266  		node.Up = true
   267  		net.lock.Unlock()
   268  		return err
   269  	}
   270  	log.Info("Stopped node", "id", id, "err", err)
   271  	net.events.Send(ControlEvent(node))
   272  	return nil
   273  }
   274  
   275  // Connect connects two nodes together by calling the "admin_addPeer" RPC
   276  // method on the "one" node so that it connects to the "other" node
   277  func (net *Network) Connect(oneID, otherID enode.ID) error {
   278  	log.Debug("Connecting nodes with addPeer", "id", oneID, "other", otherID)
   279  	conn, err := net.InitConn(oneID, otherID)
   280  	if err != nil {
   281  		return err
   282  	}
   283  	client, err := conn.one.Client()
   284  	if err != nil {
   285  		return err
   286  	}
   287  	net.events.Send(ControlEvent(conn))
   288  	return client.Call(nil, "admin_addPeer", string(conn.other.Addr()))
   289  }
   290  
   291  // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC
   292  // method on the "one" node so that it disconnects from the "other" node
   293  func (net *Network) Disconnect(oneID, otherID enode.ID) error {
   294  	conn := net.GetConn(oneID, otherID)
   295  	if conn == nil {
   296  		return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID)
   297  	}
   298  	if !conn.Up {
   299  		return fmt.Errorf("%v and %v already disconnected", oneID, otherID)
   300  	}
   301  	client, err := conn.one.Client()
   302  	if err != nil {
   303  		return err
   304  	}
   305  	net.events.Send(ControlEvent(conn))
   306  	return client.Call(nil, "admin_removePeer", string(conn.other.Addr()))
   307  }
   308  
   309  // DidConnect tracks the fact that the "one" node connected to the "other" node
   310  func (net *Network) DidConnect(one, other enode.ID) error {
   311  	net.lock.Lock()
   312  	defer net.lock.Unlock()
   313  	conn, err := net.getOrCreateConn(one, other)
   314  	if err != nil {
   315  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   316  	}
   317  	if conn.Up {
   318  		return fmt.Errorf("%v and %v already connected", one, other)
   319  	}
   320  	conn.Up = true
   321  	net.events.Send(NewEvent(conn))
   322  	return nil
   323  }
   324  
   325  // DidDisconnect tracks the fact that the "one" node disconnected from the
   326  // "other" node
   327  func (net *Network) DidDisconnect(one, other enode.ID) error {
   328  	net.lock.Lock()
   329  	defer net.lock.Unlock()
   330  	conn := net.getConn(one, other)
   331  	if conn == nil {
   332  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   333  	}
   334  	if !conn.Up {
   335  		return fmt.Errorf("%v and %v already disconnected", one, other)
   336  	}
   337  	conn.Up = false
   338  	conn.initiated = time.Now().Add(-DialBanTimeout)
   339  	net.events.Send(NewEvent(conn))
   340  	return nil
   341  }
   342  
   343  // DidSend tracks the fact that "sender" sent a message to "receiver"
   344  func (net *Network) DidSend(sender, receiver enode.ID, proto string, code uint64) error {
   345  	msg := &Msg{
   346  		One:      sender,
   347  		Other:    receiver,
   348  		Protocol: proto,
   349  		Code:     code,
   350  		Received: false,
   351  	}
   352  	net.events.Send(NewEvent(msg))
   353  	return nil
   354  }
   355  
   356  // DidReceive tracks the fact that "receiver" received a message from "sender"
   357  func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uint64) error {
   358  	msg := &Msg{
   359  		One:      sender,
   360  		Other:    receiver,
   361  		Protocol: proto,
   362  		Code:     code,
   363  		Received: true,
   364  	}
   365  	net.events.Send(NewEvent(msg))
   366  	return nil
   367  }
   368  
   369  // GetNode gets the node with the given ID, returning nil if the node does not
   370  // exist
   371  func (net *Network) GetNode(id enode.ID) *Node {
   372  	net.lock.Lock()
   373  	defer net.lock.Unlock()
   374  	return net.getNode(id)
   375  }
   376  
   377  // GetNode gets the node with the given name, returning nil if the node does
   378  // not exist
   379  func (net *Network) GetNodeByName(name string) *Node {
   380  	net.lock.Lock()
   381  	defer net.lock.Unlock()
   382  	return net.getNodeByName(name)
   383  }
   384  
   385  // GetNodes returns the existing nodes
   386  func (net *Network) GetNodes() (nodes []*Node) {
   387  	net.lock.Lock()
   388  	defer net.lock.Unlock()
   389  
   390  	nodes = append(nodes, net.Nodes...)
   391  	return nodes
   392  }
   393  
   394  func (net *Network) getNode(id enode.ID) *Node {
   395  	i, found := net.nodeMap[id]
   396  	if !found {
   397  		return nil
   398  	}
   399  	return net.Nodes[i]
   400  }
   401  
   402  func (net *Network) getNodeByName(name string) *Node {
   403  	for _, node := range net.Nodes {
   404  		if node.Config.Name == name {
   405  			return node
   406  		}
   407  	}
   408  	return nil
   409  }
   410  
   411  // GetConn returns the connection which exists between "one" and "other"
   412  // regardless of which node initiated the connection
   413  func (net *Network) GetConn(oneID, otherID enode.ID) *Conn {
   414  	net.lock.Lock()
   415  	defer net.lock.Unlock()
   416  	return net.getConn(oneID, otherID)
   417  }
   418  
   419  // GetOrCreateConn is like GetConn but creates the connection if it doesn't
   420  // already exist
   421  func (net *Network) GetOrCreateConn(oneID, otherID enode.ID) (*Conn, error) {
   422  	net.lock.Lock()
   423  	defer net.lock.Unlock()
   424  	return net.getOrCreateConn(oneID, otherID)
   425  }
   426  
   427  func (net *Network) getOrCreateConn(oneID, otherID enode.ID) (*Conn, error) {
   428  	if conn := net.getConn(oneID, otherID); conn != nil {
   429  		return conn, nil
   430  	}
   431  
   432  	one := net.getNode(oneID)
   433  	if one == nil {
   434  		return nil, fmt.Errorf("node %v does not exist", oneID)
   435  	}
   436  	other := net.getNode(otherID)
   437  	if other == nil {
   438  		return nil, fmt.Errorf("node %v does not exist", otherID)
   439  	}
   440  	conn := &Conn{
   441  		One:   oneID,
   442  		Other: otherID,
   443  		one:   one,
   444  		other: other,
   445  	}
   446  	label := ConnLabel(oneID, otherID)
   447  	net.connMap[label] = len(net.Conns)
   448  	net.Conns = append(net.Conns, conn)
   449  	return conn, nil
   450  }
   451  
   452  func (net *Network) getConn(oneID, otherID enode.ID) *Conn {
   453  	label := ConnLabel(oneID, otherID)
   454  	i, found := net.connMap[label]
   455  	if !found {
   456  		return nil
   457  	}
   458  	return net.Conns[i]
   459  }
   460  
   461  // InitConn(one, other) retrieves the connectiton model for the connection between
   462  // peers one and other, or creates a new one if it does not exist
   463  // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i)
   464  // it checks if the connection is already up, and if the nodes are running
   465  // NOTE:
   466  // it also checks whether there has been recent attempt to connect the peers
   467  // this is cheating as the simulation is used as an oracle and know about
   468  // remote peers attempt to connect to a node which will then not initiate the connection
   469  func (net *Network) InitConn(oneID, otherID enode.ID) (*Conn, error) {
   470  	net.lock.Lock()
   471  	defer net.lock.Unlock()
   472  	if oneID == otherID {
   473  		return nil, fmt.Errorf("refusing to connect to self %v", oneID)
   474  	}
   475  	conn, err := net.getOrCreateConn(oneID, otherID)
   476  	if err != nil {
   477  		return nil, err
   478  	}
   479  	if conn.Up {
   480  		return nil, fmt.Errorf("%v and %v already connected", oneID, otherID)
   481  	}
   482  	if time.Since(conn.initiated) < DialBanTimeout {
   483  		return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID)
   484  	}
   485  
   486  	err = conn.nodesUp()
   487  	if err != nil {
   488  		log.Trace("Nodes not up", "err", err)
   489  		return nil, fmt.Errorf("nodes not up: %v", err)
   490  	}
   491  	log.Debug("Connection initiated", "id", oneID, "other", otherID)
   492  	conn.initiated = time.Now()
   493  	return conn, nil
   494  }
   495  
   496  // Shutdown stops all nodes in the network and closes the quit channel
   497  func (net *Network) Shutdown() {
   498  	for _, node := range net.Nodes {
   499  		log.Debug("Stopping node", "id", node.ID())
   500  		if err := node.Stop(); err != nil {
   501  			log.Warn("Can't stop node", "id", node.ID(), "err", err)
   502  		}
   503  	}
   504  	close(net.quitc)
   505  }
   506  
   507  //Reset resets all network properties:
   508  //emtpies the nodes and the connection list
   509  func (net *Network) Reset() {
   510  	net.lock.Lock()
   511  	defer net.lock.Unlock()
   512  
   513  	//re-initialize the maps
   514  	net.connMap = make(map[string]int)
   515  	net.nodeMap = make(map[enode.ID]int)
   516  
   517  	net.Nodes = nil
   518  	net.Conns = nil
   519  }
   520  
   521  // Node is a wrapper around adapters.Node which is used to track the status
   522  // of a node in the network
   523  type Node struct {
   524  	adapters.Node `json:"-"`
   525  
   526  	// Config if the config used to created the node
   527  	Config *adapters.NodeConfig `json:"config"`
   528  
   529  	// Up tracks whether or not the node is running
   530  	Up bool `json:"up"`
   531  }
   532  
   533  // ID returns the ID of the node
   534  func (n *Node) ID() enode.ID {
   535  	return n.Config.ID
   536  }
   537  
   538  // String returns a log-friendly string
   539  func (n *Node) String() string {
   540  	return fmt.Sprintf("Node %v", n.ID().TerminalString())
   541  }
   542  
   543  // NodeInfo returns information about the node
   544  func (n *Node) NodeInfo() *p2p.NodeInfo {
   545  	// avoid a panic if the node is not started yet
   546  	if n.Node == nil {
   547  		return nil
   548  	}
   549  	info := n.Node.NodeInfo()
   550  	info.Name = n.Config.Name
   551  	return info
   552  }
   553  
   554  // MarshalJSON implements the json.Marshaler interface so that the encoded
   555  // JSON includes the NodeInfo
   556  func (n *Node) MarshalJSON() ([]byte, error) {
   557  	return json.Marshal(struct {
   558  		Info   *p2p.NodeInfo        `json:"info,omitempty"`
   559  		Config *adapters.NodeConfig `json:"config,omitempty"`
   560  		Up     bool                 `json:"up"`
   561  	}{
   562  		Info:   n.NodeInfo(),
   563  		Config: n.Config,
   564  		Up:     n.Up,
   565  	})
   566  }
   567  
   568  // Conn represents a connection between two nodes in the network
   569  type Conn struct {
   570  	// One is the node which initiated the connection
   571  	One enode.ID `json:"one"`
   572  
   573  	// Other is the node which the connection was made to
   574  	Other enode.ID `json:"other"`
   575  
   576  	// Up tracks whether or not the connection is active
   577  	Up bool `json:"up"`
   578  	// Registers when the connection was grabbed to dial
   579  	initiated time.Time
   580  
   581  	one   *Node
   582  	other *Node
   583  }
   584  
   585  // nodesUp returns whether both nodes are currently up
   586  func (c *Conn) nodesUp() error {
   587  	if !c.one.Up {
   588  		return fmt.Errorf("one %v is not up", c.One)
   589  	}
   590  	if !c.other.Up {
   591  		return fmt.Errorf("other %v is not up", c.Other)
   592  	}
   593  	return nil
   594  }
   595  
   596  // String returns a log-friendly string
   597  func (c *Conn) String() string {
   598  	return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString())
   599  }
   600  
   601  // Msg represents a p2p message sent between two nodes in the network
   602  type Msg struct {
   603  	One      enode.ID `json:"one"`
   604  	Other    enode.ID `json:"other"`
   605  	Protocol string   `json:"protocol"`
   606  	Code     uint64   `json:"code"`
   607  	Received bool     `json:"received"`
   608  }
   609  
   610  // String returns a log-friendly string
   611  func (m *Msg) String() string {
   612  	return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString())
   613  }
   614  
   615  // ConnLabel generates a deterministic string which represents a connection
   616  // between two nodes, used to compare if two connections are between the same
   617  // nodes
   618  func ConnLabel(source, target enode.ID) string {
   619  	var first, second enode.ID
   620  	if bytes.Compare(source.Bytes(), target.Bytes()) > 0 {
   621  		first = target
   622  		second = source
   623  	} else {
   624  		first = source
   625  		second = target
   626  	}
   627  	return fmt.Sprintf("%v-%v", first, second)
   628  }
   629  
   630  // Snapshot represents the state of a network at a single point in time and can
   631  // be used to restore the state of a network
   632  type Snapshot struct {
   633  	Nodes []NodeSnapshot `json:"nodes,omitempty"`
   634  	Conns []Conn         `json:"conns,omitempty"`
   635  }
   636  
   637  // NodeSnapshot represents the state of a node in the network
   638  type NodeSnapshot struct {
   639  	Node Node `json:"node,omitempty"`
   640  
   641  	// Snapshots is arbitrary data gathered from calling node.Snapshots()
   642  	Snapshots map[string][]byte `json:"snapshots,omitempty"`
   643  }
   644  
   645  // Snapshot creates a network snapshot
   646  func (net *Network) Snapshot() (*Snapshot, error) {
   647  	net.lock.Lock()
   648  	defer net.lock.Unlock()
   649  	snap := &Snapshot{
   650  		Nodes: make([]NodeSnapshot, len(net.Nodes)),
   651  		Conns: make([]Conn, len(net.Conns)),
   652  	}
   653  	for i, node := range net.Nodes {
   654  		snap.Nodes[i] = NodeSnapshot{Node: *node}
   655  		if !node.Up {
   656  			continue
   657  		}
   658  		snapshots, err := node.Snapshots()
   659  		if err != nil {
   660  			return nil, err
   661  		}
   662  		snap.Nodes[i].Snapshots = snapshots
   663  	}
   664  	for i, conn := range net.Conns {
   665  		snap.Conns[i] = *conn
   666  	}
   667  	return snap, nil
   668  }
   669  
   670  // Load loads a network snapshot
   671  func (net *Network) Load(snap *Snapshot) error {
   672  	for _, n := range snap.Nodes {
   673  		if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil {
   674  			return err
   675  		}
   676  		if !n.Node.Up {
   677  			continue
   678  		}
   679  		if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil {
   680  			return err
   681  		}
   682  	}
   683  	for _, conn := range snap.Conns {
   684  
   685  		if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up {
   686  			//in this case, at least one of the nodes of a connection is not up,
   687  			//so it would result in the snapshot `Load` to fail
   688  			continue
   689  		}
   690  		if err := net.Connect(conn.One, conn.Other); err != nil {
   691  			return err
   692  		}
   693  	}
   694  	return nil
   695  }
   696  
   697  // Subscribe reads control events from a channel and executes them
   698  func (net *Network) Subscribe(events chan *Event) {
   699  	for {
   700  		select {
   701  		case event, ok := <-events:
   702  			if !ok {
   703  				return
   704  			}
   705  			if event.Control {
   706  				net.executeControlEvent(event)
   707  			}
   708  		case <-net.quitc:
   709  			return
   710  		}
   711  	}
   712  }
   713  
   714  func (net *Network) executeControlEvent(event *Event) {
   715  	log.Trace("Executing control event", "type", event.Type, "event", event)
   716  	switch event.Type {
   717  	case EventTypeNode:
   718  		if err := net.executeNodeEvent(event); err != nil {
   719  			log.Error("Error executing node event", "event", event, "err", err)
   720  		}
   721  	case EventTypeConn:
   722  		if err := net.executeConnEvent(event); err != nil {
   723  			log.Error("Error executing conn event", "event", event, "err", err)
   724  		}
   725  	case EventTypeMsg:
   726  		log.Warn("Ignoring control msg event")
   727  	}
   728  }
   729  
   730  func (net *Network) executeNodeEvent(e *Event) error {
   731  	if !e.Node.Up {
   732  		return net.Stop(e.Node.ID())
   733  	}
   734  
   735  	if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil {
   736  		return err
   737  	}
   738  	return net.Start(e.Node.ID())
   739  }
   740  
   741  func (net *Network) executeConnEvent(e *Event) error {
   742  	if e.Conn.Up {
   743  		return net.Connect(e.Conn.One, e.Conn.Other)
   744  	} else {
   745  		return net.Disconnect(e.Conn.One, e.Conn.Other)
   746  	}
   747  }