| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | // Copyright 2017 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package simulations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/simulations/adapters" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | var DialBanTimeout = 200 * time.Millisecond | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | // NetworkConfig defines configuration options for starting a Network | 
					
						
							|  |  |  | type NetworkConfig struct { | 
					
						
							|  |  |  | 	ID             string `json:"id"` | 
					
						
							|  |  |  | 	DefaultService string `json:"default_service,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Network models a p2p simulation network which consists of a collection of | 
					
						
							|  |  |  | // simulated nodes and the connections which exist between them. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The Network has a single NodeAdapter which is responsible for actually | 
					
						
							|  |  |  | // starting nodes and connecting them together. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The Network emits events when nodes are started and stopped, when they are | 
					
						
							|  |  |  | // connected and disconnected, and also when messages are sent between nodes. | 
					
						
							|  |  |  | type Network struct { | 
					
						
							|  |  |  | 	NetworkConfig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Nodes   []*Node `json:"nodes"` | 
					
						
							|  |  |  | 	nodeMap map[discover.NodeID]int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Conns   []*Conn `json:"conns"` | 
					
						
							|  |  |  | 	connMap map[string]int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nodeAdapter adapters.NodeAdapter | 
					
						
							|  |  |  | 	events      event.Feed | 
					
						
							|  |  |  | 	lock        sync.RWMutex | 
					
						
							|  |  |  | 	quitc       chan struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig | 
					
						
							|  |  |  | func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network { | 
					
						
							|  |  |  | 	return &Network{ | 
					
						
							|  |  |  | 		NetworkConfig: *conf, | 
					
						
							|  |  |  | 		nodeAdapter:   nodeAdapter, | 
					
						
							|  |  |  | 		nodeMap:       make(map[discover.NodeID]int), | 
					
						
							|  |  |  | 		connMap:       make(map[string]int), | 
					
						
							|  |  |  | 		quitc:         make(chan struct{}), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Events returns the output event feed of the Network. | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Events() *event.Feed { | 
					
						
							|  |  |  | 	return &net.events | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewNodeWithConfig adds a new node to the network with the given config, | 
					
						
							|  |  |  | // returning an error if a node with the same ID or name already exists | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	if conf.Reachable == nil { | 
					
						
							|  |  |  | 		conf.Reachable = func(otherID discover.NodeID) bool { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 			_, err := net.InitConn(conf.ID, otherID) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 			if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return true | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// check the node doesn't already exist | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if node := net.getNode(conf.ID); node != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("node with ID %q already exists", conf.ID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	if node := net.getNodeByName(conf.Name); node != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		return nil, fmt.Errorf("node with name %q already exists", conf.Name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if no services are configured, use the default service | 
					
						
							|  |  |  | 	if len(conf.Services) == 0 { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		conf.Services = []string{net.DefaultService} | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// use the NodeAdapter to create the node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	adapterNode, err := net.nodeAdapter.NewNode(conf) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	node := &Node{ | 
					
						
							|  |  |  | 		Node:   adapterNode, | 
					
						
							|  |  |  | 		Config: conf, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	log.Trace(fmt.Sprintf("node %v created", conf.ID)) | 
					
						
							|  |  |  | 	net.nodeMap[conf.ID] = len(net.Nodes) | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.Nodes = append(net.Nodes, node) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// emit a "control" event | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(ControlEvent(node)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Config returns the network configuration | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Config() *NetworkConfig { | 
					
						
							|  |  |  | 	return &net.NetworkConfig | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StartAll starts all nodes in the network | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) StartAll() error { | 
					
						
							|  |  |  | 	for _, node := range net.Nodes { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		if node.Up { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.Start(node.ID()); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StopAll stops all nodes in the network | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) StopAll() error { | 
					
						
							|  |  |  | 	for _, node := range net.Nodes { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		if !node.Up { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.Stop(node.ID()); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Start starts the node with the given ID | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Start(id discover.NodeID) error { | 
					
						
							|  |  |  | 	return net.startWithSnapshots(id, nil) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // startWithSnapshots starts the node with the given ID using the give | 
					
						
							|  |  |  | // snapshots | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) startWithSnapshots(id discover.NodeID, snapshots map[string][]byte) error { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	node := net.getNode(id) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if node == nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("node %v does not exist", id) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if node.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("node %v already up", id) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, net.nodeAdapter.Name())) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if err := node.Start(snapshots); err != nil { | 
					
						
							|  |  |  | 		log.Warn(fmt.Sprintf("start up failed: %v", err)) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	node.Up = true | 
					
						
							|  |  |  | 	log.Info(fmt.Sprintf("started node %v: %v", id, node.Up)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(NewEvent(node)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// subscribe to peer events | 
					
						
							|  |  |  | 	client, err := node.Client() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("error getting rpc client  for node %v: %s", id, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	events := make(chan *p2p.PeerEvent) | 
					
						
							|  |  |  | 	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("error getting peer events for node %v: %s", id, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	go net.watchPeerEvents(id, events, sub) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // watchPeerEvents reads peer events from the given channel and emits | 
					
						
							|  |  |  | // corresponding network events | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEvent, sub event.Subscription) { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		sub.Unsubscribe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// assume the node is now down | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		net.lock.Lock() | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		defer net.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		node := net.getNode(id) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		if node == nil { | 
					
						
							|  |  |  | 			log.Error("Can not find node for id", "id", id) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		node.Up = false | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		net.events.Send(NewEvent(node)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case event, ok := <-events: | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			peer := event.Peer | 
					
						
							|  |  |  | 			switch event.Type { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case p2p.PeerEventTypeAdd: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 				net.DidConnect(id, peer) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			case p2p.PeerEventTypeDrop: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 				net.DidDisconnect(id, peer) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			case p2p.PeerEventTypeMsgSend: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 				net.DidSend(id, peer, event.Protocol, *event.MsgCode) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			case p2p.PeerEventTypeMsgRecv: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 				net.DidReceive(peer, id, event.Protocol, *event.MsgCode) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case err := <-sub.Err(): | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop stops the node with the given ID | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Stop(id discover.NodeID) error { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	node := net.getNode(id) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if node == nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("node %v does not exist", id) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !node.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("node %v already down", id) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := node.Stop(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	node.Up = false | 
					
						
							|  |  |  | 	log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(ControlEvent(node)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Connect connects two nodes together by calling the "admin_addPeer" RPC | 
					
						
							|  |  |  | // method on the "one" node so that it connects to the "other" node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Connect(oneID, otherID discover.NodeID) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	log.Debug(fmt.Sprintf("connecting %s to %s", oneID, otherID)) | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	conn, err := net.InitConn(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	client, err := conn.one.Client() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(ControlEvent(conn)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC | 
					
						
							|  |  |  | // method on the "one" node so that it disconnects from the "other" node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Disconnect(oneID, otherID discover.NodeID) error { | 
					
						
							|  |  |  | 	conn := net.GetConn(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if conn == nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !conn.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("%v and %v already disconnected", oneID, otherID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	client, err := conn.one.Client() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(ControlEvent(conn)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DidConnect tracks the fact that the "one" node connected to the "other" node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) DidConnect(one, other discover.NodeID) error { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	conn, err := net.getOrCreateConn(one, other) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("connection between %v and %v does not exist", one, other) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conn.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("%v and %v already connected", one, other) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	conn.Up = true | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(NewEvent(conn)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DidDisconnect tracks the fact that the "one" node disconnected from the | 
					
						
							|  |  |  | // "other" node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) DidDisconnect(one, other discover.NodeID) error { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	conn := net.getConn(one, other) | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	if conn == nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		return fmt.Errorf("connection between %v and %v does not exist", one, other) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !conn.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("%v and %v already disconnected", one, other) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	conn.Up = false | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	conn.initiated = time.Now().Add(-DialBanTimeout) | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(NewEvent(conn)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DidSend tracks the fact that "sender" sent a message to "receiver" | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) DidSend(sender, receiver discover.NodeID, proto string, code uint64) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	msg := &Msg{ | 
					
						
							|  |  |  | 		One:      sender, | 
					
						
							|  |  |  | 		Other:    receiver, | 
					
						
							|  |  |  | 		Protocol: proto, | 
					
						
							|  |  |  | 		Code:     code, | 
					
						
							|  |  |  | 		Received: false, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(NewEvent(msg)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DidReceive tracks the fact that "receiver" received a message from "sender" | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) DidReceive(sender, receiver discover.NodeID, proto string, code uint64) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	msg := &Msg{ | 
					
						
							|  |  |  | 		One:      sender, | 
					
						
							|  |  |  | 		Other:    receiver, | 
					
						
							|  |  |  | 		Protocol: proto, | 
					
						
							|  |  |  | 		Code:     code, | 
					
						
							|  |  |  | 		Received: true, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.events.Send(NewEvent(msg)) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetNode gets the node with the given ID, returning nil if the node does not | 
					
						
							|  |  |  | // exist | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) GetNode(id discover.NodeID) *Node { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	return net.getNode(id) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetNode gets the node with the given name, returning nil if the node does | 
					
						
							|  |  |  | // not exist | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) GetNodeByName(name string) *Node { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	return net.getNodeByName(name) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-14 11:21:17 +02:00
										 |  |  | // GetNodes returns the existing nodes | 
					
						
							|  |  |  | func (net *Network) GetNodes() (nodes []*Node) { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nodes = append(nodes, net.Nodes...) | 
					
						
							|  |  |  | 	return nodes | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) getNode(id discover.NodeID) *Node { | 
					
						
							|  |  |  | 	i, found := net.nodeMap[id] | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if !found { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	return net.Nodes[i] | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) getNodeByName(name string) *Node { | 
					
						
							|  |  |  | 	for _, node := range net.Nodes { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		if node.Config.Name == name { | 
					
						
							|  |  |  | 			return node | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetConn returns the connection which exists between "one" and "other" | 
					
						
							|  |  |  | // regardless of which node initiated the connection | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) GetConn(oneID, otherID discover.NodeID) *Conn { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	return net.getConn(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetOrCreateConn is like GetConn but creates the connection if it doesn't | 
					
						
							|  |  |  | // already exist | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) GetOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							|  |  |  | 	return net.getOrCreateConn(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) { | 
					
						
							|  |  |  | 	if conn := net.getConn(oneID, otherID); conn != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		return conn, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	one := net.getNode(oneID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if one == nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("node %v does not exist", oneID) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	other := net.getNode(otherID) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if other == nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("node %v does not exist", otherID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	conn := &Conn{ | 
					
						
							|  |  |  | 		One:   oneID, | 
					
						
							|  |  |  | 		Other: otherID, | 
					
						
							|  |  |  | 		one:   one, | 
					
						
							|  |  |  | 		other: other, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	label := ConnLabel(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.connMap[label] = len(net.Conns) | 
					
						
							|  |  |  | 	net.Conns = append(net.Conns, conn) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return conn, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) getConn(oneID, otherID discover.NodeID) *Conn { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	label := ConnLabel(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	i, found := net.connMap[label] | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if !found { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	return net.Conns[i] | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | // InitConn(one, other) retrieves the connectiton model for the connection between | 
					
						
							|  |  |  | // peers one and other, or creates a new one if it does not exist | 
					
						
							|  |  |  | // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) | 
					
						
							|  |  |  | // it checks if the connection is already up, and if the nodes are running | 
					
						
							|  |  |  | // NOTE: | 
					
						
							|  |  |  | // it also checks whether there has been recent attempt to connect the peers | 
					
						
							|  |  |  | // this is cheating as the simulation is used as an oracle and know about | 
					
						
							|  |  |  | // remote peers attempt to connect to a node which will then not initiate the connection | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) InitConn(oneID, otherID discover.NodeID) (*Conn, error) { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	if oneID == otherID { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("refusing to connect to self %v", oneID) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	conn, err := net.getOrCreateConn(oneID, otherID) | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conn.Up { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if time.Since(conn.initiated) < DialBanTimeout { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	err = conn.nodesUp() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		log.Trace(fmt.Sprintf("nodes not up: %v", err)) | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 		return nil, fmt.Errorf("nodes not up: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	log.Debug("InitConn - connection initiated") | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	conn.initiated = time.Now() | 
					
						
							|  |  |  | 	return conn, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | // Shutdown stops all nodes in the network and closes the quit channel | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Shutdown() { | 
					
						
							|  |  |  | 	for _, node := range net.Nodes { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		log.Debug(fmt.Sprintf("stopping node %s", node.ID().TerminalString())) | 
					
						
							|  |  |  | 		if err := node.Stop(); err != nil { | 
					
						
							|  |  |  | 			log.Warn(fmt.Sprintf("error stopping node %s", node.ID().TerminalString()), "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	close(net.quitc) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | //Reset resets all network properties: | 
					
						
							|  |  |  | //emtpies the nodes and the connection list | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Reset() { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	//re-initialize the maps | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.connMap = make(map[string]int) | 
					
						
							|  |  |  | 	net.nodeMap = make(map[discover.NodeID]int) | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	net.Nodes = nil | 
					
						
							|  |  |  | 	net.Conns = nil | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | // Node is a wrapper around adapters.Node which is used to track the status | 
					
						
							|  |  |  | // of a node in the network | 
					
						
							|  |  |  | type Node struct { | 
					
						
							|  |  |  | 	adapters.Node `json:"-"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Config if the config used to created the node | 
					
						
							|  |  |  | 	Config *adapters.NodeConfig `json:"config"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Up tracks whether or not the node is running | 
					
						
							|  |  |  | 	Up bool `json:"up"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ID returns the ID of the node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (n *Node) ID() discover.NodeID { | 
					
						
							|  |  |  | 	return n.Config.ID | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String returns a log-friendly string | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (n *Node) String() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("Node %v", n.ID().TerminalString()) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeInfo returns information about the node | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (n *Node) NodeInfo() *p2p.NodeInfo { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	// avoid a panic if the node is not started yet | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	if n.Node == nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	info := n.Node.NodeInfo() | 
					
						
							|  |  |  | 	info.Name = n.Config.Name | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return info | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MarshalJSON implements the json.Marshaler interface so that the encoded | 
					
						
							|  |  |  | // JSON includes the NodeInfo | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (n *Node) MarshalJSON() ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	return json.Marshal(struct { | 
					
						
							|  |  |  | 		Info   *p2p.NodeInfo        `json:"info,omitempty"` | 
					
						
							|  |  |  | 		Config *adapters.NodeConfig `json:"config,omitempty"` | 
					
						
							|  |  |  | 		Up     bool                 `json:"up"` | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		Info:   n.NodeInfo(), | 
					
						
							|  |  |  | 		Config: n.Config, | 
					
						
							|  |  |  | 		Up:     n.Up, | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conn represents a connection between two nodes in the network | 
					
						
							|  |  |  | type Conn struct { | 
					
						
							|  |  |  | 	// One is the node which initiated the connection | 
					
						
							|  |  |  | 	One discover.NodeID `json:"one"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Other is the node which the connection was made to | 
					
						
							|  |  |  | 	Other discover.NodeID `json:"other"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Up tracks whether or not the connection is active | 
					
						
							|  |  |  | 	Up bool `json:"up"` | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 	// Registers when the connection was grabbed to dial | 
					
						
							|  |  |  | 	initiated time.Time | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	one   *Node | 
					
						
							|  |  |  | 	other *Node | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // nodesUp returns whether both nodes are currently up | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (c *Conn) nodesUp() error { | 
					
						
							|  |  |  | 	if !c.one.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("one %v is not up", c.One) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	if !c.other.Up { | 
					
						
							|  |  |  | 		return fmt.Errorf("other %v is not up", c.Other) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String returns a log-friendly string | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (c *Conn) String() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Msg represents a p2p message sent between two nodes in the network | 
					
						
							|  |  |  | type Msg struct { | 
					
						
							|  |  |  | 	One      discover.NodeID `json:"one"` | 
					
						
							|  |  |  | 	Other    discover.NodeID `json:"other"` | 
					
						
							|  |  |  | 	Protocol string          `json:"protocol"` | 
					
						
							|  |  |  | 	Code     uint64          `json:"code"` | 
					
						
							|  |  |  | 	Received bool            `json:"received"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String returns a log-friendly string | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (m *Msg) String() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ConnLabel generates a deterministic string which represents a connection | 
					
						
							|  |  |  | // between two nodes, used to compare if two connections are between the same | 
					
						
							|  |  |  | // nodes | 
					
						
							|  |  |  | func ConnLabel(source, target discover.NodeID) string { | 
					
						
							|  |  |  | 	var first, second discover.NodeID | 
					
						
							|  |  |  | 	if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { | 
					
						
							|  |  |  | 		first = target | 
					
						
							|  |  |  | 		second = source | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		first = source | 
					
						
							|  |  |  | 		second = target | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Sprintf("%v-%v", first, second) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Snapshot represents the state of a network at a single point in time and can | 
					
						
							|  |  |  | // be used to restore the state of a network | 
					
						
							|  |  |  | type Snapshot struct { | 
					
						
							|  |  |  | 	Nodes []NodeSnapshot `json:"nodes,omitempty"` | 
					
						
							|  |  |  | 	Conns []Conn         `json:"conns,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeSnapshot represents the state of a node in the network | 
					
						
							|  |  |  | type NodeSnapshot struct { | 
					
						
							|  |  |  | 	Node Node `json:"node,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Snapshots is arbitrary data gathered from calling node.Snapshots() | 
					
						
							|  |  |  | 	Snapshots map[string][]byte `json:"snapshots,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Snapshot creates a network snapshot | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Snapshot() (*Snapshot, error) { | 
					
						
							|  |  |  | 	net.lock.Lock() | 
					
						
							|  |  |  | 	defer net.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	snap := &Snapshot{ | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		Nodes: make([]NodeSnapshot, len(net.Nodes)), | 
					
						
							|  |  |  | 		Conns: make([]Conn, len(net.Conns)), | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	for i, node := range net.Nodes { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		snap.Nodes[i] = NodeSnapshot{Node: *node} | 
					
						
							|  |  |  | 		if !node.Up { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		snapshots, err := node.Snapshots() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		snap.Nodes[i].Snapshots = snapshots | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	for i, conn := range net.Conns { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		snap.Conns[i] = *conn | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return snap, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Load loads a network snapshot | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Load(snap *Snapshot) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	for _, n := range snap.Nodes { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !n.Node.Up { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, conn := range snap.Conns { | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up { | 
					
						
							| 
									
										
										
										
											2017-12-12 13:10:41 -05:00
										 |  |  | 			//in this case, at least one of the nodes of a connection is not up, | 
					
						
							|  |  |  | 			//so it would result in the snapshot `Load` to fail | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.Connect(conn.One, conn.Other); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Subscribe reads control events from a channel and executes them | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) Subscribe(events chan *Event) { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case event, ok := <-events: | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if event.Control { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 				net.executeControlEvent(event) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		case <-net.quitc: | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) executeControlEvent(event *Event) { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	log.Trace("execute control event", "type", event.Type, "event", event) | 
					
						
							|  |  |  | 	switch event.Type { | 
					
						
							|  |  |  | 	case EventTypeNode: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.executeNodeEvent(event); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			log.Error("error executing node event", "event", event, "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case EventTypeConn: | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		if err := net.executeConnEvent(event); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 			log.Error("error executing conn event", "event", event, "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case EventTypeMsg: | 
					
						
							|  |  |  | 		log.Warn("ignoring control msg event") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) executeNodeEvent(e *Event) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if !e.Node.Up { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		return net.Stop(e.Node.ID()) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 	return net.Start(e.Node.ID()) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | func (net *Network) executeConnEvent(e *Event) error { | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	if e.Conn.Up { | 
					
						
							| 
									
										
										
										
											2018-05-08 04:08:43 -07:00
										 |  |  | 		return net.Connect(e.Conn.One, e.Conn.Other) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return net.Disconnect(e.Conn.One, e.Conn.Other) | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |