github.com/luckypickle/go-ethereum-vet@v1.14.2/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/luckypickle/go-ethereum-vet/event"
    28  	"github.com/luckypickle/go-ethereum-vet/log"
    29  	"github.com/luckypickle/go-ethereum-vet/p2p"
    30  	"github.com/luckypickle/go-ethereum-vet/p2p/discover"
    31  	"github.com/luckypickle/go-ethereum-vet/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[discover.NodeID]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[discover.NodeID]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 discover.NodeID) 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(fmt.Sprintf("node %v created", 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 discover.NodeID) 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 discover.NodeID, snapshots map[string][]byte) error {
   168  	net.lock.Lock()
   169  	defer net.lock.Unlock()
   170  	node := net.getNode(id)
   171  	if node == nil {
   172  		return fmt.Errorf("node %v does not exist", id)
   173  	}
   174  	if node.Up {
   175  		return fmt.Errorf("node %v already up", id)
   176  	}
   177  	log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, net.nodeAdapter.Name()))
   178  	if err := node.Start(snapshots); err != nil {
   179  		log.Warn(fmt.Sprintf("start up failed: %v", err))
   180  		return err
   181  	}
   182  	node.Up = true
   183  	log.Info(fmt.Sprintf("started node %v: %v", id, node.Up))
   184  
   185  	net.events.Send(NewEvent(node))
   186  
   187  	// subscribe to peer events
   188  	client, err := node.Client()
   189  	if err != nil {
   190  		return fmt.Errorf("error getting rpc client  for node %v: %s", id, err)
   191  	}
   192  	events := make(chan *p2p.PeerEvent)
   193  	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents")
   194  	if err != nil {
   195  		return fmt.Errorf("error getting peer events for node %v: %s", id, err)
   196  	}
   197  	go net.watchPeerEvents(id, events, sub)
   198  	return nil
   199  }
   200  
   201  // watchPeerEvents reads peer events from the given channel and emits
   202  // corresponding network events
   203  func (net *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEvent, sub event.Subscription) {
   204  	defer func() {
   205  		sub.Unsubscribe()
   206  
   207  		// assume the node is now down
   208  		net.lock.Lock()
   209  		defer net.lock.Unlock()
   210  		node := net.getNode(id)
   211  		if node == nil {
   212  			log.Error("Can not find node for id", "id", id)
   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(fmt.Sprintf("error getting peer events for node %v", 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 discover.NodeID) error {
   252  	net.lock.Lock()
   253  	defer net.lock.Unlock()
   254  	node := net.getNode(id)
   255  	if node == nil {
   256  		return fmt.Errorf("node %v does not exist", id)
   257  	}
   258  	if !node.Up {
   259  		return fmt.Errorf("node %v already down", id)
   260  	}
   261  	if err := node.Stop(); err != nil {
   262  		return err
   263  	}
   264  	node.Up = false
   265  	log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up))
   266  
   267  	net.events.Send(ControlEvent(node))
   268  	return nil
   269  }
   270  
   271  // Connect connects two nodes together by calling the "admin_addPeer" RPC
   272  // method on the "one" node so that it connects to the "other" node
   273  func (net *Network) Connect(oneID, otherID discover.NodeID) error {
   274  	log.Debug(fmt.Sprintf("connecting %s to %s", oneID, otherID))
   275  	conn, err := net.InitConn(oneID, otherID)
   276  	if err != nil {
   277  		return err
   278  	}
   279  	client, err := conn.one.Client()
   280  	if err != nil {
   281  		return err
   282  	}
   283  	net.events.Send(ControlEvent(conn))
   284  	return client.Call(nil, "admin_addPeer", string(conn.other.Addr()))
   285  }
   286  
   287  // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC
   288  // method on the "one" node so that it disconnects from the "other" node
   289  func (net *Network) Disconnect(oneID, otherID discover.NodeID) error {
   290  	conn := net.GetConn(oneID, otherID)
   291  	if conn == nil {
   292  		return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID)
   293  	}
   294  	if !conn.Up {
   295  		return fmt.Errorf("%v and %v already disconnected", oneID, otherID)
   296  	}
   297  	client, err := conn.one.Client()
   298  	if err != nil {
   299  		return err
   300  	}
   301  	net.events.Send(ControlEvent(conn))
   302  	return client.Call(nil, "admin_removePeer", string(conn.other.Addr()))
   303  }
   304  
   305  // DidConnect tracks the fact that the "one" node connected to the "other" node
   306  func (net *Network) DidConnect(one, other discover.NodeID) error {
   307  	net.lock.Lock()
   308  	defer net.lock.Unlock()
   309  	conn, err := net.getOrCreateConn(one, other)
   310  	if err != nil {
   311  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   312  	}
   313  	if conn.Up {
   314  		return fmt.Errorf("%v and %v already connected", one, other)
   315  	}
   316  	conn.Up = true
   317  	net.events.Send(NewEvent(conn))
   318  	return nil
   319  }
   320  
   321  // DidDisconnect tracks the fact that the "one" node disconnected from the
   322  // "other" node
   323  func (net *Network) DidDisconnect(one, other discover.NodeID) error {
   324  	net.lock.Lock()
   325  	defer net.lock.Unlock()
   326  	conn := net.getConn(one, other)
   327  	if conn == nil {
   328  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   329  	}
   330  	if !conn.Up {
   331  		return fmt.Errorf("%v and %v already disconnected", one, other)
   332  	}
   333  	conn.Up = false
   334  	conn.initiated = time.Now().Add(-DialBanTimeout)
   335  	net.events.Send(NewEvent(conn))
   336  	return nil
   337  }
   338  
   339  // DidSend tracks the fact that "sender" sent a message to "receiver"
   340  func (net *Network) DidSend(sender, receiver discover.NodeID, proto string, code uint64) error {
   341  	msg := &Msg{
   342  		One:      sender,
   343  		Other:    receiver,
   344  		Protocol: proto,
   345  		Code:     code,
   346  		Received: false,
   347  	}
   348  	net.events.Send(NewEvent(msg))
   349  	return nil
   350  }
   351  
   352  // DidReceive tracks the fact that "receiver" received a message from "sender"
   353  func (net *Network) DidReceive(sender, receiver discover.NodeID, proto string, code uint64) error {
   354  	msg := &Msg{
   355  		One:      sender,
   356  		Other:    receiver,
   357  		Protocol: proto,
   358  		Code:     code,
   359  		Received: true,
   360  	}
   361  	net.events.Send(NewEvent(msg))
   362  	return nil
   363  }
   364  
   365  // GetNode gets the node with the given ID, returning nil if the node does not
   366  // exist
   367  func (net *Network) GetNode(id discover.NodeID) *Node {
   368  	net.lock.Lock()
   369  	defer net.lock.Unlock()
   370  	return net.getNode(id)
   371  }
   372  
   373  // GetNode gets the node with the given name, returning nil if the node does
   374  // not exist
   375  func (net *Network) GetNodeByName(name string) *Node {
   376  	net.lock.Lock()
   377  	defer net.lock.Unlock()
   378  	return net.getNodeByName(name)
   379  }
   380  
   381  // GetNodes returns the existing nodes
   382  func (net *Network) GetNodes() (nodes []*Node) {
   383  	net.lock.Lock()
   384  	defer net.lock.Unlock()
   385  
   386  	nodes = append(nodes, net.Nodes...)
   387  	return nodes
   388  }
   389  
   390  func (net *Network) getNode(id discover.NodeID) *Node {
   391  	i, found := net.nodeMap[id]
   392  	if !found {
   393  		return nil
   394  	}
   395  	return net.Nodes[i]
   396  }
   397  
   398  func (net *Network) getNodeByName(name string) *Node {
   399  	for _, node := range net.Nodes {
   400  		if node.Config.Name == name {
   401  			return node
   402  		}
   403  	}
   404  	return nil
   405  }
   406  
   407  // GetConn returns the connection which exists between "one" and "other"
   408  // regardless of which node initiated the connection
   409  func (net *Network) GetConn(oneID, otherID discover.NodeID) *Conn {
   410  	net.lock.Lock()
   411  	defer net.lock.Unlock()
   412  	return net.getConn(oneID, otherID)
   413  }
   414  
   415  // GetOrCreateConn is like GetConn but creates the connection if it doesn't
   416  // already exist
   417  func (net *Network) GetOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) {
   418  	net.lock.Lock()
   419  	defer net.lock.Unlock()
   420  	return net.getOrCreateConn(oneID, otherID)
   421  }
   422  
   423  func (net *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) {
   424  	if conn := net.getConn(oneID, otherID); conn != nil {
   425  		return conn, nil
   426  	}
   427  
   428  	one := net.getNode(oneID)
   429  	if one == nil {
   430  		return nil, fmt.Errorf("node %v does not exist", oneID)
   431  	}
   432  	other := net.getNode(otherID)
   433  	if other == nil {
   434  		return nil, fmt.Errorf("node %v does not exist", otherID)
   435  	}
   436  	conn := &Conn{
   437  		One:   oneID,
   438  		Other: otherID,
   439  		one:   one,
   440  		other: other,
   441  	}
   442  	label := ConnLabel(oneID, otherID)
   443  	net.connMap[label] = len(net.Conns)
   444  	net.Conns = append(net.Conns, conn)
   445  	return conn, nil
   446  }
   447  
   448  func (net *Network) getConn(oneID, otherID discover.NodeID) *Conn {
   449  	label := ConnLabel(oneID, otherID)
   450  	i, found := net.connMap[label]
   451  	if !found {
   452  		return nil
   453  	}
   454  	return net.Conns[i]
   455  }
   456  
   457  // InitConn(one, other) retrieves the connectiton model for the connection between
   458  // peers one and other, or creates a new one if it does not exist
   459  // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i)
   460  // it checks if the connection is already up, and if the nodes are running
   461  // NOTE:
   462  // it also checks whether there has been recent attempt to connect the peers
   463  // this is cheating as the simulation is used as an oracle and know about
   464  // remote peers attempt to connect to a node which will then not initiate the connection
   465  func (net *Network) InitConn(oneID, otherID discover.NodeID) (*Conn, error) {
   466  	net.lock.Lock()
   467  	defer net.lock.Unlock()
   468  	if oneID == otherID {
   469  		return nil, fmt.Errorf("refusing to connect to self %v", oneID)
   470  	}
   471  	conn, err := net.getOrCreateConn(oneID, otherID)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	if conn.Up {
   476  		return nil, fmt.Errorf("%v and %v already connected", oneID, otherID)
   477  	}
   478  	if time.Since(conn.initiated) < DialBanTimeout {
   479  		return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID)
   480  	}
   481  
   482  	err = conn.nodesUp()
   483  	if err != nil {
   484  		log.Trace(fmt.Sprintf("nodes not up: %v", err))
   485  		return nil, fmt.Errorf("nodes not up: %v", err)
   486  	}
   487  	log.Debug("InitConn - connection initiated")
   488  	conn.initiated = time.Now()
   489  	return conn, nil
   490  }
   491  
   492  // Shutdown stops all nodes in the network and closes the quit channel
   493  func (net *Network) Shutdown() {
   494  	for _, node := range net.Nodes {
   495  		log.Debug(fmt.Sprintf("stopping node %s", node.ID().TerminalString()))
   496  		if err := node.Stop(); err != nil {
   497  			log.Warn(fmt.Sprintf("error stopping node %s", node.ID().TerminalString()), "err", err)
   498  		}
   499  	}
   500  	close(net.quitc)
   501  }
   502  
   503  // Reset resets all network properties:
   504  // emtpies the nodes and the connection list
   505  func (net *Network) Reset() {
   506  	net.lock.Lock()
   507  	defer net.lock.Unlock()
   508  
   509  	//re-initialize the maps
   510  	net.connMap = make(map[string]int)
   511  	net.nodeMap = make(map[discover.NodeID]int)
   512  
   513  	net.Nodes = nil
   514  	net.Conns = nil
   515  }
   516  
   517  // Node is a wrapper around adapters.Node which is used to track the status
   518  // of a node in the network
   519  type Node struct {
   520  	adapters.Node `json:"-"`
   521  
   522  	// Config if the config used to created the node
   523  	Config *adapters.NodeConfig `json:"config"`
   524  
   525  	// Up tracks whether or not the node is running
   526  	Up bool `json:"up"`
   527  }
   528  
   529  // ID returns the ID of the node
   530  func (n *Node) ID() discover.NodeID {
   531  	return n.Config.ID
   532  }
   533  
   534  // String returns a log-friendly string
   535  func (n *Node) String() string {
   536  	return fmt.Sprintf("Node %v", n.ID().TerminalString())
   537  }
   538  
   539  // NodeInfo returns information about the node
   540  func (n *Node) NodeInfo() *p2p.NodeInfo {
   541  	// avoid a panic if the node is not started yet
   542  	if n.Node == nil {
   543  		return nil
   544  	}
   545  	info := n.Node.NodeInfo()
   546  	info.Name = n.Config.Name
   547  	return info
   548  }
   549  
   550  // MarshalJSON implements the json.Marshaler interface so that the encoded
   551  // JSON includes the NodeInfo
   552  func (n *Node) MarshalJSON() ([]byte, error) {
   553  	return json.Marshal(struct {
   554  		Info   *p2p.NodeInfo        `json:"info,omitempty"`
   555  		Config *adapters.NodeConfig `json:"config,omitempty"`
   556  		Up     bool                 `json:"up"`
   557  	}{
   558  		Info:   n.NodeInfo(),
   559  		Config: n.Config,
   560  		Up:     n.Up,
   561  	})
   562  }
   563  
   564  // Conn represents a connection between two nodes in the network
   565  type Conn struct {
   566  	// One is the node which initiated the connection
   567  	One discover.NodeID `json:"one"`
   568  
   569  	// Other is the node which the connection was made to
   570  	Other discover.NodeID `json:"other"`
   571  
   572  	// Up tracks whether or not the connection is active
   573  	Up bool `json:"up"`
   574  	// Registers when the connection was grabbed to dial
   575  	initiated time.Time
   576  
   577  	one   *Node
   578  	other *Node
   579  }
   580  
   581  // nodesUp returns whether both nodes are currently up
   582  func (c *Conn) nodesUp() error {
   583  	if !c.one.Up {
   584  		return fmt.Errorf("one %v is not up", c.One)
   585  	}
   586  	if !c.other.Up {
   587  		return fmt.Errorf("other %v is not up", c.Other)
   588  	}
   589  	return nil
   590  }
   591  
   592  // String returns a log-friendly string
   593  func (c *Conn) String() string {
   594  	return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString())
   595  }
   596  
   597  // Msg represents a p2p message sent between two nodes in the network
   598  type Msg struct {
   599  	One      discover.NodeID `json:"one"`
   600  	Other    discover.NodeID `json:"other"`
   601  	Protocol string          `json:"protocol"`
   602  	Code     uint64          `json:"code"`
   603  	Received bool            `json:"received"`
   604  }
   605  
   606  // String returns a log-friendly string
   607  func (m *Msg) String() string {
   608  	return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString())
   609  }
   610  
   611  // ConnLabel generates a deterministic string which represents a connection
   612  // between two nodes, used to compare if two connections are between the same
   613  // nodes
   614  func ConnLabel(source, target discover.NodeID) string {
   615  	var first, second discover.NodeID
   616  	if bytes.Compare(source.Bytes(), target.Bytes()) > 0 {
   617  		first = target
   618  		second = source
   619  	} else {
   620  		first = source
   621  		second = target
   622  	}
   623  	return fmt.Sprintf("%v-%v", first, second)
   624  }
   625  
   626  // Snapshot represents the state of a network at a single point in time and can
   627  // be used to restore the state of a network
   628  type Snapshot struct {
   629  	Nodes []NodeSnapshot `json:"nodes,omitempty"`
   630  	Conns []Conn         `json:"conns,omitempty"`
   631  }
   632  
   633  // NodeSnapshot represents the state of a node in the network
   634  type NodeSnapshot struct {
   635  	Node Node `json:"node,omitempty"`
   636  
   637  	// Snapshots is arbitrary data gathered from calling node.Snapshots()
   638  	Snapshots map[string][]byte `json:"snapshots,omitempty"`
   639  }
   640  
   641  // Snapshot creates a network snapshot
   642  func (net *Network) Snapshot() (*Snapshot, error) {
   643  	net.lock.Lock()
   644  	defer net.lock.Unlock()
   645  	snap := &Snapshot{
   646  		Nodes: make([]NodeSnapshot, len(net.Nodes)),
   647  		Conns: make([]Conn, len(net.Conns)),
   648  	}
   649  	for i, node := range net.Nodes {
   650  		snap.Nodes[i] = NodeSnapshot{Node: *node}
   651  		if !node.Up {
   652  			continue
   653  		}
   654  		snapshots, err := node.Snapshots()
   655  		if err != nil {
   656  			return nil, err
   657  		}
   658  		snap.Nodes[i].Snapshots = snapshots
   659  	}
   660  	for i, conn := range net.Conns {
   661  		snap.Conns[i] = *conn
   662  	}
   663  	return snap, nil
   664  }
   665  
   666  // Load loads a network snapshot
   667  func (net *Network) Load(snap *Snapshot) error {
   668  	for _, n := range snap.Nodes {
   669  		if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil {
   670  			return err
   671  		}
   672  		if !n.Node.Up {
   673  			continue
   674  		}
   675  		if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil {
   676  			return err
   677  		}
   678  	}
   679  	for _, conn := range snap.Conns {
   680  
   681  		if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up {
   682  			//in this case, at least one of the nodes of a connection is not up,
   683  			//so it would result in the snapshot `Load` to fail
   684  			continue
   685  		}
   686  		if err := net.Connect(conn.One, conn.Other); err != nil {
   687  			return err
   688  		}
   689  	}
   690  	return nil
   691  }
   692  
   693  // Subscribe reads control events from a channel and executes them
   694  func (net *Network) Subscribe(events chan *Event) {
   695  	for {
   696  		select {
   697  		case event, ok := <-events:
   698  			if !ok {
   699  				return
   700  			}
   701  			if event.Control {
   702  				net.executeControlEvent(event)
   703  			}
   704  		case <-net.quitc:
   705  			return
   706  		}
   707  	}
   708  }
   709  
   710  func (net *Network) executeControlEvent(event *Event) {
   711  	log.Trace("execute control event", "type", event.Type, "event", event)
   712  	switch event.Type {
   713  	case EventTypeNode:
   714  		if err := net.executeNodeEvent(event); err != nil {
   715  			log.Error("error executing node event", "event", event, "err", err)
   716  		}
   717  	case EventTypeConn:
   718  		if err := net.executeConnEvent(event); err != nil {
   719  			log.Error("error executing conn event", "event", event, "err", err)
   720  		}
   721  	case EventTypeMsg:
   722  		log.Warn("ignoring control msg event")
   723  	}
   724  }
   725  
   726  func (net *Network) executeNodeEvent(e *Event) error {
   727  	if !e.Node.Up {
   728  		return net.Stop(e.Node.ID())
   729  	}
   730  
   731  	if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil {
   732  		return err
   733  	}
   734  	return net.Start(e.Node.ID())
   735  }
   736  
   737  func (net *Network) executeConnEvent(e *Event) error {
   738  	if e.Conn.Up {
   739  		return net.Connect(e.Conn.One, e.Conn.Other)
   740  	} else {
   741  		return net.Disconnect(e.Conn.One, e.Conn.Other)
   742  	}
   743  }