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