From 09b65037957df851400ba626a9892b8645a853ea Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Fri, 12 Feb 2016 09:52:32 +0100
Subject: [PATCH 01/45] Discovery packets

---
 util/src/network/connection.rs |   5 +
 util/src/network/discovery.rs  | 201 ++++++++++++++++++++++++++-------
 util/src/network/error.rs      |   7 ++
 util/src/network/handshake.rs  |  10 ++
 util/src/network/host.rs       |  98 ++++++++++------
 util/src/network/mod.rs        |   1 +
 util/src/network/node_table.rs |  52 +++++++++
 util/src/network/session.rs    |   5 +
 8 files changed, 303 insertions(+), 76 deletions(-)
 create mode 100644 util/src/network/node_table.rs

diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs
index 746c745c4..44d429164 100644
--- a/util/src/network/connection.rs
+++ b/util/src/network/connection.rs
@@ -159,6 +159,11 @@ impl Connection {
 		}
 	}
 
+	/// Get socket token 
+	pub fn token(&self) -> StreamToken {
+		self.token
+	}
+
 	/// Register this connection with the IO event loop.
 	pub fn register_socket<Host: Handler>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
 		trace!(target: "net", "connection register; token={:?}", reg);
diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 32370b88d..da81920ff 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -14,26 +14,34 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
-// This module is a work in progress
-
-#![allow(dead_code)] //TODO: remove this after everything is done
-
-use std::collections::{HashSet, BTreeMap};
+use bytes::Bytes;
+use std::net::SocketAddr;
+use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
 use std::cell::{RefCell};
 use std::ops::{DerefMut};
+use std::mem;
 use mio::*;
 use mio::udp::*;
 use hash::*;
 use sha3::Hashable;
 use crypto::*;
+use rlp::*;
 use network::node::*;
+use network::error::NetworkError;
+use io::StreamToken;
 
-const ADDRESS_BYTES_SIZE: u32 = 32;							///< Size of address type in bytes.
-const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE;			///< Denoted by n in [Kademlia].
-const NODE_BINS: u32 = ADDRESS_BITS - 1;					///< Size of m_state (excludes root, which is us).
-const DISCOVERY_MAX_STEPS: u16 = 8;							///< Max iterations of discovery. (discover)
-const BUCKET_SIZE: u32 = 16;		///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
-const ALPHA: usize = 3;				///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
+const ADDRESS_BYTES_SIZE: u32 = 32;							// Size of address type in bytes.
+const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE;			// Denoted by n in [Kademlia].
+const NODE_BINS: u32 = ADDRESS_BITS - 1;					// Size of m_state (excludes root, which is us).
+const DISCOVERY_MAX_STEPS: u16 = 8;							// Max iterations of discovery. (discover)
+const BUCKET_SIZE: u32 = 16;		// Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
+const ALPHA: usize = 3;				// Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
+const MAX_DATAGRAM_SIZE: usize = 1280;
+
+const PACKET_PING: u8 = 1;
+const PACKET_PONG: u8 = 2;
+const PACKET_FIND_NODE: u8 = 3;
+const PACKET_NEIGHBOURS: u8 = 4;
 
 struct NodeBucket {
 	distance: u32,
@@ -49,12 +57,25 @@ impl NodeBucket {
 	}
 }
 
-struct Discovery {
+struct Datagramm {
+	payload: Bytes,
+	address: SocketAddr,
+}
+
+pub struct Discovery {
 	id: NodeId,
+	udp_socket: UdpSocket,
+	token: StreamToken,
 	discovery_round: u16,
 	discovery_id: NodeId,
 	discovery_nodes: HashSet<NodeId>,
 	node_buckets: Vec<NodeBucket>,
+	send_queue: VecDeque<Datagramm>
+}
+
+pub struct TableUpdates {
+	pub added: HashMap<NodeId, Node>,
+	pub removed: HashSet<NodeId>,
 }
 
 struct FindNodePacket;
@@ -72,13 +93,17 @@ impl FindNodePacket {
 }
 
 impl Discovery {
-	pub fn new(id: &NodeId) -> Discovery {
+	pub fn new(id: &NodeId, address: &SocketAddr, token: StreamToken) -> Discovery {
+		let socket = UdpSocket::bound(address).expect("Error binding UDP socket");
 		Discovery {
 			id: id.clone(),
+			token: token,
 			discovery_round: 0,
 			discovery_id: NodeId::new(),
 			discovery_nodes: HashSet::new(),
 			node_buckets: (0..NODE_BINS).map(NodeBucket::new).collect(),
+			udp_socket: socket,
+			send_queue: VecDeque::new(),
 		}
 	}
 
@@ -151,17 +176,13 @@ impl Discovery {
 
 		// if d is 0, then we roll look forward, if last, we reverse, else, spread from d
 		if head > 1 && tail != LAST_BIN {
-			while head != tail && head < NODE_BINS && count < BUCKET_SIZE
-			{
-				for n in &buckets[head as usize].nodes
-				{
-						if count < BUCKET_SIZE {
-							count += 1;
-							found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-						}
-						else {
-							break;
-						}
+			while head != tail && head < NODE_BINS && count < BUCKET_SIZE {
+				for n in &buckets[head as usize].nodes {
+					if count < BUCKET_SIZE {
+						count += 1;
+						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
+					}
+					else { break }
 				}
 				if count < BUCKET_SIZE && tail != 0 {
 					for n in &buckets[tail as usize].nodes {
@@ -169,9 +190,7 @@ impl Discovery {
 							count += 1;
 							found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
 						}
-						else {
-							break;
-						}
+						else { break }
 					}
 				}
 
@@ -184,13 +203,11 @@ impl Discovery {
 		else if head < 2 {
 			while head < NODE_BINS && count < BUCKET_SIZE {
 				for n in &buckets[head as usize].nodes {
-						if count < BUCKET_SIZE {
-							count += 1;
-							found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-						}
-						else {
-							break;
-						}
+					if count < BUCKET_SIZE {
+						count += 1;
+						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
+					}
+					else { break }
 				}
 				head += 1;
 			}
@@ -198,13 +215,11 @@ impl Discovery {
 		else {
 			while tail > 0 && count < BUCKET_SIZE {
 				for n in &buckets[tail as usize].nodes {
-						if count < BUCKET_SIZE {
-							count += 1;
-							found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-						}
-						else {
-							break;
-						}
+					if count < BUCKET_SIZE {
+						count += 1;
+						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
+					}
+					else { break }
 				}
 				tail -= 1;
 			}
@@ -220,4 +235,108 @@ impl Discovery {
 		}
 		ret
 	}
+
+	pub fn writable(&mut self) {
+		if self.send_queue.is_empty() {
+			return;
+		}
+		let data = self.send_queue.pop_front().unwrap();
+		match self.udp_socket.send_to(&data.payload, &data.address) {
+			Ok(Some(size)) if size == data.payload.len() => {
+			},
+			Ok(Some(size)) => {
+				warn!("UDP sent incomplete datagramm");
+			},
+			Ok(None) => {
+				self.send_queue.push_front(data);
+			}
+			Err(e) => {
+				warn!("UDP sent error: {:?}", e);
+			}
+		}
+	}
+
+	fn send_to(&mut self, payload: Bytes, address: SocketAddr) {
+		self.send_queue.push_back(Datagramm { payload: payload, address: address });
+	}
+
+	pub fn readable(&mut self) -> Option<TableUpdates> {
+		let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() };
+		match self.udp_socket.recv_from(&mut buf) {
+			Ok(Some((len, address))) => self.on_packet(&buf[0..len], address).unwrap_or_else(|e| {
+				debug!("Error processing UDP packet: {:?}", e);
+				None
+			}),
+			Ok(_) => None,
+			Err(e) => { 
+				warn!("Error reading UPD socket: {:?}", e);
+				None
+			}
+		}
+	}
+
+	fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		// validate packet
+		if packet.len() < 32 + 65 + 4 + 1 {
+			return Err(NetworkError::BadProtocol);
+		}
+
+		let hash_signed = (&packet[32..]).sha3();
+		if hash_signed[..] != packet[0..32] {
+			return Err(NetworkError::BadProtocol);
+		}
+
+		let signed = &packet[(32 + 65)..];
+		let signature = Signature::from_slice(&packet[32..(32 + 65)]);
+		let node_id = try!(ec::recover(&signature, &signed.sha3()));
+
+		let packet_id = signed[0];
+		let rlp = UntrustedRlp::new(&signed[1..]);
+		match packet_id {
+			PACKET_PING => self.on_ping(&rlp, &node_id, &from),
+			PACKET_PONG => self.on_pong(&rlp, &node_id, &from),
+			PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from),
+			PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from),
+			_ => { 
+				debug!("Unknown UDP packet: {}", packet_id);
+				Ok(None)
+			}
+		}
+	}
+
+	fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		Ok(None)
+	}
+
+	fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		Ok(None)
+	}
+
+	fn on_find_node(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		Ok(None)
+	}
+
+	fn on_neighbours(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		Ok(None)
+	}
+
+	pub fn round(&mut self) {
+	}
+
+	pub fn refresh(&mut self) {
+	}
+
+	pub fn register_socket<Host:Handler>(&self, event_loop: &mut EventLoop<Host>) -> Result<(), NetworkError> {
+		event_loop.register(&self.udp_socket, Token(self.token), EventSet::all(), PollOpt::edge()).expect("Error registering UDP socket");
+		Ok(())
+	}
+
+	pub fn update_registration<Host:Handler>(&self, event_loop: &mut EventLoop<Host>) -> Result<(), NetworkError> {
+		let mut registration = EventSet::readable();
+		if !self.send_queue.is_empty() {
+			registration &= EventSet::writable();
+		}
+		event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket");
+		Ok(())
+	}
 }
diff --git a/util/src/network/error.rs b/util/src/network/error.rs
index 4d7fb483e..eb97e54b6 100644
--- a/util/src/network/error.rs
+++ b/util/src/network/error.rs
@@ -15,6 +15,7 @@
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
 use io::IoError;
+use crypto::CryptoError;
 use rlp::*;
 
 #[derive(Debug, Copy, Clone)]
@@ -61,3 +62,9 @@ impl From<IoError> for NetworkError {
 	}
 }
 
+impl From<CryptoError> for NetworkError {
+	fn from(_err: CryptoError) -> NetworkError {
+		NetworkError::Auth
+	}
+}
+
diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs
index 4b23c4e16..94650b2a7 100644
--- a/util/src/network/handshake.rs
+++ b/util/src/network/handshake.rs
@@ -87,6 +87,16 @@ impl Handshake {
 		})
 	}
 
+	/// Get id of the remote node if known
+	pub fn id(&self) -> &NodeId {
+		&self.id
+	}
+
+	/// Get stream token id
+	pub fn token(&self) -> StreamToken {
+		self.connection.token()
+	}
+
 	/// Start a handhsake
 	pub fn start<Message>(&mut self, io: &IoContext<Message>, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{
 		self.originated = originated;
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index c1423dbb3..2ad949642 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -22,7 +22,6 @@ use std::sync::*;
 use std::ops::*;
 use mio::*;
 use mio::tcp::*;
-use mio::udp::*;
 use target_info::Target;
 use hash::*;
 use crypto::*;
@@ -37,6 +36,8 @@ use network::node::*;
 use network::stats::NetworkStats;
 use network::error::DisconnectReason;
 use igd::{PortMappingProtocol,search_gateway};
+use network::discovery::{Discovery, TableUpdates};
+use network::node_table::NodeTable;
 
 type Slab<T> = ::slab::Slab<T, usize>;
 
@@ -50,6 +51,8 @@ const MAINTENANCE_TIMEOUT: u64 = 1000;
 #[derive(Debug)]
 /// Network service configuration
 pub struct NetworkConfiguration {
+	/// Directory path to store network configuration. None means nothing will be saved
+	pub config_path: Option<String>,
 	/// IP address to listen for incoming connections
 	pub listen_address: SocketAddr,
 	/// IP address to advertise
@@ -70,6 +73,7 @@ impl NetworkConfiguration {
 	/// Create a new instance of default settings.
 	pub fn new() -> NetworkConfiguration {
 		NetworkConfiguration {
+			config_path: None,
 			listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
 			public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
 			nat_enabled: true,
@@ -114,6 +118,7 @@ impl NetworkConfiguration {
 		}
 
 		NetworkConfiguration {
+			config_path: self.config_path,
 			listen_address: listen,
 			public_address: public,
 			nat_enabled: false,
@@ -126,14 +131,12 @@ impl NetworkConfiguration {
 }
 
 // Tokens
-//const TOKEN_BEGIN: usize = USER_TOKEN_START; // TODO: ICE in rustc 1.7.0-nightly (49c382779 2016-01-12)
-const TOKEN_BEGIN: usize = 32;
-const TCP_ACCEPT: usize = TOKEN_BEGIN + 1;
-const IDLE: usize = TOKEN_BEGIN + 2;
-const NODETABLE_RECEIVE: usize = TOKEN_BEGIN + 3;
-const NODETABLE_MAINTAIN: usize = TOKEN_BEGIN + 4;
-const NODETABLE_DISCOVERY: usize = TOKEN_BEGIN + 5;
-const FIRST_CONNECTION: usize = TOKEN_BEGIN + 16;
+const TCP_ACCEPT: usize = MAX_CONNECTIONS + 1;
+const IDLE: usize = MAX_CONNECTIONS + 2;
+const DISCOVERY: usize = MAX_CONNECTIONS + 3;
+const DISCOVERY_REFRESH: usize = MAX_CONNECTIONS + 4;
+const DISCOVERY_ROUND: usize = MAX_CONNECTIONS + 5;
+const FIRST_CONNECTION: usize = 0;
 const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1;
 
 /// Protocol handler level packet id
@@ -320,10 +323,10 @@ struct ProtocolTimer {
 /// Root IO handler. Manages protocol handlers, IO timers and network connections.
 pub struct Host<Message> where Message: Send + Sync + Clone {
 	pub info: RwLock<HostInfo>,
-	udp_socket: Mutex<UdpSocket>,
 	tcp_listener: Mutex<TcpListener>,
 	connections: Arc<RwLock<Slab<SharedConnectionEntry>>>,
-	nodes: RwLock<HashMap<NodeId, Node>>,
+	discovery: Mutex<Discovery>,
+	nodes: RwLock<NodeTable>,
 	handlers: RwLock<HashMap<ProtocolId, Arc<NetworkProtocolHandler<Message>>>>,
 	timers: RwLock<HashMap<TimerToken, ProtocolTimer>>,
 	timer_counter: RwLock<usize>,
@@ -338,10 +341,12 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let addr = config.listen_address;
 		// Setup the server socket
 		let tcp_listener = TcpListener::bind(&addr).unwrap();
-		let udp_socket = UdpSocket::bound(&addr).unwrap();
+		let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() };
+		let public = keys.public().clone();
+		let path = config.config_path.clone();
 		let mut host = Host::<Message> {
 			info: RwLock::new(HostInfo {
-				keys: if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() },
+				keys: keys,
 				config: config,
 				nonce: H256::random(),
 				protocol_version: 4,
@@ -349,10 +354,10 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				listen_port: 0,
 				capabilities: Vec::new(),
 			}),
-			udp_socket: Mutex::new(udp_socket),
+			discovery: Mutex::new(Discovery::new(&public, &addr, DISCOVERY)),
 			tcp_listener: Mutex::new(tcp_listener),
 			connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))),
-			nodes: RwLock::new(HashMap::new()),
+			nodes: RwLock::new(NodeTable::new(path)),
 			handlers: RwLock::new(HashMap::new()),
 			timers: RwLock::new(HashMap::new()),
 			timer_counter: RwLock::new(LAST_CONNECTION + 1),
@@ -361,12 +366,6 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let port = host.info.read().unwrap().config.listen_address.port();
 		host.info.write().unwrap().deref_mut().listen_port = port;
 
-		/*
-		match ::ifaces::Interface::get_all().unwrap().into_iter().filter(|x| x.kind == ::ifaces::Kind::Packet && x.addr.is_some()).next() {
-		Some(iface) => config.public_address = iface.addr.unwrap(),
-		None => warn!("No public network interface"),
-		*/
-
 		let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone();
 		for n in boot_nodes {
 			host.add_node(&n);
@@ -382,7 +381,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		match Node::from_str(id) {
 			Err(e) => { warn!("Could not add node: {:?}", e); },
 			Ok(n) => {
-				self.nodes.write().unwrap().insert(n.id.clone(), n);
+				self.nodes.write().unwrap().add_node(n);
 			}
 		}
 	}
@@ -430,12 +429,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		}
 
 		let mut to_connect: Vec<NodeInfo> = Vec::new();
-
 		let mut req_conn = 0;
-		//TODO: use nodes from discovery here
-		//for n in self.node_buckets.iter().flat_map(|n| &n.nodes).map(|id| NodeInfo { id: id.clone(), peer_type: self.nodes.get(id).unwrap().peer_type}) {
 		let pin = self.info.read().unwrap().deref().config.pin;
-		for n in self.nodes.read().unwrap().values().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
+		for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
 			let connected = self.have_session(&n.id) || self.connecting_to(&n.id);
 			let required = n.peer_type == PeerType::Required;
 			if connected && required {
@@ -685,15 +681,39 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token);
 		}
 	}
+
+	fn update_nodes(&self, io: &IoContext<NetworkIoMessage<Message>>, node_changes: TableUpdates) {
+		let connections = self.connections.write().unwrap();
+		let mut to_remove: Vec<PeerId> = Vec::new();
+		for c in connections.iter() {
+			match *c.lock().unwrap().deref_mut() {
+				ConnectionEntry::Handshake(ref h) => {
+					if node_changes.removed.contains(&h.id) {
+						to_remove.push(h.token());
+					}
+				}
+				ConnectionEntry::Session(ref s) => {
+					if node_changes.removed.contains(&s.id()) {
+						to_remove.push(s.token());
+					}
+				}
+			}
+		}
+		for i in to_remove {
+			self.kill_connection(i, io);
+		}
+		self.nodes.write().unwrap().update(node_changes);
+	}
 }
 
 impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Message: Send + Sync + Clone + 'static {
 	/// Initialize networking
 	fn initialize(&self, io: &IoContext<NetworkIoMessage<Message>>) {
 		io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener");
-		io.register_stream(NODETABLE_RECEIVE).expect("Error registering UDP listener");
+		io.register_stream(DISCOVERY).expect("Error registering UDP listener");
 		io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer");
-		//io.register_timer(NODETABLE_MAINTAIN, 7200);
+		io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer");
+		io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer");
 	}
 
 	fn stream_hup(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
@@ -707,7 +727,11 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn stream_readable(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		match stream {
 			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io),
-			NODETABLE_RECEIVE => {},
+			DISCOVERY => {
+				if let Some(node_changes) = self.discovery.lock().unwrap().readable() {
+					self.update_nodes(io, node_changes);
+				}
+			},
 			TCP_ACCEPT => self.accept(io), 
 			_ => panic!("Received unknown readable token"),
 		}
@@ -716,7 +740,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn stream_writable(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		match stream {
 			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io),
-			NODETABLE_RECEIVE => {},
+			DISCOVERY => self.discovery.lock().unwrap().writable(),
 			_ => panic!("Received unknown writable token"),
 		}
 	}
@@ -725,8 +749,12 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 		match token {
 			IDLE => self.maintain_network(io),
 			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io),
-			NODETABLE_DISCOVERY => {},
-			NODETABLE_MAINTAIN => {},
+			DISCOVERY_REFRESH => {
+				self.discovery.lock().unwrap().refresh();
+			},
+			DISCOVERY_ROUND => {
+				self.discovery.lock().unwrap().round();
+			},
 			_ => match self.timers.read().unwrap().get(&token).cloned() {
 				Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() {
 						None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) },
@@ -794,7 +822,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 					}
 				} else {} // expired
 			}
-			NODETABLE_RECEIVE => event_loop.register(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error registering stream"),
+			DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"),
 			TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"),
 			_ => warn!("Unexpected stream registration")
 		}
@@ -812,7 +840,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 					connections.remove(stream);
 				} 
 			},
-			NODETABLE_RECEIVE => event_loop.deregister(self.udp_socket.lock().unwrap().deref()).unwrap(),
+			DISCOVERY => (),
 			TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(),
 			_ => warn!("Unexpected stream deregistration")
 		}
@@ -828,7 +856,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 					}
 				} else {} // expired
 			}
-			NODETABLE_RECEIVE => event_loop.reregister(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"),
+			DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"),
 			TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"),
 			_ => warn!("Unexpected stream update")
 		}
diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index 6b58c87eb..e5465c952 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -72,6 +72,7 @@ mod discovery;
 mod service;
 mod error;
 mod node;
+mod node_table;
 mod stats;
 
 #[cfg(test)]
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
new file mode 100644
index 000000000..0f1c2c5ad
--- /dev/null
+++ b/util/src/network/node_table.rs
@@ -0,0 +1,52 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
+
+use std::collections::HashMap;
+use std::collections::hash_map::Values;
+use network::node::*;
+use network::discovery::TableUpdates;
+
+pub struct NodeTable {
+	nodes: HashMap<NodeId, Node>
+}
+
+impl NodeTable {
+	pub fn new(_path: Option<String>) -> NodeTable {
+		NodeTable {
+			nodes: HashMap::new()
+		}
+	}
+
+	pub fn add_node(&mut self, node: Node) {
+		self.nodes.insert(node.id.clone(), node);
+	}
+
+	pub fn nodes(&self) -> Values<NodeId, Node> {
+		self.nodes.values()
+	}
+
+	pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
+		self.nodes.get_mut(id)
+	}
+
+	pub fn update(&mut self, mut update: TableUpdates) {
+		self.nodes.extend(update.added.drain());
+		for r in update.removed {
+			self.nodes.remove(&r);
+		}
+	}
+
+}
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index b38807c49..19e2cf08e 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -129,6 +129,11 @@ impl Session {
 		Ok(session)
 	}
 
+	/// Get id of the remote peer
+	pub fn id(&self) -> &NodeId {
+		&self.info.id
+	}
+
 	/// Check if session is ready to send/receive data
 	pub fn is_ready(&self) -> bool {
 		self.had_hello

From 62b9f4b91db181f0d93ee1d76e78dbd526f82e25 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sat, 13 Feb 2016 22:57:39 +0100
Subject: [PATCH 02/45] UDP discovery working

---
 util/src/bytes.rs              |  24 +-
 util/src/hash.rs               |   6 -
 util/src/lib.rs                |   1 +
 util/src/network/discovery.rs  | 394 ++++++++++++++++++++++-----------
 util/src/network/error.rs      |   2 +
 util/src/network/host.rs       |  43 ++--
 util/src/network/mod.rs        |   2 +
 util/src/network/node.rs       |  78 ++++++-
 util/src/network/node_table.rs |   5 +-
 9 files changed, 375 insertions(+), 180 deletions(-)

diff --git a/util/src/bytes.rs b/util/src/bytes.rs
index 5ad2660e8..4923e6eb4 100644
--- a/util/src/bytes.rs
+++ b/util/src/bytes.rs
@@ -170,28 +170,8 @@ pub trait BytesConvertable {
 	fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() }
 }
 
-impl<'a> BytesConvertable for &'a [u8] {
-	fn bytes(&self) -> &[u8] { self }
-}
-
-impl BytesConvertable for Vec<u8> {
-	fn bytes(&self) -> &[u8] { self }
-}
-
-macro_rules! impl_bytes_convertable_for_array {
-	($zero: expr) => ();
-	($len: expr, $($idx: expr),*) => {
-		impl BytesConvertable for [u8; $len] {
-			fn bytes(&self) -> &[u8] { self }
-		}
-		impl_bytes_convertable_for_array! { $($idx),* }
-	}
-}
-
-// -1 at the end is not expanded
-impl_bytes_convertable_for_array! {
-		32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
-		15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1
+impl<T> BytesConvertable for T where T: Deref<Target = [u8]> {
+	fn bytes(&self) -> &[u8] { self.deref() }
 }
 
 #[test]
diff --git a/util/src/hash.rs b/util/src/hash.rs
index 75c39720e..c678d13a7 100644
--- a/util/src/hash.rs
+++ b/util/src/hash.rs
@@ -77,12 +77,6 @@ macro_rules! impl_hash {
 		/// Unformatted binary data of fixed length.
 		pub struct $from (pub [u8; $size]);
 
-		impl BytesConvertable for $from {
-			fn bytes(&self) -> &[u8] {
-				&self.0
-			}
-		}
-
 		impl Deref for $from {
 			type Target = [u8];
 
diff --git a/util/src/lib.rs b/util/src/lib.rs
index bdd595014..05162bca7 100644
--- a/util/src/lib.rs
+++ b/util/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(augmented_assignments)]
 #![feature(associated_consts)]
 #![feature(plugin)]
+#![feature(ip)]
 #![plugin(clippy)]
 #![allow(needless_range_loop, match_bool)]
 #![feature(catch_panic)]
diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index da81920ff..a214f5278 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -17,24 +17,26 @@
 use bytes::Bytes;
 use std::net::SocketAddr;
 use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
-use std::cell::{RefCell};
-use std::ops::{DerefMut};
 use std::mem;
+use std::cmp;
 use mio::*;
 use mio::udp::*;
+use sha3::*;
+use time;
 use hash::*;
-use sha3::Hashable;
 use crypto::*;
 use rlp::*;
 use network::node::*;
 use network::error::NetworkError;
 use io::StreamToken;
 
+use network::PROTOCOL_VERSION;
+
 const ADDRESS_BYTES_SIZE: u32 = 32;							// Size of address type in bytes.
 const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE;			// Denoted by n in [Kademlia].
 const NODE_BINS: u32 = ADDRESS_BITS - 1;					// Size of m_state (excludes root, which is us).
 const DISCOVERY_MAX_STEPS: u16 = 8;							// Max iterations of discovery. (discover)
-const BUCKET_SIZE: u32 = 16;		// Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
+const BUCKET_SIZE: usize = 16;		// Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
 const ALPHA: usize = 3;				// Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
 const MAX_DATAGRAM_SIZE: usize = 1280;
 
@@ -43,16 +45,27 @@ const PACKET_PONG: u8 = 2;
 const PACKET_FIND_NODE: u8 = 3;
 const PACKET_NEIGHBOURS: u8 = 4;
 
+const PING_TIMEOUT_MS: u64 = 300;
+
+#[derive(Clone, Debug)]
+pub struct NodeEntry {
+	pub id: NodeId,
+	pub endpoint: NodeEndpoint,
+}
+
+pub struct BucketEntry {
+	pub address: NodeEntry,
+	pub timeout: Option<u64>,
+}
+
 struct NodeBucket {
-	distance: u32,
-	nodes: Vec<NodeId>
+	nodes: VecDeque<BucketEntry>, //sorted by last active
 }
 
 impl NodeBucket {
-	fn new(distance: u32) -> NodeBucket {
+	fn new() -> NodeBucket {
 		NodeBucket {
-			distance: distance,
-			nodes: Vec::new()
+			nodes: VecDeque::new()
 		}
 	}
 }
@@ -64,6 +77,8 @@ struct Datagramm {
 
 pub struct Discovery {
 	id: NodeId,
+	secret: Secret,
+	address: NodeEndpoint,
 	udp_socket: UdpSocket,
 	token: StreamToken,
 	discovery_round: u16,
@@ -74,80 +89,90 @@ pub struct Discovery {
 }
 
 pub struct TableUpdates {
-	pub added: HashMap<NodeId, Node>,
+	pub added: HashMap<NodeId, NodeEntry>,
 	pub removed: HashSet<NodeId>,
 }
 
-struct FindNodePacket;
-
-impl FindNodePacket {
-	fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket {
-		FindNodePacket
-	}
-
-	fn sign(&mut self, _secret: &Secret) {
-	}
-
-	fn send(& self, _socket: &mut UdpSocket) {
-	}
-}
-
 impl Discovery {
-	pub fn new(id: &NodeId, address: &SocketAddr, token: StreamToken) -> Discovery {
-		let socket = UdpSocket::bound(address).expect("Error binding UDP socket");
+	pub fn new(key: &KeyPair, address: NodeEndpoint, token: StreamToken) -> Discovery {
+		let socket = UdpSocket::bound(&address.udp_address()).expect("Error binding UDP socket");
 		Discovery {
-			id: id.clone(),
+			id: key.public().clone(),
+			secret: key.secret().clone(),
+			address: address,
 			token: token,
 			discovery_round: 0,
 			discovery_id: NodeId::new(),
 			discovery_nodes: HashSet::new(),
-			node_buckets: (0..NODE_BINS).map(NodeBucket::new).collect(),
+			node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(),
 			udp_socket: socket,
 			send_queue: VecDeque::new(),
 		}
 	}
 
-	pub fn add_node(&mut self, id: &NodeId) {
-		self.node_buckets[Discovery::distance(&self.id, &id) as usize].nodes.push(id.clone());
+	pub fn add_node(&mut self, e: NodeEntry) {
+		let endpoint = e.endpoint.clone();
+		self.update_node(e);
+		self.ping(&endpoint);
 	}
 
-	fn start_node_discovery<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) {
+	fn update_node(&mut self, e: NodeEntry) {
+		trace!(target: "discovery", "Inserting {:?}", &e);
+		let ping = {
+			let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &e.id) as usize).unwrap();
+			let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) {
+				node.address = e.clone();
+				node.timeout = None;
+				true
+			} else { false };
+
+			if !updated {
+				bucket.nodes.push_front(BucketEntry { address: e, timeout: None });
+			}
+
+			if bucket.nodes.len() > BUCKET_SIZE {
+				//ping least active node
+				bucket.nodes.back_mut().unwrap().timeout = Some(time::precise_time_ns());
+				Some(bucket.nodes.back().unwrap().address.endpoint.clone())
+			} else { None }
+		};
+		if let Some(endpoint) = ping {
+			self.ping(&endpoint);
+		}
+	}
+
+	fn start(&mut self) {
+		trace!(target: "discovery", "Starting discovery");
 		self.discovery_round = 0;
-		self.discovery_id.randomize();
+		self.discovery_id.randomize(); //TODO: use cryptographic nonce
 		self.discovery_nodes.clear();
-		self.discover(event_loop);
 	}
 
-	fn discover<Host:Handler>(&mut self, event_loop: &mut EventLoop<Host>) {
-		if self.discovery_round == DISCOVERY_MAX_STEPS
-		{
-			debug!("Restarting discovery");
-			self.start_node_discovery(event_loop);
+	fn discover(&mut self) {
+		if self.discovery_round == DISCOVERY_MAX_STEPS {
 			return;
 		}
+		trace!(target: "discovery", "Starting round {:?}", self.discovery_round);
 		let mut tried_count = 0;
 		{
-			let nearest = Discovery::nearest_node_entries(&self.id, &self.discovery_id, &self.node_buckets).into_iter();
-			let nodes = RefCell::new(&mut self.discovery_nodes);
-			let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA);
+			let nearest = Discovery::nearest_node_entries(&self.discovery_id, &self.node_buckets).into_iter();
+			let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::<Vec<_>>();
 			for r in nearest {
-				//let mut p = FindNodePacket::new(&r.endpoint, &self.discovery_id);
-				//p.sign(&self.secret);
-				//p.send(&mut self.udp_socket);
-				let mut borrowed = nodes.borrow_mut();
-				borrowed.deref_mut().insert(r.clone());
+				let rlp = encode(&(&[self.discovery_id.clone()][..]));
+				self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp);
+				self.discovery_nodes.insert(r.id.clone());
 				tried_count += 1;
+				trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint);
 			}
 		}
 
-		if tried_count == 0
-		{
-			debug!("Restarting discovery");
-			self.start_node_discovery(event_loop);
+		if tried_count == 0 {
+			trace!(target: "discovery", "Completing discovery");
+			self.discovery_round = DISCOVERY_MAX_STEPS;
+			self.discovery_nodes.clear();
 			return;
 		}
 		self.discovery_round += 1;
-		//event_loop.timeout_ms(Token(NODETABLE_DISCOVERY), 1200).unwrap();
 	}
 
 	fn distance(a: &NodeId, b: &NodeId) -> u32 {
@@ -163,75 +188,75 @@ impl Discovery {
 		ret
 	}
 
-	#[allow(cyclomatic_complexity)]
-	fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b [NodeBucket]) -> Vec<&'b NodeId>
-	{
-		// send ALPHA FindNode packets to nodes we know, closest to target
-		const LAST_BIN: u32 = NODE_BINS - 1;
-		let mut head = Discovery::distance(source, target);
-		let mut tail = if head == 0  { LAST_BIN } else { (head - 1) % NODE_BINS };
+	fn ping(&mut self, node: &NodeEndpoint) {
+		let mut rlp = RlpStream::new_list(3);
+		rlp.append(&PROTOCOL_VERSION);
+		self.address.to_rlp_list(&mut rlp);
+		node.to_rlp_list(&mut rlp);
+		trace!(target: "discovery", "Sent Ping to {:?}", &node);
+		self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain());
+	}
 
-		let mut found: BTreeMap<u32, Vec<&'b NodeId>> = BTreeMap::new();
+	fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) {
+		let mut rlp = RlpStream::new();
+		rlp.append_raw(&[packet_id], 1);
+		let source = Rlp::new(payload);
+		rlp.begin_list(source.item_count() + 1);
+		for i in 0 .. source.item_count() {
+			rlp.append_raw(source.at(i).as_raw(), 1);
+		}
+		let timestamp = time::get_time().sec as u32 + 60;
+		rlp.append(&timestamp);
+
+		let bytes = rlp.drain();
+		let hash = bytes.sha3();
+		let signature = match ec::sign(&self.secret, &hash) {
+			Ok(s) => s,
+			Err(_) => {
+				warn!("Error signing UDP packet");
+				return;
+			}
+		};
+		let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65);
+		packet.extend(hash.iter());
+		packet.extend(signature.iter());
+		packet.extend(bytes.iter());
+		let signed_hash = (&packet[32..]).sha3();
+		packet[0..32].clone_from_slice(&signed_hash);
+		self.send_to(packet, address.clone());
+	}
+
+	#[allow(map_clone)]
+	fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec<NodeEntry>
+	{
+		let mut found: BTreeMap<u32, Vec<&NodeEntry>> = BTreeMap::new();
 		let mut count = 0;
 
-		// if d is 0, then we roll look forward, if last, we reverse, else, spread from d
-		if head > 1 && tail != LAST_BIN {
-			while head != tail && head < NODE_BINS && count < BUCKET_SIZE {
-				for n in &buckets[head as usize].nodes {
-					if count < BUCKET_SIZE {
-						count += 1;
-						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-					}
-					else { break }
-				}
-				if count < BUCKET_SIZE && tail != 0 {
-					for n in &buckets[tail as usize].nodes {
-						if count < BUCKET_SIZE {
-							count += 1;
-							found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-						}
-						else { break }
+		// Sort nodes by distance to target
+		for bucket in buckets {
+			for node in &bucket.nodes {
+				let distance = Discovery::distance(target, &node.address.id); 
+				found.entry(distance).or_insert_with(Vec::new).push(&node.address);
+				if count == BUCKET_SIZE {
+					// delete the most distant element
+					let remove = {
+						let (_, last) = found.iter_mut().next_back().unwrap();
+						last.pop();
+						last.is_empty()
+					};
+					if remove {
+						found.remove(&distance);
 					}
 				}
-
-				head += 1;
-				if tail > 0 {
-					tail -= 1;
+				else {
+					count += 1;
 				}
 			}
 		}
-		else if head < 2 {
-			while head < NODE_BINS && count < BUCKET_SIZE {
-				for n in &buckets[head as usize].nodes {
-					if count < BUCKET_SIZE {
-						count += 1;
-						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-					}
-					else { break }
-				}
-				head += 1;
-			}
-		}
-		else {
-			while tail > 0 && count < BUCKET_SIZE {
-				for n in &buckets[tail as usize].nodes {
-					if count < BUCKET_SIZE {
-						count += 1;
-						found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n);
-					}
-					else { break }
-				}
-				tail -= 1;
-			}
-		}
 
-		let mut ret:Vec<&NodeId> = Vec::new();
+		let mut ret:Vec<NodeEntry> = Vec::new();
 		for (_, nodes) in found {
-			for n in nodes {
-				if ret.len() < BUCKET_SIZE as usize /* && n->endpoint && n->endpoint.isAllowed() */ {
-					ret.push(n);
-				}
-			}
+			ret.extend(nodes.iter().map(|&n| n.clone()));
 		}
 		ret
 	}
@@ -240,18 +265,22 @@ impl Discovery {
 		if self.send_queue.is_empty() {
 			return;
 		}
-		let data = self.send_queue.pop_front().unwrap();
-		match self.udp_socket.send_to(&data.payload, &data.address) {
-			Ok(Some(size)) if size == data.payload.len() => {
-			},
-			Ok(Some(size)) => {
-				warn!("UDP sent incomplete datagramm");
-			},
-			Ok(None) => {
-				self.send_queue.push_front(data);
-			}
-			Err(e) => {
-				warn!("UDP sent error: {:?}", e);
+		while !self.send_queue.is_empty() {
+			let data = self.send_queue.pop_front().unwrap();
+			match self.udp_socket.send_to(&data.payload, &data.address) {
+				Ok(Some(size)) if size == data.payload.len() => {
+				},
+				Ok(Some(_)) => {
+					warn!("UDP sent incomplete datagramm");
+				},
+				Ok(None) => {
+					self.send_queue.push_front(data);
+					return;
+				}
+				Err(e) => {
+					warn!("UDP send error: {:?}, address: {:?}", e, &data.address);
+					return;
+				}
 			}
 		}
 	}
@@ -305,25 +334,132 @@ impl Discovery {
 	}
 
 	fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
-		Ok(None)
+		trace!(target: "discovery", "Got Ping from {:?}", &from);
+		let version: u32 = try!(rlp.val_at(0));
+		if version != PROTOCOL_VERSION {
+			debug!(target: "discovery", "Unexpected protocol version: {}", version);
+			return Err(NetworkError::BadProtocol);
+		}
+		let source = try!(NodeEndpoint::from_rlp(&try!(rlp.at(1))));
+		let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(2))));
+		let timestamp: u64 = try!(rlp.val_at(3));
+		if timestamp < time::get_time().sec as u64{
+			debug!(target: "discovery", "Expired ping");
+			return Err(NetworkError::Expired);
+		}
+		let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() };
+		if !entry.endpoint.is_valid() {
+			debug!(target: "discovery", "Bad address: {:?}", entry);
+			entry.endpoint.address = from.clone();
+		}
+		self.update_node(entry.clone());
+		let hash = rlp.as_raw().sha3();
+		let mut response = RlpStream::new_list(2);
+		dest.to_rlp_list(&mut response);
+		response.append(&hash);
+		self.send_packet(PACKET_PONG, &entry.endpoint.udp_address(), &response.drain());
+		
+		let mut added_map = HashMap::new();
+		added_map.insert(node.clone(), entry); 
+		Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() }))
 	}
 
 	fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		trace!(target: "discovery", "Got Pong from {:?}", &from);
+		// TODO: validate pong packet
+		let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0))));
+		let timestamp: u64 = try!(rlp.val_at(2));
+		if timestamp > time::get_time().sec as u64 {
+			return Err(NetworkError::Expired);
+		}
+		let mut entry = NodeEntry { id: node.clone(), endpoint: dest };
+		if !entry.endpoint.is_valid() {
+			debug!(target: "discovery", "Bad address: {:?}", entry);
+			entry.endpoint.address = from.clone();
+		}
+		self.update_node(entry.clone());
+		let mut added_map = HashMap::new();
+		added_map.insert(node.clone(), entry); 
+		Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() }))
+	}
+
+	fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		trace!(target: "discovery", "Got FindNode from {:?}", &from);
+		let target: NodeId = try!(rlp.val_at(0));
+		let timestamp: u64 = try!(rlp.val_at(1));
+		if timestamp > time::get_time().sec as u64 {
+			return Err(NetworkError::Expired);
+		}
+
+		let limit = (MAX_DATAGRAM_SIZE - 109) / 90;
+		let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets);
+		if nearest.is_empty() {
+			return Ok(None);
+		}
+		let mut rlp = RlpStream::new_list(cmp::min(limit, nearest.len()));
+		rlp.begin_list(1);
+		for n in 0 .. nearest.len() {
+			rlp.begin_list(4);
+			nearest[n].endpoint.to_rlp(&mut rlp);
+			rlp.append(&nearest[n].id);
+			if (n + 1) % limit == 0 || n == nearest.len() - 1 {
+				self.send_packet(PACKET_NEIGHBOURS, &from, &rlp.drain());
+				trace!(target: "discovery", "Sent {} Neighbours to {:?}", n, &from);
+				rlp = RlpStream::new_list(cmp::min(limit, nearest.len() - n));
+				rlp.begin_list(1);
+			}
+		}
 		Ok(None)
 	}
 
-	fn on_find_node(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
-		Ok(None)
+	fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
+		// TODO: validate packet
+		let mut added = HashMap::new();
+		trace!(target: "discovery", "Got {} Neighbours from {:?}", try!(rlp.at(0)).item_count(), &from);
+		for r in try!(rlp.at(0)).iter() {
+			let endpoint = try!(NodeEndpoint::from_rlp(&r));
+			if !endpoint.is_valid() {
+				debug!(target: "discovery", "Bad address: {:?}", endpoint);
+				continue;
+			}
+			let node_id: NodeId = try!(r.val_at(3));
+			let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint };
+			added.insert(node_id, entry.clone());
+			self.update_node(entry);
+		}
+		Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
 	}
 
-	fn on_neighbours(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
-		Ok(None)
+	fn check_expired(&mut self) -> HashSet<NodeId> {
+		let now = time::precise_time_ns();
+		let mut removed: HashSet<NodeId> = HashSet::new();
+		for bucket in &mut self.node_buckets {
+			bucket.nodes.retain(|node| {
+				if let Some(timeout) = node.timeout {
+					if now - timeout < PING_TIMEOUT_MS * 1000_0000 {
+						true
+					}
+					else {
+						trace!(target: "discovery", "Removed expired node {:?}", &node.address);
+						removed.insert(node.address.id.clone());
+						false
+					}
+				} else { true }
+			});
+		}
+		removed
 	}
 
-	pub fn round(&mut self) {
+	pub fn round(&mut self) -> Option<TableUpdates> {
+		let removed = self.check_expired();
+		self.discover();
+		if !removed.is_empty() { 
+			Some(TableUpdates { added: HashMap::new(), removed: removed }) 
+		} else { None }
 	}
 
 	pub fn refresh(&mut self) {
+		self.start();
 	}
 
 	pub fn register_socket<Host:Handler>(&self, event_loop: &mut EventLoop<Host>) -> Result<(), NetworkError> {
@@ -334,7 +470,7 @@ impl Discovery {
 	pub fn update_registration<Host:Handler>(&self, event_loop: &mut EventLoop<Host>) -> Result<(), NetworkError> {
 		let mut registration = EventSet::readable();
 		if !self.send_queue.is_empty() {
-			registration &= EventSet::writable();
+			registration = registration | EventSet::writable();
 		}
 		event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket");
 		Ok(())
diff --git a/util/src/network/error.rs b/util/src/network/error.rs
index eb97e54b6..74babb110 100644
--- a/util/src/network/error.rs
+++ b/util/src/network/error.rs
@@ -42,6 +42,8 @@ pub enum NetworkError {
 	Auth,
 	/// Unrecognised protocol.
 	BadProtocol,
+	/// Message expired.
+	Expired,
 	/// Peer not found.
 	PeerNotFound,
 	/// Peer is diconnected.
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 05462be37..47a3d9986 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -31,21 +31,18 @@ use network::handshake::Handshake;
 use network::session::{Session, SessionData};
 use error::*;
 use io::*;
-use network::NetworkProtocolHandler;
+use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
 use network::node::*;
 use network::stats::NetworkStats;
 use network::error::DisconnectReason;
 use igd::{PortMappingProtocol,search_gateway};
-use network::discovery::{Discovery, TableUpdates};
+use network::discovery::{Discovery, TableUpdates, NodeEntry};
 use network::node_table::NodeTable;
 
 type Slab<T> = ::slab::Slab<T, usize>;
 
 const _DEFAULT_PORT: u16 = 30304;
-
 const MAX_CONNECTIONS: usize = 1024;
-const IDEAL_PEERS: u32 = 10;
-
 const MAINTENANCE_TIMEOUT: u64 = 1000;
 
 #[derive(Debug)]
@@ -67,6 +64,8 @@ pub struct NetworkConfiguration {
 	pub boot_nodes: Vec<String>,
 	/// Use provided node key instead of default
 	pub use_secret: Option<Secret>,
+	/// Number of connected peers to maintain
+	pub ideal_peers: u32,
 }
 
 impl NetworkConfiguration {
@@ -81,6 +80,7 @@ impl NetworkConfiguration {
 			pin: false,
 			boot_nodes: Vec::new(),
 			use_secret: None,
+			ideal_peers: 10,
 		}
 	}
 
@@ -126,6 +126,7 @@ impl NetworkConfiguration {
 			pin: self.pin,
 			boot_nodes: self.boot_nodes,
 			use_secret: self.use_secret,
+			ideal_peers: self.ideal_peers,
 		}
 	}
 }
@@ -343,19 +344,20 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		// Setup the server socket
 		let tcp_listener = TcpListener::bind(&addr).unwrap();
 		let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() };
-		let public = keys.public().clone();
+		let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() };
+		let discovery = Discovery::new(&keys, endpoint, DISCOVERY);
 		let path = config.config_path.clone();
 		let mut host = Host::<Message> {
 			info: RwLock::new(HostInfo {
 				keys: keys,
 				config: config,
 				nonce: H256::random(),
-				protocol_version: 4,
+				protocol_version: PROTOCOL_VERSION,
 				client_version: format!("Parity/{}/{}-{}-{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()),
 				listen_port: 0,
 				capabilities: Vec::new(),
 			}),
-			discovery: Mutex::new(Discovery::new(&public, &addr, DISCOVERY)),
+			discovery: Mutex::new(discovery),
 			tcp_listener: Mutex::new(tcp_listener),
 			connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))),
 			nodes: RwLock::new(NodeTable::new(path)),
@@ -382,7 +384,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		match Node::from_str(id) {
 			Err(e) => { warn!("Could not add node: {:?}", e); },
 			Ok(n) => {
+				let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
 				self.nodes.write().unwrap().add_node(n);
+				self.discovery.lock().unwrap().add_node(entry);
 			}
 		}
 	}
@@ -432,6 +436,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let mut to_connect: Vec<NodeInfo> = Vec::new();
 		let mut req_conn = 0;
 		let pin = self.info.read().unwrap().deref().config.pin;
+		let ideal_peers = self.info.read().unwrap().deref().config.ideal_peers;
 		for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
 			let connected = self.have_session(&n.id) || self.connecting_to(&n.id);
 			let required = n.peer_type == PeerType::Required;
@@ -445,7 +450,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 
 		for n in &to_connect {
 			if n.peer_type == PeerType::Required {
-				if req_conn < IDEAL_PEERS {
+				if req_conn < ideal_peers {
 					self.connect_peer(&n.id, io);
 				}
 				req_conn += 1;
@@ -455,7 +460,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		if !pin {
 			let pending_count = 0; //TODO:
 			let peer_count = 0;
-			let mut open_slots = IDEAL_PEERS - peer_count  - pending_count + req_conn;
+			let mut open_slots = ideal_peers - peer_count  - pending_count + req_conn;
 			if open_slots > 0 {
 				for n in &to_connect {
 					if n.peer_type == PeerType::Optional && open_slots > 0 {
@@ -471,11 +476,11 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	fn connect_peer(&self, id: &NodeId, io: &IoContext<NetworkIoMessage<Message>>) {
 		if self.have_session(id)
 		{
-			warn!("Aborted connect. Node already connected.");
+			debug!("Aborted connect. Node already connected.");
 			return;
 		}
 		if self.connecting_to(id) {
-			warn!("Aborted connect. Node already connecting.");
+			debug!("Aborted connect. Node already connecting.");
 			return;
 		}
 
@@ -689,7 +694,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		for c in connections.iter() {
 			match *c.lock().unwrap().deref_mut() {
 				ConnectionEntry::Handshake(ref h) => {
-					if node_changes.removed.contains(&h.id) {
+					if node_changes.removed.contains(&h.id()) {
 						to_remove.push(h.token());
 					}
 				}
@@ -732,6 +737,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 				if let Some(node_changes) = self.discovery.lock().unwrap().readable() {
 					self.update_nodes(io, node_changes);
 				}
+				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
 			},
 			TCP_ACCEPT => self.accept(io), 
 			_ => panic!("Received unknown readable token"),
@@ -741,7 +747,10 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn stream_writable(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		match stream {
 			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io),
-			DISCOVERY => self.discovery.lock().unwrap().writable(),
+			DISCOVERY => {
+				self.discovery.lock().unwrap().writable();
+				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
+			}
 			_ => panic!("Received unknown writable token"),
 		}
 	}
@@ -752,9 +761,13 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io),
 			DISCOVERY_REFRESH => {
 				self.discovery.lock().unwrap().refresh();
+				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
 			},
 			DISCOVERY_ROUND => {
-				self.discovery.lock().unwrap().round();
+				if let Some(node_changes) = self.discovery.lock().unwrap().round() {
+					self.update_nodes(io, node_changes);
+				}
+				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
 			},
 			_ => match self.timers.read().unwrap().get(&token).cloned() {
 				Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() {
diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index e5465c952..466ef4e6a 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -90,6 +90,8 @@ pub use network::stats::NetworkStats;
 
 use io::TimerToken;
 
+const PROTOCOL_VERSION: u32 = 4;
+
 /// Network IO protocol handler. This needs to be implemented for each new subprotocol.
 /// All the handler function are called from within IO event loop.
 /// `Message` is the type for message data.
diff --git a/util/src/network/node.rs b/util/src/network/node.rs
index e23dee9f5..d8370bc79 100644
--- a/util/src/network/node.rs
+++ b/util/src/network/node.rs
@@ -14,7 +14,9 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
-use std::net::{SocketAddr, ToSocketAddrs};
+use std::mem;
+use std::slice::from_raw_parts;
+use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
 use std::hash::{Hash, Hasher};
 use std::str::{FromStr};
 use hash::*;
@@ -25,17 +27,69 @@ use error::*;
 /// Node public key
 pub type NodeId = H512;
 
-#[derive(Debug)]
-/// Noe address info
+#[derive(Debug, Clone)]
+/// Node address info
 pub struct NodeEndpoint {
 	/// IP(V4 or V6) address
 	pub address: SocketAddr,
-	/// Address as string (can be host name).
-	pub address_str: String,
 	/// Conneciton port.
 	pub udp_port: u16
 }
 
+impl NodeEndpoint {
+	pub fn udp_address(&self) -> SocketAddr {
+		match self.address {
+			SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)),
+			SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())),
+		}
+	}
+}
+
+impl NodeEndpoint {
+	pub fn from_rlp(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
+		let tcp_port = try!(rlp.val_at::<u16>(2));
+		let udp_port = try!(rlp.val_at::<u16>(1));
+		let addr_bytes = try!(try!(rlp.at(0)).data());
+		let address = try!(match addr_bytes.len() {
+			4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
+			16 => unsafe {
+				let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
+				let o = from_raw_parts(o, 8);
+				Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
+			},
+			_ => Err(DecoderError::RlpInconsistentLengthAndData)
+		});
+		Ok(NodeEndpoint { address: address, udp_port: udp_port })
+	}
+
+	pub fn to_rlp(&self, rlp: &mut RlpStream) {
+		match self.address {
+			SocketAddr::V4(a) => {
+				rlp.append(&(&a.ip().octets()[..]));
+			}
+			SocketAddr::V6(a) => unsafe {
+				let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
+				rlp.append(&from_raw_parts(o, 16));
+			}
+		};
+		rlp.append(&self.udp_port);
+		rlp.append(&self.address.port());
+	}
+
+	pub fn to_rlp_list(&self, rlp: &mut RlpStream) {
+		rlp.begin_list(3);
+		self.to_rlp(rlp);
+	}
+
+	pub fn is_valid(&self) -> bool {
+		self.udp_port != 0 && self.address.port() != 0 &&
+		match self.address {
+			SocketAddr::V4(a) => !a.ip().is_unspecified(),
+			SocketAddr::V6(a) => !a.ip().is_unspecified()
+		}
+	}
+}
+
 impl FromStr for NodeEndpoint {
 	type Err = UtilError;
 
@@ -45,7 +99,6 @@ impl FromStr for NodeEndpoint {
 		match address {
 			Ok(Some(a)) => Ok(NodeEndpoint {
 				address: a,
-				address_str: s.to_owned(),
 				udp_port: a.port()
 			}),
 			Ok(_) => Err(UtilError::AddressResolve(None)),
@@ -67,6 +120,17 @@ pub struct Node {
 	pub last_attempted: Option<Tm>,
 }
 
+impl Node {
+	pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
+		Node {
+			id: id,
+			endpoint: endpoint,
+			peer_type: PeerType::Optional,
+			last_attempted: None,
+		}
+	}
+}
+
 impl FromStr for Node {
 	type Err = UtilError;
 	fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -91,7 +155,7 @@ impl PartialEq for Node {
 		self.id == other.id
 	}
 }
-impl Eq for Node { }
+impl Eq for Node {}
 
 impl Hash for Node {
 	fn hash<H>(&self, state: &mut H) where H: Hasher {
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 0f1c2c5ad..d93057eb3 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -43,7 +43,10 @@ impl NodeTable {
 	}
 
 	pub fn update(&mut self, mut update: TableUpdates) {
-		self.nodes.extend(update.added.drain());
+		for (_, node) in update.added.drain() {
+			let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone()));
+			entry.endpoint = node.endpoint;
+		}
 		for r in update.removed {
 			self.nodes.remove(&r);
 		}

From 76ea030b7817a3f3c21f4674c987d817de4d7c38 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 01:03:48 +0100
Subject: [PATCH 03/45] Small refactoring

---
 sync/src/chain.rs              |   6 +-
 util/src/network/discovery.rs  |   6 +-
 util/src/network/handshake.rs  |   2 +-
 util/src/network/host.rs       | 106 ++++++++---------
 util/src/network/mod.rs        |   1 -
 util/src/network/node.rs       | 198 --------------------------------
 util/src/network/node_table.rs | 203 ++++++++++++++++++++++++++++++++-
 util/src/network/session.rs    |   2 +-
 8 files changed, 257 insertions(+), 267 deletions(-)
 delete mode 100644 util/src/network/node.rs

diff --git a/sync/src/chain.rs b/sync/src/chain.rs
index f82162b79..671e2241e 100644
--- a/sync/src/chain.rs
+++ b/sync/src/chain.rs
@@ -82,7 +82,7 @@ const RECEIPTS_PACKET: u8 = 0x10;
 
 const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent
 
-const CONNECTION_TIMEOUT_SEC: f64 = 30f64;
+const CONNECTION_TIMEOUT_SEC: f64 = 10f64;
 
 struct Header {
 	/// Header data
@@ -309,7 +309,7 @@ impl ChainSync {
 		}
 
 		self.peers.insert(peer_id.clone(), peer);
-		info!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id));
+		debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id));
 		self.sync_peer(io, peer_id, false);
 		Ok(())
 	}
@@ -537,7 +537,7 @@ impl ChainSync {
 	pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) {
 		trace!(target: "sync", "== Disconnecting {}", peer);
 		if self.peers.contains_key(&peer) {
-			info!(target: "sync", "Disconnected {}", peer);
+			debug!(target: "sync", "Disconnected {}", peer);
 			self.clear_peer_download(peer);
 			self.peers.remove(&peer);
 			self.continue_sync(io);
diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index a214f5278..9feef9c74 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -26,7 +26,7 @@ use time;
 use hash::*;
 use crypto::*;
 use rlp::*;
-use network::node::*;
+use network::node_table::*;
 use network::error::NetworkError;
 use io::StreamToken;
 
@@ -227,8 +227,7 @@ impl Discovery {
 	}
 
 	#[allow(map_clone)]
-	fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec<NodeEntry>
-	{
+	fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec<NodeEntry> {
 		let mut found: BTreeMap<u32, Vec<&NodeEntry>> = BTreeMap::new();
 		let mut count = 0;
 
@@ -425,6 +424,7 @@ impl Discovery {
 			let node_id: NodeId = try!(r.val_at(3));
 			let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint };
 			added.insert(node_id, entry.clone());
+			self.ping(&entry.endpoint);
 			self.update_node(entry);
 		}
 		Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs
index 94650b2a7..1fd830ea0 100644
--- a/util/src/network/handshake.rs
+++ b/util/src/network/handshake.rs
@@ -24,7 +24,7 @@ use crypto::*;
 use crypto;
 use network::connection::{Connection};
 use network::host::{HostInfo};
-use network::node::NodeId;
+use network::node_table::NodeId;
 use error::*;
 use network::error::NetworkError;
 use network::stats::NetworkStats;
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 47a3d9986..321e965ec 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -32,18 +32,18 @@ use network::session::{Session, SessionData};
 use error::*;
 use io::*;
 use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
-use network::node::*;
+use network::node_table::*;
 use network::stats::NetworkStats;
 use network::error::DisconnectReason;
 use igd::{PortMappingProtocol,search_gateway};
 use network::discovery::{Discovery, TableUpdates, NodeEntry};
-use network::node_table::NodeTable;
 
 type Slab<T> = ::slab::Slab<T, usize>;
 
 const _DEFAULT_PORT: u16 = 30304;
 const MAX_CONNECTIONS: usize = 1024;
 const MAINTENANCE_TIMEOUT: u64 = 1000;
+const MAX_HANDSHAKES: usize = 100;
 
 #[derive(Debug)]
 /// Network service configuration
@@ -226,7 +226,7 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 				_ => warn!(target: "net", "Send: Peer is not connected yet")
 			}
 		} else  {
-			warn!(target: "net", "Send: Peer does not exist")
+			trace!(target: "net", "Send: Peer no longer exist")
 		}
 		Ok(())
 	}
@@ -405,11 +405,23 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn have_session(&self, id: &NodeId) -> bool {
-		self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false  })
+		self.connections.read().unwrap().iter().any(|e| 
+			match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false  })
+	}
+
+	fn session_count(&self) -> usize {
+		self.connections.read().unwrap().iter().filter(|e| 
+			match *e.lock().unwrap().deref() { ConnectionEntry::Session(_) => true, _ => false  }).count()
 	}
 
 	fn connecting_to(&self, id: &NodeId) -> bool {
-		self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false  })
+		self.connections.read().unwrap().iter().any(|e| 
+			match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false  })
+	}
+
+	fn handshake_count(&self) -> usize {
+		self.connections.read().unwrap().iter().filter(|e| 
+			match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(_) => true, _ => false  }).count()
 	}
 
 	fn keep_alive(&self, io: &IoContext<NetworkIoMessage<Message>>) {
@@ -423,64 +435,40 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		}
 		for p in to_kill {
-			self.kill_connection(p, io);
+			self.kill_connection(p, io, true);
 		}
 	}
 
 	fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
-		struct NodeInfo {
-			id: NodeId,
-			peer_type: PeerType
+		let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers };
+		let connections = self.session_count();
+		if connections >= ideal_peers as usize {
+			return;
 		}
 
-		let mut to_connect: Vec<NodeInfo> = Vec::new();
-		let mut req_conn = 0;
-		let pin = self.info.read().unwrap().deref().config.pin;
-		let ideal_peers = self.info.read().unwrap().deref().config.ideal_peers;
-		for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
-			let connected = self.have_session(&n.id) || self.connecting_to(&n.id);
-			let required = n.peer_type == PeerType::Required;
-			if connected && required {
-				req_conn += 1;
-			}
-			else if !connected && (!pin || required) {
-				to_connect.push(n);
-			}
+		let handshake_count = self.handshake_count();
+		if handshake_count >= MAX_HANDSHAKES {
+			return;
 		}
 
-		for n in &to_connect {
-			if n.peer_type == PeerType::Required {
-				if req_conn < ideal_peers {
-					self.connect_peer(&n.id, io);
-				}
-				req_conn += 1;
-			}
-		}
 
-		if !pin {
-			let pending_count = 0; //TODO:
-			let peer_count = 0;
-			let mut open_slots = ideal_peers - peer_count  - pending_count + req_conn;
-			if open_slots > 0 {
-				for n in &to_connect {
-					if n.peer_type == PeerType::Optional && open_slots > 0 {
-						open_slots -= 1;
-						self.connect_peer(&n.id, io);
-					}
-				}
-			}
+		let nodes = { self.nodes.read().unwrap().nodes() };
+
+		for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)).take(MAX_HANDSHAKES - handshake_count) {
+			self.connect_peer(&id, io);
 		}
+		debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count());
 	}
 
 	#[allow(single_match)]
 	fn connect_peer(&self, id: &NodeId, io: &IoContext<NetworkIoMessage<Message>>) {
 		if self.have_session(id)
 		{
-			debug!("Aborted connect. Node already connected.");
+			trace!("Aborted connect. Node already connected.");
 			return;
 		}
 		if self.connecting_to(id) {
-			debug!("Aborted connect. Node already connecting.");
+			trace!("Aborted connect. Node already connecting.");
 			return;
 		}
 
@@ -542,7 +530,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				ConnectionEntry::Handshake(ref mut h) => {
 					match h.writable(io, &self.info.read().unwrap()) {
 						Err(e) => {
-							debug!(target: "net", "Handshake write error: {:?}", e);
+							debug!(target: "net", "Handshake write error: {}:{:?}", token, e);
 							kill = true;
 						},
 						Ok(_) => ()
@@ -554,7 +542,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				ConnectionEntry::Session(ref mut s) => {
 					match s.writable(io, &self.info.read().unwrap()) {
 						Err(e) => {
-							debug!(target: "net", "Session write error: {:?}", e);
+							debug!(target: "net", "Session write error: {}:{:?}", token, e);
 							kill = true;
 						},
 						Ok(_) => ()
@@ -564,7 +552,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		} 
 		if kill {
-			self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection
+			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
 			return;
 		} else if create_session {
 			self.start_session(token, io);
@@ -573,7 +561,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn connection_closed(&self, token: TimerToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		self.kill_connection(token, io);
+		self.kill_connection(token, io, true);
 	}
 
 	fn connection_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
@@ -585,7 +573,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			match *connection.lock().unwrap().deref_mut() {
 				ConnectionEntry::Handshake(ref mut h) => {
 					if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
-						debug!(target: "net", "Handshake read error: {:?}", e);
+						debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
 						kill = true;
 					}
 					if h.done() {
@@ -595,7 +583,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				ConnectionEntry::Session(ref mut s) => {
 					match s.readable(io, &self.info.read().unwrap()) {
 						Err(e) => {
-							debug!(target: "net", "Handshake read error: {:?}", e);
+							debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
 							kill = true;
 						},
 						Ok(SessionData::Ready) => {
@@ -621,7 +609,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		} 
 		if kill {
-			self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection
+			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
 			return;
 		} else if create_session {
 			self.start_session(token, io);
@@ -657,17 +645,20 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn connection_timeout(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		self.kill_connection(token, io)
+		self.kill_connection(token, io, true)
 	}
 
-	fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
+	fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>, remote: bool) {
 		let mut to_disconnect: Vec<ProtocolId> = Vec::new();
 		{
 			let mut connections = self.connections.write().unwrap();
 			if let Some(connection) = connections.get(token).cloned() {
 				match *connection.lock().unwrap().deref_mut() {
-					ConnectionEntry::Handshake(_) => {
+					ConnectionEntry::Handshake(ref h) => {
 						connections.remove(token);
+						if remote {
+							self.nodes.write().unwrap().note_failure(h.id());
+						}
 					},
 					ConnectionEntry::Session(ref mut s) if s.is_ready() => {
 						for (p, _) in self.handlers.read().unwrap().iter() {
@@ -676,6 +667,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 							}
 						}
 						connections.remove(token);
+						if remote {
+							self.nodes.write().unwrap().note_failure(s.id());
+						}
 					},
 					_ => {},
 				}
@@ -706,7 +700,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		}
 		for i in to_remove {
-			self.kill_connection(i, io);
+			self.kill_connection(i, io, false);
 		}
 		self.nodes.write().unwrap().update(node_changes);
 	}
@@ -816,7 +810,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 						ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } 
 					}
 				} 
-				self.kill_connection(*peer, io);
+				self.kill_connection(*peer, io, false);
 			},
 			NetworkIoMessage::User(ref message) => {
 				for (p, h) in self.handlers.read().unwrap().iter() {
diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index 466ef4e6a..7d5aac8f7 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -71,7 +71,6 @@ mod session;
 mod discovery;
 mod service;
 mod error;
-mod node;
 mod node_table;
 mod stats;
 
diff --git a/util/src/network/node.rs b/util/src/network/node.rs
deleted file mode 100644
index d8370bc79..000000000
--- a/util/src/network/node.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2015, 2016 Ethcore (UK) Ltd.
-// This file is part of Parity.
-
-// Parity is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Parity 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 General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
-
-use std::mem;
-use std::slice::from_raw_parts;
-use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
-use std::hash::{Hash, Hasher};
-use std::str::{FromStr};
-use hash::*;
-use rlp::*;
-use time::Tm;
-use error::*;
-
-/// Node public key
-pub type NodeId = H512;
-
-#[derive(Debug, Clone)]
-/// Node address info
-pub struct NodeEndpoint {
-	/// IP(V4 or V6) address
-	pub address: SocketAddr,
-	/// Conneciton port.
-	pub udp_port: u16
-}
-
-impl NodeEndpoint {
-	pub fn udp_address(&self) -> SocketAddr {
-		match self.address {
-			SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)),
-			SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())),
-		}
-	}
-}
-
-impl NodeEndpoint {
-	pub fn from_rlp(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
-		let tcp_port = try!(rlp.val_at::<u16>(2));
-		let udp_port = try!(rlp.val_at::<u16>(1));
-		let addr_bytes = try!(try!(rlp.at(0)).data());
-		let address = try!(match addr_bytes.len() {
-			4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
-			16 => unsafe {
-				let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
-				let o = from_raw_parts(o, 8);
-				Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
-			},
-			_ => Err(DecoderError::RlpInconsistentLengthAndData)
-		});
-		Ok(NodeEndpoint { address: address, udp_port: udp_port })
-	}
-
-	pub fn to_rlp(&self, rlp: &mut RlpStream) {
-		match self.address {
-			SocketAddr::V4(a) => {
-				rlp.append(&(&a.ip().octets()[..]));
-			}
-			SocketAddr::V6(a) => unsafe {
-				let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
-				rlp.append(&from_raw_parts(o, 16));
-			}
-		};
-		rlp.append(&self.udp_port);
-		rlp.append(&self.address.port());
-	}
-
-	pub fn to_rlp_list(&self, rlp: &mut RlpStream) {
-		rlp.begin_list(3);
-		self.to_rlp(rlp);
-	}
-
-	pub fn is_valid(&self) -> bool {
-		self.udp_port != 0 && self.address.port() != 0 &&
-		match self.address {
-			SocketAddr::V4(a) => !a.ip().is_unspecified(),
-			SocketAddr::V6(a) => !a.ip().is_unspecified()
-		}
-	}
-}
-
-impl FromStr for NodeEndpoint {
-	type Err = UtilError;
-
-	/// Create endpoint from string. Performs name resolution if given a host name.
-	fn from_str(s: &str) -> Result<NodeEndpoint, UtilError> {
-		let address = s.to_socket_addrs().map(|mut i| i.next());
-		match address {
-			Ok(Some(a)) => Ok(NodeEndpoint {
-				address: a,
-				udp_port: a.port()
-			}),
-			Ok(_) => Err(UtilError::AddressResolve(None)),
-			Err(e) => Err(UtilError::AddressResolve(Some(e)))
-		}
-	}
-}
-
-#[derive(PartialEq, Eq, Copy, Clone)]
-pub enum PeerType {
-	Required,
-	Optional
-}
-
-pub struct Node {
-	pub id: NodeId,
-	pub endpoint: NodeEndpoint,
-	pub peer_type: PeerType,
-	pub last_attempted: Option<Tm>,
-}
-
-impl Node {
-	pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
-		Node {
-			id: id,
-			endpoint: endpoint,
-			peer_type: PeerType::Optional,
-			last_attempted: None,
-		}
-	}
-}
-
-impl FromStr for Node {
-	type Err = UtilError;
-	fn from_str(s: &str) -> Result<Self, Self::Err> {
-		let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" {
-			(try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..])))
-		}
-		else {
-			(NodeId::new(), try!(NodeEndpoint::from_str(s)))
-		};
-
-		Ok(Node {
-			id: id,
-			endpoint: endpoint,
-			peer_type: PeerType::Optional,
-			last_attempted: None,
-		})
-	}
-}
-
-impl PartialEq for Node {
-	fn eq(&self, other: &Self) -> bool {
-		self.id == other.id
-	}
-}
-impl Eq for Node {}
-
-impl Hash for Node {
-	fn hash<H>(&self, state: &mut H) where H: Hasher {
-		self.id.hash(state)
-	}
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use std::str::FromStr;
-	use std::net::*;
-	use hash::*;
-
-	#[test]
-	fn endpoint_parse() {
-		let endpoint = NodeEndpoint::from_str("123.99.55.44:7770");
-		assert!(endpoint.is_ok());
-		let v4 = match endpoint.unwrap().address {
-			SocketAddr::V4(v4address) => v4address,
-			_ => panic!("should ve v4 address")
-		};
-		assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4);
-	}
-
-	#[test]
-	fn node_parse() {
-		let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
-		assert!(node.is_ok());
-		let node = node.unwrap();
-		let v4 = match node.endpoint.address {
-			SocketAddr::V4(v4address) => v4address,
-			_ => panic!("should ve v4 address")
-		};
-		assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4);
-		assert_eq!(
-			H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(),
-			node.id);
-	}
-}
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index d93057eb3..a3ee57481 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -14,11 +14,161 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
+use std::mem;
+use std::slice::from_raw_parts;
+use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
+use std::hash::{Hash, Hasher};
+use std::str::{FromStr};
 use std::collections::HashMap;
-use std::collections::hash_map::Values;
-use network::node::*;
+use hash::*;
+use rlp::*;
+use time::Tm;
+use error::*;
 use network::discovery::TableUpdates;
 
+/// Node public key
+pub type NodeId = H512;
+
+#[derive(Debug, Clone)]
+/// Node address info
+pub struct NodeEndpoint {
+	/// IP(V4 or V6) address
+	pub address: SocketAddr,
+	/// Conneciton port.
+	pub udp_port: u16
+}
+
+impl NodeEndpoint {
+	pub fn udp_address(&self) -> SocketAddr {
+		match self.address {
+			SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)),
+			SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())),
+		}
+	}
+}
+
+impl NodeEndpoint {
+	pub fn from_rlp(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
+		let tcp_port = try!(rlp.val_at::<u16>(2));
+		let udp_port = try!(rlp.val_at::<u16>(1));
+		let addr_bytes = try!(try!(rlp.at(0)).data());
+		let address = try!(match addr_bytes.len() {
+			4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
+			16 => unsafe {
+				let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
+				let o = from_raw_parts(o, 8);
+				Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
+			},
+			_ => Err(DecoderError::RlpInconsistentLengthAndData)
+		});
+		Ok(NodeEndpoint { address: address, udp_port: udp_port })
+	}
+
+	pub fn to_rlp(&self, rlp: &mut RlpStream) {
+		match self.address {
+			SocketAddr::V4(a) => {
+				rlp.append(&(&a.ip().octets()[..]));
+			}
+			SocketAddr::V6(a) => unsafe {
+				let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
+				rlp.append(&from_raw_parts(o, 16));
+			}
+		};
+		rlp.append(&self.udp_port);
+		rlp.append(&self.address.port());
+	}
+
+	pub fn to_rlp_list(&self, rlp: &mut RlpStream) {
+		rlp.begin_list(3);
+		self.to_rlp(rlp);
+	}
+
+	pub fn is_valid(&self) -> bool {
+		self.udp_port != 0 && self.address.port() != 0 &&
+		match self.address {
+			SocketAddr::V4(a) => !a.ip().is_unspecified(),
+			SocketAddr::V6(a) => !a.ip().is_unspecified()
+		}
+	}
+}
+
+impl FromStr for NodeEndpoint {
+	type Err = UtilError;
+
+	/// Create endpoint from string. Performs name resolution if given a host name.
+	fn from_str(s: &str) -> Result<NodeEndpoint, UtilError> {
+		let address = s.to_socket_addrs().map(|mut i| i.next());
+		match address {
+			Ok(Some(a)) => Ok(NodeEndpoint {
+				address: a,
+				udp_port: a.port()
+			}),
+			Ok(_) => Err(UtilError::AddressResolve(None)),
+			Err(e) => Err(UtilError::AddressResolve(Some(e)))
+		}
+	}
+}
+
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub enum PeerType {
+	_Required,
+	Optional
+}
+
+pub struct Node {
+	pub id: NodeId,
+	pub endpoint: NodeEndpoint,
+	pub peer_type: PeerType,
+	pub failures: u32,
+	pub last_attempted: Option<Tm>,
+}
+
+impl Node {
+	pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
+		Node {
+			id: id,
+			endpoint: endpoint,
+			peer_type: PeerType::Optional,
+			failures: 0,
+			last_attempted: None,
+		}
+	}
+}
+
+impl FromStr for Node {
+	type Err = UtilError;
+	fn from_str(s: &str) -> Result<Self, Self::Err> {
+		let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" {
+			(try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..])))
+		}
+		else {
+			(NodeId::new(), try!(NodeEndpoint::from_str(s)))
+		};
+
+		Ok(Node {
+			id: id,
+			endpoint: endpoint,
+			peer_type: PeerType::Optional,
+			last_attempted: None,
+			failures: 0,
+		})
+	}
+}
+
+impl PartialEq for Node {
+	fn eq(&self, other: &Self) -> bool {
+		self.id == other.id
+	}
+}
+impl Eq for Node {}
+
+impl Hash for Node {
+	fn hash<H>(&self, state: &mut H) where H: Hasher {
+		self.id.hash(state)
+	}
+}
+
+/// Node table backed by disk file.
 pub struct NodeTable {
 	nodes: HashMap<NodeId, Node>
 }
@@ -30,18 +180,24 @@ impl NodeTable {
 		}
 	}
 
+	/// Add a node to table
 	pub fn add_node(&mut self, node: Node) {
 		self.nodes.insert(node.id.clone(), node);
 	}
 
-	pub fn nodes(&self) -> Values<NodeId, Node> {
-		self.nodes.values()
+	/// Returns node ids sorted by number of failures
+	pub fn nodes(&self) -> Vec<NodeId> {
+		let mut refs: Vec<&Node> = self.nodes.values().collect();
+		refs.sort_by(|a, b| a.failures.cmp(&b.failures));
+		refs.iter().map(|n| n.id.clone()).collect()
 	}
 
+	/// Get particular node
 	pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
 		self.nodes.get_mut(id)
 	}
 
+	/// Apply table changes coming from discovery
 	pub fn update(&mut self, mut update: TableUpdates) {
 		for (_, node) in update.added.drain() {
 			let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone()));
@@ -52,4 +208,43 @@ impl NodeTable {
 		}
 	}
 
+	pub fn note_failure(&mut self, id: &NodeId) {
+		if let Some(node) = self.nodes.get_mut(id) {
+			node.failures += 1;
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use std::str::FromStr;
+	use std::net::*;
+	use hash::*;
+
+	#[test]
+	fn endpoint_parse() {
+		let endpoint = NodeEndpoint::from_str("123.99.55.44:7770");
+		assert!(endpoint.is_ok());
+		let v4 = match endpoint.unwrap().address {
+			SocketAddr::V4(v4address) => v4address,
+			_ => panic!("should ve v4 address")
+		};
+		assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4);
+	}
+
+	#[test]
+	fn node_parse() {
+		let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
+		assert!(node.is_ok());
+		let node = node.unwrap();
+		let v4 = match node.endpoint.address {
+			SocketAddr::V4(v4address) => v4address,
+			_ => panic!("should ve v4 address")
+		};
+		assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4);
+		assert_eq!(
+			H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(),
+			node.id);
+	}
 }
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 19e2cf08e..3b49a8f5e 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -23,7 +23,7 @@ use error::*;
 use io::{IoContext, StreamToken};
 use network::error::{NetworkError, DisconnectReason};
 use network::host::*;
-use network::node::NodeId;
+use network::node_table::NodeId;
 use time;
 
 const PING_TIMEOUT_SEC: u64 = 30;

From 9768fddb19e76a82bbee4c071d6fd4b88e181fe7 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 01:05:54 +0100
Subject: [PATCH 04/45] Homestead block set to 1100000

---
 ethcore/res/ethereum/frontier.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json
index 301441958..6e31a2fce 100644
--- a/ethcore/res/ethereum/frontier.json
+++ b/ethcore/res/ethereum/frontier.json
@@ -3,7 +3,7 @@
 	"engineName": "Ethash",
 	"params": {
 		"accountStartNonce": "0x00",
-		"frontierCompatibilityModeLimit": "0xf4240",
+		"frontierCompatibilityModeLimit": "0x10c8e0",
 		"maximumExtraDataSize": "0x20",
 		"tieBreakingGas": false,
 		"minGasLimit": "0x1388",

From 2d89708ea8cc034bc625df68c02ff6511fbfce90 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 02:11:55 +0100
Subject: [PATCH 05/45] Reduced thread contention

---
 util/src/network/host.rs | 91 ++++++++++++++++++++++++----------------
 1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 321e965ec..5c08ad5c8 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -215,7 +215,8 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 
 	/// Send a packet over the network to another peer.
 	pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
-		if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() {
+		let connection = { self.connections.read().unwrap().get(peer).cloned() };
+		if let Some(connection) = connection {
 			match *connection.lock().unwrap().deref_mut() {
 				ConnectionEntry::Session(ref mut s) => {
 					s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| {
@@ -264,7 +265,8 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 
 	/// Returns peer identification string
 	pub fn peer_info(&self, peer: PeerId) -> String {
-		if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() {
+		let connection = { self.connections.read().unwrap().get(peer).cloned() };
+		if let Some(connection) = connection {
 			if let ConnectionEntry::Session(ref s) = *connection.lock().unwrap().deref() {
 				return s.info.client_version.clone()
 			}
@@ -525,7 +527,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	fn connection_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
 		let mut create_session = false;
 		let mut kill = false;
-		if let Some(connection) = self.connections.read().unwrap().get(token).cloned() {
+		let connection = { self.connections.read().unwrap().get(token).cloned() };
+		if let Some(connection) = connection {
 			match *connection.lock().unwrap().deref_mut() {
 				ConnectionEntry::Handshake(ref mut h) => {
 					match h.writable(io, &self.info.read().unwrap()) {
@@ -569,7 +572,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let mut packet_data: Option<(ProtocolId, PacketId, Vec<u8>)> = None;
 		let mut create_session = false;
 		let mut kill = false;
-		if let Some(connection) = self.connections.read().unwrap().get(token).cloned() {
+		let connection = { self.connections.read().unwrap().get(token).cloned() };
+		if let Some(connection) = connection {
 			match *connection.lock().unwrap().deref_mut() {
 				ConnectionEntry::Handshake(ref mut h) => {
 					if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
@@ -628,20 +632,28 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 
 	fn start_session(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
 		let mut connections = self.connections.write().unwrap();
-		if connections.get(token).is_none() {
-			return; // handshake expired
+		let replace = { 
+			let connection = { connections.get(token).cloned() };
+			if let Some(connection) = connection {
+				match *connection.lock().unwrap().deref_mut() {
+					ConnectionEntry::Handshake(_) => true,
+					_ => false,
+				}
+			} else { false }
+		};
+		if replace {
+			connections.replace_with(token, |c| {
+				match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() {
+					ConnectionEntry::Handshake(h) => {
+						let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error");
+						io.update_registration(token).expect("Error updating session registration");
+						self.stats.inc_sessions();
+						Some(Arc::new(Mutex::new(ConnectionEntry::Session(session))))
+					},
+					_ => { None } // handshake expired
+				}
+			}).ok();
 		}
-		connections.replace_with(token, |c| {
-			match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() {
-				ConnectionEntry::Handshake(h) => {
-					let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error");
-					io.update_registration(token).expect("Error updating session registration");
-					self.stats.inc_sessions();
-					Some(Arc::new(Mutex::new(ConnectionEntry::Session(session))))
-				},
-				_ => { None } // handshake expired
-			}
-		}).ok();
 	}
 
 	fn connection_timeout(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
@@ -650,15 +662,14 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 
 	fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>, remote: bool) {
 		let mut to_disconnect: Vec<ProtocolId> = Vec::new();
+		let mut failure_id = None;
 		{
 			let mut connections = self.connections.write().unwrap();
 			if let Some(connection) = connections.get(token).cloned() {
 				match *connection.lock().unwrap().deref_mut() {
 					ConnectionEntry::Handshake(ref h) => {
 						connections.remove(token);
-						if remote {
-							self.nodes.write().unwrap().note_failure(h.id());
-						}
+						failure_id = Some(h.id().clone());
 					},
 					ConnectionEntry::Session(ref mut s) if s.is_ready() => {
 						for (p, _) in self.handlers.read().unwrap().iter() {
@@ -667,15 +678,18 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 							}
 						}
 						connections.remove(token);
-						if remote {
-							self.nodes.write().unwrap().note_failure(s.id());
-						}
+						failure_id = Some(s.id().clone());
 					},
 					_ => {},
 				}
 			}
 			io.deregister_stream(token).expect("Error deregistering stream");
 		}
+		if let Some(id) = failure_id {
+			if remote {
+				self.nodes.write().unwrap().note_failure(&id);
+			}
+		}
 		for p in to_disconnect {
 			let h = self.handlers.read().unwrap().get(p).unwrap().clone();
 			h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token);
@@ -683,18 +697,20 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn update_nodes(&self, io: &IoContext<NetworkIoMessage<Message>>, node_changes: TableUpdates) {
-		let connections = self.connections.write().unwrap();
 		let mut to_remove: Vec<PeerId> = Vec::new();
-		for c in connections.iter() {
-			match *c.lock().unwrap().deref_mut() {
-				ConnectionEntry::Handshake(ref h) => {
-					if node_changes.removed.contains(&h.id()) {
-						to_remove.push(h.token());
+		{
+			let connections = self.connections.write().unwrap();
+			for c in connections.iter() {
+				match *c.lock().unwrap().deref_mut() {
+					ConnectionEntry::Handshake(ref h) => {
+						if node_changes.removed.contains(&h.id()) {
+							to_remove.push(h.token());
+						}
 					}
-				}
-				ConnectionEntry::Session(ref s) => {
-					if node_changes.removed.contains(&s.id()) {
-						to_remove.push(s.token());
+					ConnectionEntry::Session(ref s) => {
+						if node_changes.removed.contains(&s.id()) {
+							to_remove.push(s.token());
+						}
 					}
 				}
 			}
@@ -804,7 +820,8 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 				io.register_timer(handler_token, *delay).expect("Error registering timer");
 			},
 			NetworkIoMessage::Disconnect(ref peer) => {
-				if let Some(connection) = self.connections.read().unwrap().get(*peer).cloned() {
+				let connection = { self.connections.read().unwrap().get(*peer).cloned() };
+				if let Some(connection) = connection {
 					match *connection.lock().unwrap().deref_mut() {
 						ConnectionEntry::Handshake(_) => {},
 						ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } 
@@ -823,7 +840,8 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop<IoManager<NetworkIoMessage<Message>>>) {
 		match stream {
 			FIRST_CONNECTION ... LAST_CONNECTION => {
-				if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() {
+				let connection = { self.connections.read().unwrap().get(stream).cloned() };
+				if let Some(connection) = connection {
 					match *connection.lock().unwrap().deref() {
 						ConnectionEntry::Handshake(ref h) => h.register_socket(reg, event_loop).expect("Error registering socket"),
 						ConnectionEntry::Session(_) => warn!("Unexpected session stream registration")
@@ -857,7 +875,8 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn update_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop<IoManager<NetworkIoMessage<Message>>>) {
 		match stream {
 			FIRST_CONNECTION ... LAST_CONNECTION => {
-				if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() {
+				let connection = { self.connections.read().unwrap().get(stream).cloned() };
+				if let Some(connection) = connection { 
 					match *connection.lock().unwrap().deref() {
 						ConnectionEntry::Handshake(ref h) => h.update_socket(reg, event_loop).expect("Error updating socket"),
 						ConnectionEntry::Session(ref s) => s.update_socket(reg, event_loop).expect("Error updating socket"),

From 718646f943b1388fb68afa95f5e79aca13e53a93 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 11:34:59 +0100
Subject: [PATCH 06/45] Refactored host to use different containers for
 handshakes and sessions

---
 util/src/network/connection.rs |  10 +
 util/src/network/host.rs       | 435 +++++++++++++++++----------------
 util/src/network/session.rs    |   3 +-
 3 files changed, 233 insertions(+), 215 deletions(-)

diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs
index 44d429164..242e8935e 100644
--- a/util/src/network/connection.rs
+++ b/util/src/network/connection.rs
@@ -164,6 +164,11 @@ impl Connection {
 		self.token
 	}
 
+	/// Replace socket token 
+	pub fn set_token(&mut self, token: StreamToken) {
+		self.token = token;
+	}
+
 	/// Register this connection with the IO event loop.
 	pub fn register_socket<Host: Handler>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
 		trace!(target: "net", "connection register; token={:?}", reg);
@@ -243,6 +248,11 @@ impl EncryptedConnection {
 		self.connection.token
 	}
 
+	/// Replace socket token 
+	pub fn set_token(&mut self, token: StreamToken) {
+		self.connection.set_token(token);
+	}
+
 	/// Create an encrypted connection out of the handshake. Consumes a handshake object.
 	pub fn new(mut handshake: Handshake) -> Result<EncryptedConnection, UtilError> {
 		let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public));
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 5c08ad5c8..04dda02bd 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -20,6 +20,7 @@ use std::hash::{Hasher};
 use std::str::{FromStr};
 use std::sync::*;
 use std::ops::*;
+use std::cmp::min;
 use mio::*;
 use mio::tcp::*;
 use target_info::Target;
@@ -41,9 +42,10 @@ use network::discovery::{Discovery, TableUpdates, NodeEntry};
 type Slab<T> = ::slab::Slab<T, usize>;
 
 const _DEFAULT_PORT: u16 = 30304;
-const MAX_CONNECTIONS: usize = 1024;
+const MAX_SESSIONS: usize = 1024;
+const MAX_HANDSHAKES: usize = 256;
+const MAX_HANDSHAKES_PER_ROUND: usize = 64;
 const MAINTENANCE_TIMEOUT: u64 = 1000;
-const MAX_HANDSHAKES: usize = 100;
 
 #[derive(Debug)]
 /// Network service configuration
@@ -132,13 +134,16 @@ impl NetworkConfiguration {
 }
 
 // Tokens
-const TCP_ACCEPT: usize = MAX_CONNECTIONS + 1;
-const IDLE: usize = MAX_CONNECTIONS + 2;
-const DISCOVERY: usize = MAX_CONNECTIONS + 3;
-const DISCOVERY_REFRESH: usize = MAX_CONNECTIONS + 4;
-const DISCOVERY_ROUND: usize = MAX_CONNECTIONS + 5;
-const FIRST_CONNECTION: usize = 0;
-const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1;
+const TCP_ACCEPT: usize = LAST_HANDSHAKE + 1;
+const IDLE: usize = LAST_HANDSHAKE + 2;
+const DISCOVERY: usize = LAST_HANDSHAKE + 3;
+const DISCOVERY_REFRESH: usize = LAST_HANDSHAKE + 4;
+const DISCOVERY_ROUND: usize = LAST_HANDSHAKE + 5;
+const FIRST_SESSION: usize = 0;
+const LAST_SESSION: usize = FIRST_SESSION + MAX_SESSIONS - 1;
+const FIRST_HANDSHAKE: usize = LAST_SESSION + 1;
+const LAST_HANDSHAKE: usize = FIRST_HANDSHAKE + MAX_HANDSHAKES - 1;
+const USER_TIMER: usize = LAST_HANDSHAKE + 256;
 
 /// Protocol handler level packet id
 pub type PacketId = u8;
@@ -196,7 +201,7 @@ impl Encodable for CapabilityInfo {
 pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, 's {
 	io: &'s IoContext<NetworkIoMessage<Message>>,
 	protocol: ProtocolId,
-	connections: Arc<RwLock<Slab<SharedConnectionEntry>>>,
+	sessions: Arc<RwLock<Slab<SharedSession>>>,
 	session: Option<StreamToken>,
 }
 
@@ -204,28 +209,23 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 	/// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler.
 	fn new(io: &'s IoContext<NetworkIoMessage<Message>>, 
 		protocol: ProtocolId, 
-		session: Option<StreamToken>, connections: Arc<RwLock<Slab<SharedConnectionEntry>>>) -> NetworkContext<'s, Message> {
+		session: Option<StreamToken>, sessions: Arc<RwLock<Slab<SharedSession>>>) -> NetworkContext<'s, Message> {
 		NetworkContext {
 			io: io,
 			protocol: protocol,
 			session: session,
-			connections: connections,
+			sessions: sessions,
 		}
 	}
 
 	/// Send a packet over the network to another peer.
 	pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
-		let connection = { self.connections.read().unwrap().get(peer).cloned() };
-		if let Some(connection) = connection {
-			match *connection.lock().unwrap().deref_mut() {
-				ConnectionEntry::Session(ref mut s) => {
-					s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| {
+		let session = { self.sessions.read().unwrap().get(peer).cloned() };
+		if let Some(session) = session {
+			session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| {
 						warn!(target: "net", "Send error: {:?}", e);
 					}); //TODO: don't copy vector data
-					try!(self.io.update_registration(peer));
-				},
-				_ => warn!(target: "net", "Send: Peer is not connected yet")
-			}
+			try!(self.io.update_registration(peer));
 		} else  {
 			trace!(target: "net", "Send: Peer no longer exist")
 		}
@@ -265,11 +265,9 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 
 	/// Returns peer identification string
 	pub fn peer_info(&self, peer: PeerId) -> String {
-		let connection = { self.connections.read().unwrap().get(peer).cloned() };
-		if let Some(connection) = connection {
-			if let ConnectionEntry::Session(ref s) = *connection.lock().unwrap().deref() {
-				return s.info.client_version.clone()
-			}
+		let session = { self.sessions.read().unwrap().get(peer).cloned() };
+		if let Some(session) = session {
+			return session.lock().unwrap().info.client_version.clone()
 		}
 		"unknown".to_owned()
 	}
@@ -311,12 +309,8 @@ impl HostInfo {
 	}
 }
 
-enum ConnectionEntry {
-	Handshake(Handshake),
-	Session(Session)
-}
-
-type SharedConnectionEntry = Arc<Mutex<ConnectionEntry>>;
+type SharedSession = Arc<Mutex<Session>>;
+type SharedHandshake = Arc<Mutex<Handshake>>;
 
 #[derive(Copy, Clone)]
 struct ProtocolTimer {
@@ -328,7 +322,8 @@ struct ProtocolTimer {
 pub struct Host<Message> where Message: Send + Sync + Clone {
 	pub info: RwLock<HostInfo>,
 	tcp_listener: Mutex<TcpListener>,
-	connections: Arc<RwLock<Slab<SharedConnectionEntry>>>,
+	handshakes: Arc<RwLock<Slab<SharedHandshake>>>,
+	sessions: Arc<RwLock<Slab<SharedSession>>>,
 	discovery: Mutex<Discovery>,
 	nodes: RwLock<NodeTable>,
 	handlers: RwLock<HashMap<ProtocolId, Arc<NetworkProtocolHandler<Message>>>>,
@@ -361,11 +356,12 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}),
 			discovery: Mutex::new(discovery),
 			tcp_listener: Mutex::new(tcp_listener),
-			connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))),
+			handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))),
+			sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))),
 			nodes: RwLock::new(NodeTable::new(path)),
 			handlers: RwLock::new(HashMap::new()),
 			timers: RwLock::new(HashMap::new()),
-			timer_counter: RwLock::new(LAST_CONNECTION + 1),
+			timer_counter: RwLock::new(USER_TIMER),
 			stats: Arc::new(NetworkStats::default()),
 		};
 		let port = host.info.read().unwrap().config.listen_address.port();
@@ -407,33 +403,28 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn have_session(&self, id: &NodeId) -> bool {
-		self.connections.read().unwrap().iter().any(|e| 
-			match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false  })
+		self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().info.id.eq(&id))
 	}
 
 	fn session_count(&self) -> usize {
-		self.connections.read().unwrap().iter().filter(|e| 
-			match *e.lock().unwrap().deref() { ConnectionEntry::Session(_) => true, _ => false  }).count()
+		self.sessions.read().unwrap().count()
 	}
 
 	fn connecting_to(&self, id: &NodeId) -> bool {
-		self.connections.read().unwrap().iter().any(|e| 
-			match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false  })
+		self.handshakes.read().unwrap().iter().any(|e| e.lock().unwrap().id.eq(&id))
 	}
 
 	fn handshake_count(&self) -> usize {
-		self.connections.read().unwrap().iter().filter(|e| 
-			match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(_) => true, _ => false  }).count()
+		self.handshakes.read().unwrap().count()
 	}
 
 	fn keep_alive(&self, io: &IoContext<NetworkIoMessage<Message>>) {
 		let mut to_kill = Vec::new();
-		for e in self.connections.write().unwrap().iter_mut() {
-			if let ConnectionEntry::Session(ref mut s) = *e.lock().unwrap().deref_mut() {
-				if !s.keep_alive(io) {
-					s.disconnect(DisconnectReason::PingTimeout);
-					to_kill.push(s.token());
-				}
+		for e in self.sessions.write().unwrap().iter_mut() {
+			let mut s = e.lock().unwrap();
+			if !s.keep_alive(io) {
+				s.disconnect(DisconnectReason::PingTimeout);
+				to_kill.push(s.token());
 			}
 		}
 		for p in to_kill {
@@ -443,8 +434,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 
 	fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
 		let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers };
-		let connections = self.session_count();
-		if connections >= ideal_peers as usize {
+		let session_count = self.session_count();
+		if session_count >= ideal_peers as usize {
 			return;
 		}
 
@@ -453,10 +444,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			return;
 		}
 
-
 		let nodes = { self.nodes.read().unwrap().nodes() };
-
-		for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)).take(MAX_HANDSHAKES - handshake_count) {
+		for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id))
+			.take(min(MAX_HANDSHAKES_PER_ROUND, MAX_HANDSHAKES - handshake_count)) {
 			self.connect_peer(&id, io);
 		}
 		debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count());
@@ -495,15 +485,15 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	#[allow(block_in_if_condition_stmt)]
 	fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext<NetworkIoMessage<Message>>) {
 		let nonce = self.info.write().unwrap().next_nonce();
-		let mut connections = self.connections.write().unwrap();
-		if connections.insert_with(|token| {
+		let mut handshakes = self.handshakes.write().unwrap();
+		if handshakes.insert_with(|token| {
 			let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake");
 			handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| {
 				debug!(target: "net", "Handshake create error: {:?}", e);
 			});
-			Arc::new(Mutex::new(ConnectionEntry::Handshake(handshake)))
+			Arc::new(Mutex::new(handshake))
 		}).is_none() {
-			warn!("Max connections reached");
+			warn!("Max handshakes reached");
 		}
 	}
 
@@ -523,35 +513,18 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener");
 	}
 
-	#[allow(single_match)]
-	fn connection_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
+	fn handshake_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
 		let mut create_session = false;
 		let mut kill = false;
-		let connection = { self.connections.read().unwrap().get(token).cloned() };
-		if let Some(connection) = connection {
-			match *connection.lock().unwrap().deref_mut() {
-				ConnectionEntry::Handshake(ref mut h) => {
-					match h.writable(io, &self.info.read().unwrap()) {
-						Err(e) => {
-							debug!(target: "net", "Handshake write error: {}:{:?}", token, e);
-							kill = true;
-						},
-						Ok(_) => ()
-					}
-					if h.done() {
-						create_session = true;
-					}
-				},
-				ConnectionEntry::Session(ref mut s) => {
-					match s.writable(io, &self.info.read().unwrap()) {
-						Err(e) => {
-							debug!(target: "net", "Session write error: {}:{:?}", token, e);
-							kill = true;
-						},
-						Ok(_) => ()
-					}
-					io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
-				}
+		let handshake = { self.handshakes.read().unwrap().get(token).cloned() };
+		if let Some(handshake) = handshake {
+			let mut h = handshake.lock().unwrap();
+			if let Err(e) = h.writable(io, &self.info.read().unwrap()) {
+				debug!(target: "net", "Handshake write error: {}:{:?}", token, e);
+				kill = true;
+			}
+			if h.done() {
+				create_session = true;
 			}
 		} 
 		if kill {
@@ -563,55 +536,40 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		}
 	}
 
+	fn session_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
+		let mut kill = false;
+		let session = { self.sessions.read().unwrap().get(token).cloned() };
+		if let Some(session) = session {
+			let mut s = session.lock().unwrap();
+			if let Err(e) = s.writable(io, &self.info.read().unwrap()) {
+				debug!(target: "net", "Session write error: {}:{:?}", token, e);
+				kill = true;
+			}
+			io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
+		} 
+		if kill {
+			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
+		}
+	}
+
 	fn connection_closed(&self, token: TimerToken, io: &IoContext<NetworkIoMessage<Message>>) {
 		self.kill_connection(token, io, true);
 	}
 
-	fn connection_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		let mut ready_data: Vec<ProtocolId> = Vec::new();
-		let mut packet_data: Option<(ProtocolId, PacketId, Vec<u8>)> = None;
+	fn handshake_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
 		let mut create_session = false;
 		let mut kill = false;
-		let connection = { self.connections.read().unwrap().get(token).cloned() };
-		if let Some(connection) = connection {
-			match *connection.lock().unwrap().deref_mut() {
-				ConnectionEntry::Handshake(ref mut h) => {
-					if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
-						debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
-						kill = true;
-					}
-					if h.done() {
-						create_session = true;
-					}
-				},
-				ConnectionEntry::Session(ref mut s) => {
-					match s.readable(io, &self.info.read().unwrap()) {
-						Err(e) => {
-							debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
-							kill = true;
-						},
-						Ok(SessionData::Ready) => {
-							for (p, _) in self.handlers.read().unwrap().iter() {
-								if s.have_capability(p)  {
-									ready_data.push(p);
-								}
-							}
-						},
-						Ok(SessionData::Packet {
-							data,
-							protocol,
-							packet_id,
-						}) => {
-							match self.handlers.read().unwrap().get(protocol) {
-								None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) },
-								Some(_) => packet_data = Some((protocol, packet_id, data)),
-							}
-						},
-						Ok(SessionData::None) => {},
-					}
-				}
+		let handshake = { self.handshakes.read().unwrap().get(token).cloned() };
+		if let Some(handshake) = handshake {
+			let mut h = handshake.lock().unwrap();
+			if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
+				debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
+				kill = true;
 			}
-		} 
+			if h.done() {
+				create_session = true;
+			}
+		}
 		if kill {
 			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
 			return;
@@ -619,40 +577,74 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			self.start_session(token, io);
 			io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
 		}
+		io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e));
+	}
+
+	fn session_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
+		let mut ready_data: Vec<ProtocolId> = Vec::new();
+		let mut packet_data: Option<(ProtocolId, PacketId, Vec<u8>)> = None;
+		let mut kill = false;
+		let session = { self.sessions.read().unwrap().get(token).cloned() };
+		if let Some(session) = session {
+			let mut s = session.lock().unwrap();
+			match s.readable(io, &self.info.read().unwrap()) {
+				Err(e) => {
+					debug!(target: "net", "Session read error: {}:{:?}", token, e);
+					kill = true;
+				},
+				Ok(SessionData::Ready) => {
+					for (p, _) in self.handlers.read().unwrap().iter() {
+						if s.have_capability(p)  {
+							ready_data.push(p);
+						}
+					}
+				},
+				Ok(SessionData::Packet {
+					data,
+					protocol,
+					packet_id,
+				}) => {
+					match self.handlers.read().unwrap().get(protocol) {
+						None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) },
+						Some(_) => packet_data = Some((protocol, packet_id, data)),
+					}
+				},
+				Ok(SessionData::None) => {},
+			}
+		} 
+		if kill {
+			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
+			return;
+		}
 		for p in ready_data {
 			let h = self.handlers.read().unwrap().get(p).unwrap().clone();
-			h.connected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token);
+			h.connected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token);
 		}
 		if let Some((p, packet_id, data)) = packet_data {
 			let h = self.handlers.read().unwrap().get(p).unwrap().clone();
-			h.read(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token, packet_id, &data[1..]);
+			h.read(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token, packet_id, &data[1..]);
 		}
 		io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e));
 	}
 
 	fn start_session(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		let mut connections = self.connections.write().unwrap();
-		let replace = { 
-			let connection = { connections.get(token).cloned() };
-			if let Some(connection) = connection {
-				match *connection.lock().unwrap().deref_mut() {
-					ConnectionEntry::Handshake(_) => true,
-					_ => false,
-				}
-			} else { false }
-		};
-		if replace {
-			connections.replace_with(token, |c| {
-				match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() {
-					ConnectionEntry::Handshake(h) => {
-						let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error");
-						io.update_registration(token).expect("Error updating session registration");
-						self.stats.inc_sessions();
-						Some(Arc::new(Mutex::new(ConnectionEntry::Session(session))))
-					},
-					_ => { None } // handshake expired
-				}
-			}).ok();
+		let mut handshakes = self.handshakes.write().unwrap();
+		if handshakes.get(token).is_none() {
+			return;
+		}
+		
+		// turn a handshake into a session
+		let mut sessions = self.sessions.write().unwrap();
+		let h = handshakes.remove(token).unwrap();
+		let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap();
+		let result = sessions.insert_with(move |session_token| {
+			let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error");
+			io.update_registration(session_token).expect("Error updating session registration");
+			self.stats.inc_sessions();
+			Arc::new(Mutex::new(session))
+		});
+		if result.is_none() {
+			warn!("Max sessions reached");
 		}
 	}
 
@@ -663,28 +655,32 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>, remote: bool) {
 		let mut to_disconnect: Vec<ProtocolId> = Vec::new();
 		let mut failure_id = None;
-		{
-			let mut connections = self.connections.write().unwrap();
-			if let Some(connection) = connections.get(token).cloned() {
-				match *connection.lock().unwrap().deref_mut() {
-					ConnectionEntry::Handshake(ref h) => {
-						connections.remove(token);
-						failure_id = Some(h.id().clone());
-					},
-					ConnectionEntry::Session(ref mut s) if s.is_ready() => {
+		match token {
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => {
+				let mut handshakes = self.handshakes.write().unwrap();
+				if let Some(handshake) = handshakes.get(token).cloned() {
+					failure_id = Some(handshake.lock().unwrap().id().clone());
+					handshakes.remove(token);
+				}
+			},
+			FIRST_SESSION ... LAST_SESSION => {
+				let mut sessions = self.sessions.write().unwrap();
+				if let Some(session) = sessions.get(token).cloned() {
+					let s = session.lock().unwrap();
+					if s.is_ready() {
 						for (p, _) in self.handlers.read().unwrap().iter() {
 							if s.have_capability(p)  {
 								to_disconnect.push(p);
 							}
 						}
-						connections.remove(token);
-						failure_id = Some(s.id().clone());
-					},
-					_ => {},
+					}
+					failure_id = Some(s.id().clone());
+					sessions.remove(token);
 				}
-			}
-			io.deregister_stream(token).expect("Error deregistering stream");
+			},
+			_ => {},
 		}
+		io.deregister_stream(token).expect("Error deregistering stream");
 		if let Some(id) = failure_id {
 			if remote {
 				self.nodes.write().unwrap().note_failure(&id);
@@ -692,25 +688,28 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		}
 		for p in to_disconnect {
 			let h = self.handlers.read().unwrap().get(p).unwrap().clone();
-			h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token);
+			h.disconnected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token);
 		}
 	}
 
 	fn update_nodes(&self, io: &IoContext<NetworkIoMessage<Message>>, node_changes: TableUpdates) {
 		let mut to_remove: Vec<PeerId> = Vec::new();
 		{
-			let connections = self.connections.write().unwrap();
-			for c in connections.iter() {
-				match *c.lock().unwrap().deref_mut() {
-					ConnectionEntry::Handshake(ref h) => {
-						if node_changes.removed.contains(&h.id()) {
-							to_remove.push(h.token());
-						}
+			{
+				let handshakes = self.handshakes.write().unwrap();
+				for c in handshakes.iter() {
+					let h = c.lock().unwrap();
+					if node_changes.removed.contains(&h.id()) {
+						to_remove.push(h.token());
 					}
-					ConnectionEntry::Session(ref s) => {
-						if node_changes.removed.contains(&s.id()) {
-							to_remove.push(s.token());
-						}
+				}
+			}
+			{
+				let sessions = self.sessions.write().unwrap();
+				for c in sessions.iter() {
+					let s = c.lock().unwrap();
+					if node_changes.removed.contains(&s.id()) {
+						to_remove.push(s.token());
 					}
 				}
 			}
@@ -735,14 +734,16 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn stream_hup(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		trace!(target: "net", "Hup: {}", stream);
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_closed(stream, io),
+			FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io),
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io),
 			_ => warn!(target: "net", "Unexpected hup"),
 		};
 	}
 
 	fn stream_readable(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io),
+			FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io),
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io),
 			DISCOVERY => {
 				if let Some(node_changes) = self.discovery.lock().unwrap().readable() {
 					self.update_nodes(io, node_changes);
@@ -756,7 +757,8 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 
 	fn stream_writable(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io),
+			FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io),
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io),
 			DISCOVERY => {
 				self.discovery.lock().unwrap().writable();
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
@@ -768,7 +770,8 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	fn timeout(&self, io: &IoContext<NetworkIoMessage<Message>>, token: TimerToken) {
 		match token {
 			IDLE => self.maintain_network(io),
-			FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io),
+			FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io),
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io),
 			DISCOVERY_REFRESH => {
 				self.discovery.lock().unwrap().refresh();
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
@@ -782,7 +785,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			_ => match self.timers.read().unwrap().get(&token).cloned() {
 				Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() {
 						None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) },
-						Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.connections.clone()), timer.token); }
+						Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.sessions.clone()), timer.token); }
 				},
 				None => { warn!("Unknown timer token: {}", token); } // timer is not registerd through us
 			}
@@ -797,7 +800,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 				ref versions
 			} => {
 				let h = handler.clone();
-				h.initialize(&NetworkContext::new(io, protocol, None, self.connections.clone()));
+				h.initialize(&NetworkContext::new(io, protocol, None, self.sessions.clone()));
 				self.handlers.write().unwrap().insert(protocol, h);
 				let mut info = self.info.write().unwrap();
 				for v in versions {
@@ -820,18 +823,15 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 				io.register_timer(handler_token, *delay).expect("Error registering timer");
 			},
 			NetworkIoMessage::Disconnect(ref peer) => {
-				let connection = { self.connections.read().unwrap().get(*peer).cloned() };
-				if let Some(connection) = connection {
-					match *connection.lock().unwrap().deref_mut() {
-						ConnectionEntry::Handshake(_) => {},
-						ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } 
-					}
+				let session = { self.sessions.read().unwrap().get(*peer).cloned() };
+				if let Some(session) = session {
+					session.lock().unwrap().disconnect(DisconnectReason::DisconnectRequested);
 				} 
 				self.kill_connection(*peer, io, false);
 			},
 			NetworkIoMessage::User(ref message) => {
 				for (p, h) in self.handlers.read().unwrap().iter() {
-					h.message(&NetworkContext::new(io, p, None, self.connections.clone()), &message);
+					h.message(&NetworkContext::new(io, p, None, self.sessions.clone()), &message);
 				}
 			}
 		}
@@ -839,14 +839,14 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 
 	fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop<IoManager<NetworkIoMessage<Message>>>) {
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => {
-				let connection = { self.connections.read().unwrap().get(stream).cloned() };
+			FIRST_SESSION ... LAST_SESSION => {
+				warn!("Unexpected session stream registration");
+			}
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => {
+				let connection = { self.handshakes.read().unwrap().get(stream).cloned() };
 				if let Some(connection) = connection {
-					match *connection.lock().unwrap().deref() {
-						ConnectionEntry::Handshake(ref h) => h.register_socket(reg, event_loop).expect("Error registering socket"),
-						ConnectionEntry::Session(_) => warn!("Unexpected session stream registration")
-					}
-				} else {} // expired
+					connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket");
+				}
 			}
 			DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"),
 			TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"),
@@ -856,16 +856,20 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 
 	fn deregister_stream(&self, stream: StreamToken, event_loop: &mut EventLoop<IoManager<NetworkIoMessage<Message>>>) {
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => {
-				let mut connections = self.connections.write().unwrap();
+			FIRST_SESSION ... LAST_SESSION => {
+				let mut connections = self.sessions.write().unwrap();
 				if let Some(connection) = connections.get(stream).cloned() {
-					match *connection.lock().unwrap().deref() {
-						ConnectionEntry::Handshake(ref h) => h.deregister_socket(event_loop).expect("Error deregistering socket"),
-						ConnectionEntry::Session(ref s) => s.deregister_socket(event_loop).expect("Error deregistering session socket"),
-					}
+					connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket");
 					connections.remove(stream);
-				} 
-			},
+				}
+			}
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => {
+				let mut connections = self.handshakes.write().unwrap();
+				if let Some(connection) = connections.get(stream).cloned() {
+					connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket");
+					connections.remove(stream);
+				}
+			}
 			DISCOVERY => (),
 			TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(),
 			_ => warn!("Unexpected stream deregistration")
@@ -874,14 +878,17 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 
 	fn update_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop<IoManager<NetworkIoMessage<Message>>>) {
 		match stream {
-			FIRST_CONNECTION ... LAST_CONNECTION => {
-				let connection = { self.connections.read().unwrap().get(stream).cloned() };
-				if let Some(connection) = connection { 
-					match *connection.lock().unwrap().deref() {
-						ConnectionEntry::Handshake(ref h) => h.update_socket(reg, event_loop).expect("Error updating socket"),
-						ConnectionEntry::Session(ref s) => s.update_socket(reg, event_loop).expect("Error updating socket"),
-					}
-				} else {} // expired
+			FIRST_SESSION ... LAST_SESSION => {
+				let connection = { self.sessions.read().unwrap().get(stream).cloned() };
+				if let Some(connection) = connection {
+					connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket");
+				}
+			}
+			FIRST_HANDSHAKE ... LAST_HANDSHAKE => {
+				let connection = { self.handshakes.read().unwrap().get(stream).cloned() };
+				if let Some(connection) = connection {
+					connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket");
+				}
 			}
 			DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"),
 			TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"),
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 3b49a8f5e..2763dfd82 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -108,7 +108,7 @@ const PACKET_LAST: u8 = 0x7f;
 
 impl Session {
 	/// Create a new session out of comepleted handshake. Consumes handshake object.
-	pub fn new<Message>(h: Handshake, _io: &IoContext<Message>, host: &HostInfo) -> Result<Session, UtilError> where Message: Send + Sync + Clone {
+	pub fn new(h: Handshake, token: StreamToken, host: &HostInfo) -> Result<Session, UtilError> {
 		let id = h.id.clone();
 		let connection = try!(EncryptedConnection::new(h));
 		let mut session = Session {
@@ -124,6 +124,7 @@ impl Session {
 			ping_time_ns: 0,
 			pong_time_ns: None,
 		};
+		session.connection.set_token(token);
 		try!(session.write_hello(host));
 		try!(session.send_ping());
 		Ok(session)

From 7503d6695a8ef22fa0aa4530745ceed95a260f63 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 11:54:08 +0100
Subject: [PATCH 07/45] Fixed panic on session creation

---
 util/src/network/host.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 04dda02bd..fe283e21a 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -635,7 +635,13 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		
 		// turn a handshake into a session
 		let mut sessions = self.sessions.write().unwrap();
-		let h = handshakes.remove(token).unwrap();
+		let mut h = handshakes.remove(token).unwrap();
+		// wait for other threads to stop using it
+		{
+			while Arc::get_mut(&mut h).is_none() {
+				h.lock().ok();
+			}
+		}
 		let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap();
 		let result = sessions.insert_with(move |session_token| {
 			let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error");

From dee375bfacc3010dadc97a8392f7f2d8632f8eac Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 12:11:18 +0100
Subject: [PATCH 08/45] Handle session creation error

---
 util/src/network/host.rs    | 9 ++++++++-
 util/src/network/session.rs | 8 ++++++--
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index fe283e21a..89cc4c225 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -643,8 +643,15 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		}
 		let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap();
+		let mut session = match Session::new(h, &self.info.read().unwrap()) {
+			Ok(s) => s,
+			Err(e) => {
+				warn!("Session creation error: {:?}", e);
+				return;
+			}
+		};
 		let result = sessions.insert_with(move |session_token| {
-			let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error");
+			session.set_token(session_token);
 			io.update_registration(session_token).expect("Error updating session registration");
 			self.stats.inc_sessions();
 			Arc::new(Mutex::new(session))
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 2763dfd82..f501e9c79 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -108,7 +108,7 @@ const PACKET_LAST: u8 = 0x7f;
 
 impl Session {
 	/// Create a new session out of comepleted handshake. Consumes handshake object.
-	pub fn new(h: Handshake, token: StreamToken, host: &HostInfo) -> Result<Session, UtilError> {
+	pub fn new(h: Handshake, host: &HostInfo) -> Result<Session, UtilError> {
 		let id = h.id.clone();
 		let connection = try!(EncryptedConnection::new(h));
 		let mut session = Session {
@@ -124,7 +124,6 @@ impl Session {
 			ping_time_ns: 0,
 			pong_time_ns: None,
 		};
-		session.connection.set_token(token);
 		try!(session.write_hello(host));
 		try!(session.send_ping());
 		Ok(session)
@@ -140,6 +139,11 @@ impl Session {
 		self.had_hello
 	}
 
+	/// Replace socket token 
+	pub fn set_token(&mut self, token: StreamToken) {
+		self.connection.set_token(token);
+	}
+
 	/// Readable IO handler. Returns packet data if available.
 	pub fn readable<Message>(&mut self, io: &IoContext<Message>, host: &HostInfo) -> Result<SessionData, UtilError>  where Message: Send + Sync + Clone {
 		match try!(self.connection.readable(io)) {

From fc7483ab87437e92751d676539eff93bcb774a7e Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 17:10:55 +0100
Subject: [PATCH 09/45] Propagate only one last hash for peers that are too far
 behind

---
 sync/src/chain.rs | 81 +++++++++++++++++++++++++++++------------------
 1 file changed, 51 insertions(+), 30 deletions(-)

diff --git a/sync/src/chain.rs b/sync/src/chain.rs
index 671e2241e..0de0bdcaf 100644
--- a/sync/src/chain.rs
+++ b/sync/src/chain.rs
@@ -155,7 +155,9 @@ struct PeerInfo {
 	/// Peer network id
 	network_id: U256,
 	/// Peer best block hash
-	latest: H256,
+	latest_hash: H256,
+	/// Peer best block number if known
+	latest_number: Option<BlockNumber>,
 	/// Peer total difficulty
 	difficulty: U256,
 	/// Type of data currenty being requested from peer.
@@ -282,7 +284,8 @@ impl ChainSync {
 			protocol_version: try!(r.val_at(0)),
 			network_id: try!(r.val_at(1)),
 			difficulty: try!(r.val_at(2)),
-			latest: try!(r.val_at(3)),
+			latest_hash: try!(r.val_at(3)),
+			latest_number: None,
 			genesis: try!(r.val_at(4)),
 			asking: PeerAsking::Nothing,
 			asking_blocks: Vec::new(),
@@ -290,7 +293,7 @@ impl ChainSync {
 			ask_time: 0f64,
 		};
 
-		trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest, peer.genesis);
+		trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis);
 
 		if self.peers.contains_key(&peer_id) {
 			warn!("Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id));
@@ -450,7 +453,8 @@ impl ChainSync {
  		let mut unknown = false;
 		{
 			let peer = self.peers.get_mut(&peer_id).unwrap();
-			peer.latest = header.hash();
+			peer.latest_hash = header.hash();
+			peer.latest_number = Some(header.number());
 		}
 		// TODO: Decompose block and add to self.headers and self.bodies instead
 		if header.number == From::from(self.current_base_block() + 1) {
@@ -516,7 +520,8 @@ impl ChainSync {
 					if d > max_height {
 						trace!(target: "sync", "New unknown block hash {:?}", h);
 						let peer = self.peers.get_mut(&peer_id).unwrap();
-						peer.latest = h.clone();
+						peer.latest_hash = h.clone();
+						peer.latest_number = Some(d);
 						max_height = d;
 					}
 				},
@@ -583,7 +588,7 @@ impl ChainSync {
 				trace!(target: "sync", "Waiting for block queue");
 				return;
 			}
-			(peer.latest.clone(), peer.difficulty.clone())
+			(peer.latest_hash.clone(), peer.difficulty.clone())
 		};
 
 		let td = io.chain().chain_info().pending_total_difficulty;
@@ -1117,25 +1122,28 @@ impl ChainSync {
 	}
 
 	/// returns peer ids that have less blocks than our chain
-	fn get_lagging_peers(&self, io: &SyncIo) -> Vec<PeerId> {
+	fn get_lagging_peers(&mut self, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> {
 		let chain = io.chain();
 		let chain_info = chain.chain_info();
 		let latest_hash = chain_info.best_block_hash;
 		let latest_number = chain_info.best_block_number;
-		self.peers.iter().filter(|&(_, peer_info)|
-			match io.chain().block_status(BlockId::Hash(peer_info.latest.clone())) {
+		self.peers.iter_mut().filter_map(|(&id, ref mut peer_info)|
+			match io.chain().block_status(BlockId::Hash(peer_info.latest_hash.clone())) {
 				BlockStatus::InChain => {
-					let peer_number = HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest.clone())).unwrap()).number();
-					peer_info.latest != latest_hash && latest_number > peer_number
+					if peer_info.latest_number.is_none() {
+						peer_info.latest_number = Some(HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest_hash.clone())).unwrap()).number());
+					}
+					if peer_info.latest_hash != latest_hash && latest_number > peer_info.latest_number.unwrap() {
+						Some((id, peer_info.latest_number.unwrap()))
+					} else { None }
 				},
-				_ => false
+				_ => None
 			})
-			.map(|(peer_id, _)| peer_id)
-			.cloned().collect::<Vec<PeerId>>()
+			.collect::<Vec<_>>()
 	}
 
 	/// propagades latest block to lagging peers
-	fn propagade_blocks(&mut self, local_best: &H256, io: &mut SyncIo) -> usize {
+	fn propagade_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize {
 		let updated_peers = {
 			let lagging_peers = self.get_lagging_peers(io);
 
@@ -1143,33 +1151,41 @@ impl ChainSync {
 			let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32;
 			let lucky_peers = match lagging_peers.len() {
 				0 ... MIN_PEERS_PROPAGATION => lagging_peers,
-				_ => lagging_peers.iter().filter(|_| ::rand::random::<u32>() < fraction).cloned().collect::<Vec<PeerId>>()
+				_ => lagging_peers.into_iter().filter(|_| ::rand::random::<u32>() < fraction).collect::<Vec<_>>()
 			};
 
 			// taking at max of MAX_PEERS_PROPAGATION
-			lucky_peers.iter().take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).cloned().collect::<Vec<PeerId>>()
+			lucky_peers.iter().map(|&(id, _)| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::<Vec<PeerId>>()
 		};
 
 		let mut sent = 0;
 		for peer_id in updated_peers {
 			let rlp = ChainSync::create_latest_block_rlp(io.chain());
 			self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp);
-			self.peers.get_mut(&peer_id).unwrap().latest = local_best.clone();
+			self.peers.get_mut(&peer_id).unwrap().latest_hash = local_best.clone();
+			self.peers.get_mut(&peer_id).unwrap().latest_number = Some(best_number);
 			sent = sent + 1;
 		}
 		sent
 	}
 
 	/// propagades new known hashes to all peers
-	fn propagade_new_hashes(&mut self, local_best: &H256, io: &mut SyncIo) -> usize {
+	fn propagade_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize {
 		let updated_peers = self.get_lagging_peers(io);
 		let mut sent = 0;
-		for peer_id in updated_peers {
-			sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &self.peers.get(&peer_id).unwrap().latest, &local_best) {
+		let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash();
+		for (peer_id, peer_number) in updated_peers {
+			let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone();
+			if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber {
+				// If we think peer is too far behind just end one latest hash
+				peer_best = last_parent.clone();
+			}
+			sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) {
 				Some(rlp) => {
 					{
 						let peer = self.peers.get_mut(&peer_id).unwrap();
-						peer.latest = local_best.clone();
+						peer.latest_hash = local_best.clone();
+						peer.latest_number = Some(best_number);
 					}
 					self.send_packet(io, peer_id, NEW_BLOCK_HASHES_PACKET, rlp);
 					1
@@ -1189,8 +1205,8 @@ impl ChainSync {
 	pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) {
 		let chain = io.chain().chain_info();
 		if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION {
-			let blocks = self.propagade_blocks(&chain.best_block_hash, io);
-			let hashes = self.propagade_new_hashes(&chain.best_block_hash, io);
+			let blocks = self.propagade_blocks(&chain.best_block_hash, chain.best_block_number, io);
+			let hashes = self.propagade_new_hashes(&chain.best_block_hash, chain.best_block_number, io);
 			if blocks != 0 || hashes != 0 {
 				trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
 			}
@@ -1322,7 +1338,8 @@ mod tests {
 				protocol_version: 0,
 				genesis: H256::zero(),
 				network_id: U256::zero(),
-				latest: peer_latest_hash,
+				latest_hash: peer_latest_hash,
+				latest_number: None,
 				difficulty: U256::zero(),
 				asking: PeerAsking::Nothing,
 				asking_blocks: Vec::<BlockNumber>::new(),
@@ -1337,7 +1354,7 @@ mod tests {
 		let mut client = TestBlockChainClient::new();
 		client.add_blocks(100, false);
 		let mut queue = VecDeque::new();
-		let sync = dummy_sync_with_peer(client.block_hash_delta_minus(10));
+		let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10));
 		let io = TestIo::new(&mut client, &mut queue, None);
 
 		let lagging_peers = sync.get_lagging_peers(&io);
@@ -1369,9 +1386,10 @@ mod tests {
 		let mut queue = VecDeque::new();
 		let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5));
 		let best_hash = client.chain_info().best_block_hash.clone();
+		let best_number = client.chain_info().best_block_number;
 		let mut io = TestIo::new(&mut client, &mut queue, None);
 
-		let peer_count = sync.propagade_new_hashes(&best_hash, &mut io);
+		let peer_count = sync.propagade_new_hashes(&best_hash, best_number, &mut io);
 
 		// 1 message should be send
 		assert_eq!(1, io.queue.len());
@@ -1388,9 +1406,10 @@ mod tests {
 		let mut queue = VecDeque::new();
 		let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5));
 		let best_hash = client.chain_info().best_block_hash.clone();
+		let best_number = client.chain_info().best_block_number;
 		let mut io = TestIo::new(&mut client, &mut queue, None);
 
-		let peer_count = sync.propagade_blocks(&best_hash, &mut io);
+		let peer_count = sync.propagade_blocks(&best_hash, best_number, &mut io);
 
 		// 1 message should be send
 		assert_eq!(1, io.queue.len());
@@ -1493,9 +1512,10 @@ mod tests {
 		let mut queue = VecDeque::new();
 		let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5));
 		let best_hash = client.chain_info().best_block_hash.clone();
+		let best_number = client.chain_info().best_block_number;
 		let mut io = TestIo::new(&mut client, &mut queue, None);
 
-		sync.propagade_new_hashes(&best_hash, &mut io);
+		sync.propagade_new_hashes(&best_hash, best_number, &mut io);
 
 		let data = &io.queue[0].data.clone();
 		let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data));
@@ -1511,9 +1531,10 @@ mod tests {
 		let mut queue = VecDeque::new();
 		let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5));
 		let best_hash = client.chain_info().best_block_hash.clone();
+		let best_number = client.chain_info().best_block_number;
 		let mut io = TestIo::new(&mut client, &mut queue, None);
 
-		sync.propagade_blocks(&best_hash, &mut io);
+		sync.propagade_blocks(&best_hash, best_number, &mut io);
 
 		let data = &io.queue[0].data.clone();
 		let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data));

From 61c52f15a3a2b81d718993668ba1a0a31e980ad2 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 17:42:03 +0100
Subject: [PATCH 10/45] Fixed panic on accessing expired node

---
 util/src/network/host.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 89cc4c225..454e8e802 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -82,7 +82,7 @@ impl NetworkConfiguration {
 			pin: false,
 			boot_nodes: Vec::new(),
 			use_secret: None,
-			ideal_peers: 10,
+			ideal_peers: 25,
 		}
 	}
 
@@ -467,9 +467,10 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let socket = {
 			let address = {
 				let mut nodes = self.nodes.write().unwrap();
-				let node = nodes.get_mut(id).unwrap();
-				node.last_attempted = Some(::time::now());
-				node.endpoint.address
+				if let Some(node) = nodes.get_mut(id) {
+					node.last_attempted = Some(::time::now());
+					node.endpoint.address
+				}
 			};
 			match TcpStream::connect(&address) {
 				Ok(socket) => socket,

From 38f4a06f1d248125e75ee07675a88a04f4d85617 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Sun, 14 Feb 2016 17:45:00 +0100
Subject: [PATCH 11/45] Fixed panic on accessing expired node

---
 util/src/network/host.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 454e8e802..7366e129b 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -471,6 +471,10 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 					node.last_attempted = Some(::time::now());
 					node.endpoint.address
 				}
+				else {
+					debug!("Connection to expired node aborted");
+					return;
+				}
 			};
 			match TcpStream::connect(&address) {
 				Ok(socket) => socket,
@@ -647,7 +651,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let mut session = match Session::new(h, &self.info.read().unwrap()) {
 			Ok(s) => s,
 			Err(e) => {
-				warn!("Session creation error: {:?}", e);
+				debug!("Session creation error: {:?}", e);
 				return;
 			}
 		};

From 186c7585d287a770ca0f45ed4f664e75093ff9b1 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 11:54:38 +0100
Subject: [PATCH 12/45] Node table persistency

---
 util/src/bytes.rs              |   4 +-
 util/src/hash.rs               |   7 +++
 util/src/io/service.rs         |   5 ++
 util/src/network/discovery.rs  |   2 +-
 util/src/network/node_table.rs | 111 ++++++++++++++++++++++++++++++++-
 util/src/sha3.rs               |   2 +-
 6 files changed, 124 insertions(+), 7 deletions(-)

diff --git a/util/src/bytes.rs b/util/src/bytes.rs
index 4923e6eb4..4e1a11e4d 100644
--- a/util/src/bytes.rs
+++ b/util/src/bytes.rs
@@ -170,8 +170,8 @@ pub trait BytesConvertable {
 	fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() }
 }
 
-impl<T> BytesConvertable for T where T: Deref<Target = [u8]> {
-	fn bytes(&self) -> &[u8] { self.deref() }
+impl<T> BytesConvertable for T where T: AsRef<[u8]> {
+	fn bytes(&self) -> &[u8] { self.as_ref() }
 }
 
 #[test]
diff --git a/util/src/hash.rs b/util/src/hash.rs
index 3e164098b..aefa7795b 100644
--- a/util/src/hash.rs
+++ b/util/src/hash.rs
@@ -86,6 +86,13 @@ macro_rules! impl_hash {
 			}
 		}
 
+		impl AsRef<[u8]> for $from {
+			#[inline]
+			fn as_ref(&self) -> &[u8] {
+				&self.0
+			}
+		}
+
 		impl DerefMut for $from {
 			#[inline]
 			fn deref_mut(&mut self) -> &mut [u8] {
diff --git a/util/src/io/service.rs b/util/src/io/service.rs
index c5f4a6072..83fa71b8a 100644
--- a/util/src/io/service.rs
+++ b/util/src/io/service.rs
@@ -256,6 +256,11 @@ impl<Message> Handler for IoManager<Message> where Message: Send + Clone + Sync
 			IoMessage::DeregisterStream { handler_id, token } => {
 				let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone();
 				handler.deregister_stream(token, event_loop);
+				// unregister a timer associated with the token (if any)
+				let timer_id = token + handler_id * TOKENS_PER_HANDLER;
+				if let Some(timer) = self.timers.write().unwrap().remove(&timer_id) {
+					event_loop.clear_timeout(timer.timeout);
+				}
 			},
 			IoMessage::UpdateStreamRegistration { handler_id, token } => {
 				let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone();
diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 9feef9c74..04c32cd33 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -209,7 +209,7 @@ impl Discovery {
 		rlp.append(&timestamp);
 
 		let bytes = rlp.drain();
-		let hash = bytes.sha3();
+		let hash = bytes.as_ref().sha3();
 		let signature = match ec::sign(&self.secret, &hash) {
 			Ok(s) => s,
 			Err(_) => {
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index a3ee57481..dea18ab63 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -20,11 +20,17 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr,
 use std::hash::{Hash, Hasher};
 use std::str::{FromStr};
 use std::collections::HashMap;
+use std::fmt::{Display, Formatter};
+use std::path::{PathBuf, Path};
+use std::fmt;
+use std::fs;
+use std::io::{Read, Write};
 use hash::*;
 use rlp::*;
 use time::Tm;
 use error::*;
 use network::discovery::TableUpdates;
+pub use rustc_serialize::json::Json;
 
 /// Node public key
 pub type NodeId = H512;
@@ -135,6 +141,17 @@ impl Node {
 	}
 }
 
+impl Display for Node {
+	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+		if self.endpoint.udp_port != self.endpoint.address.port() {
+			write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port);
+		} else {
+			write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address);
+		}
+		Ok(())
+	}
+}
+	
 impl FromStr for Node {
 	type Err = UtilError;
 	fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -170,13 +187,15 @@ impl Hash for Node {
 
 /// Node table backed by disk file.
 pub struct NodeTable {
-	nodes: HashMap<NodeId, Node>
+	nodes: HashMap<NodeId, Node>,
+	path: Option<String>,
 }
 
 impl NodeTable {
-	pub fn new(_path: Option<String>) -> NodeTable {
+	pub fn new(path: Option<String>) -> NodeTable {
 		NodeTable {
-			nodes: HashMap::new()
+			path: path.clone(),
+			nodes: NodeTable::load(path),
 		}
 	}
 
@@ -208,11 +227,86 @@ impl NodeTable {
 		}
 	}
 
+	/// Increase failure counte for a node
 	pub fn note_failure(&mut self, id: &NodeId) {
 		if let Some(node) = self.nodes.get_mut(id) {
 			node.failures += 1;
 		}
 	}
+
+	fn save(&self) {
+		if let Some(ref path) = self.path {
+			let mut path_buf = PathBuf::from(path);
+			path_buf.push("nodes.json");
+			let mut json = String::new();
+			json.push_str("{\n");
+			json.push_str("nodes: [\n");
+			let node_ids = self.nodes();
+			for i in 0 .. node_ids.len() {
+				let node = self.nodes.get(&node_ids[i]).unwrap();
+				json.push_str(&format!("\t{{ url: \"{}\", failures: {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) 
+			}
+			json.push_str("]\n");
+			json.push_str("}");
+			let mut file = match fs::File::create(path_buf.as_path()) {
+				Ok(file) => file,
+				Err(e) => {
+					warn!("Error creating node table file: {:?}", e);
+					return;
+				}
+			};
+			if let Err(e) = file.write(&json.into_bytes()) {
+					warn!("Error writing node table file: {:?}", e);
+			}
+		}
+	}
+
+	fn load(path: Option<String>) -> HashMap<NodeId, Node> {
+		let mut nodes: HashMap<NodeId, Node> = HashMap::new();
+		if let Some(path) = path {
+			let mut file = match fs::File::open(path.clone()) {
+				Ok(file) => file,
+				Err(e) => {
+					warn!("Error opening node table file: {:?}", e);
+					return nodes;
+				}
+			};
+			let mut buf = String::new();
+			match file.read_to_string(&mut buf) {
+				Ok(_) => {},
+				Err(e) => { 
+					warn!("Error reading node table file: {:?}", e);
+					return nodes;
+				}
+			}
+			let json = match Json::from_str(&buf) {
+				Ok(json) => json,
+				Err(e) => { 
+					warn!("Error parsing node table file: {:?}", e);
+					return nodes;
+				}
+			};
+			if let Some(list) = json.as_object().and_then(|o| o.get("nodes")).and_then(|n| n.as_array()) {
+				for n in list.iter().filter_map(|n| n.as_object()) {
+					if let Some(url) = n.get("url").and_then(|u| u.as_string()) {
+						if let Ok(mut node) = Node::from_str(url) {
+							if let Some(failures) = n.get("failures").and_then(|f| f.as_u64()) {
+								node.failures = failures as u32;
+							}
+							nodes.insert(node.id.clone(), node);
+						}
+					}
+				}
+			}
+		}
+		nodes
+	}
+}
+
+impl Drop for NodeTable {
+	fn drop(&mut self) {
+		self.save();
+	}
 }
 
 #[cfg(test)]
@@ -247,4 +341,15 @@ mod tests {
 			H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(),
 			node.id);
 	}
+
+	#[test]
+	fn table_failure_order() {
+		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
+		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
+		let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
+		let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		let id3 = H512::from_str("3979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		let mut table = NodeTable::new(None);
+	}
 }
diff --git a/util/src/sha3.rs b/util/src/sha3.rs
index 7e8382250..4079e8ba4 100644
--- a/util/src/sha3.rs
+++ b/util/src/sha3.rs
@@ -66,7 +66,7 @@ impl<T> Hashable for T where T: BytesConvertable {
 
 #[test]
 fn sha3_empty() {
-	assert_eq!([0u8; 0].sha3(), SHA3_EMPTY);
+	assert_eq!((&[0u8; 0]).sha3(), SHA3_EMPTY);
 }
 #[test]
 fn sha3_as() {

From cf45d5914a3e355210f4fad7744d00c8e7b7976a Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 14:39:56 +0100
Subject: [PATCH 13/45] Node table tests

---
 util/src/network/discovery.rs  |  2 +-
 util/src/network/mod.rs        |  2 +-
 util/src/network/node_table.rs | 95 ++++++++++++++++++++++++++++++----
 util/src/network/tests.rs      |  2 +-
 4 files changed, 88 insertions(+), 13 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 04c32cd33..c580c8507 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -254,7 +254,7 @@ impl Discovery {
 		}
 
 		let mut ret:Vec<NodeEntry> = Vec::new();
-		for (_, nodes) in found {
+		for nodes in found.values() {
 			ret.extend(nodes.iter().map(|&n| n.clone()));
 		}
 		ret
diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index 7d5aac8f7..c5066ff99 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -56,7 +56,7 @@
 //! }
 //!
 //! fn main () {
-//! 	let mut service = NetworkService::<MyMessage>::start(NetworkConfiguration::new()).expect("Error creating network service");
+//! 	let mut service = NetworkService::<MyMessage>::start(NetworkConfiguration::new_with_port(40412)).expect("Error creating network service");
 //! 	service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]);
 //!
 //! 	// Wait for quit condition
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index dea18ab63..2b02748b4 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -21,7 +21,7 @@ use std::hash::{Hash, Hasher};
 use std::str::{FromStr};
 use std::collections::HashMap;
 use std::fmt::{Display, Formatter};
-use std::path::{PathBuf, Path};
+use std::path::{PathBuf};
 use std::fmt;
 use std::fs;
 use std::io::{Read, Write};
@@ -144,9 +144,9 @@ impl Node {
 impl Display for Node {
 	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 		if self.endpoint.udp_port != self.endpoint.address.port() {
-			write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port);
+			try!(write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port));
 		} else {
-			write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address);
+			try!(write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address));
 		}
 		Ok(())
 	}
@@ -237,14 +237,18 @@ impl NodeTable {
 	fn save(&self) {
 		if let Some(ref path) = self.path {
 			let mut path_buf = PathBuf::from(path);
+			if let Err(e) = fs::create_dir_all(path_buf.as_path()) {
+				warn!("Error creating node table directory: {:?}", e);
+				return;
+			};
 			path_buf.push("nodes.json");
 			let mut json = String::new();
 			json.push_str("{\n");
-			json.push_str("nodes: [\n");
+			json.push_str("\"nodes\": [\n");
 			let node_ids = self.nodes();
 			for i in 0 .. node_ids.len() {
 				let node = self.nodes.get(&node_ids[i]).unwrap();
-				json.push_str(&format!("\t{{ url: \"{}\", failures: {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) 
+				json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) 
 			}
 			json.push_str("]\n");
 			json.push_str("}");
@@ -264,7 +268,9 @@ impl NodeTable {
 	fn load(path: Option<String>) -> HashMap<NodeId, Node> {
 		let mut nodes: HashMap<NodeId, Node> = HashMap::new();
 		if let Some(path) = path {
-			let mut file = match fs::File::open(path.clone()) {
+			let mut path_buf = PathBuf::from(path);
+			path_buf.push("nodes.json");
+			let mut file = match fs::File::open(path_buf.as_path()) {
 				Ok(file) => file,
 				Err(e) => {
 					warn!("Error opening node table file: {:?}", e);
@@ -344,12 +350,81 @@ mod tests {
 
 	#[test]
 	fn table_failure_order() {
-		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
-		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
-		let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
+		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
+		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
+		let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
 		let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
 		let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
-		let id3 = H512::from_str("3979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
 		let mut table = NodeTable::new(None);
+		table.add_node(node3);
+		table.add_node(node1);
+		table.add_node(node2);
+
+		table.note_failure(&id1);
+		table.note_failure(&id1);
+		table.note_failure(&id2);
+
+		let r = table.nodes();
+		assert_eq!(r[0][..], id3[..]);
+		assert_eq!(r[1][..], id2[..]);
+		assert_eq!(r[2][..], id1[..]);
+	}
+
+	use std::path::PathBuf;
+	use std::env;
+	use std::fs::{remove_dir_all};
+	// TODO: use common impl
+	pub struct RandomTempPath {
+		path: PathBuf
+	}
+
+	impl RandomTempPath {
+		pub fn new() -> RandomTempPath {
+			let mut dir = env::temp_dir();
+			dir.push(H32::random().hex());
+			RandomTempPath {
+				path: dir.clone()
+			}
+		}
+
+		pub fn as_path(&self) -> &PathBuf {
+			&self.path
+		}
+
+		pub fn as_str(&self) -> &str {
+			self.path.to_str().unwrap()
+		}
+	}
+
+	impl Drop for RandomTempPath {
+		fn drop(&mut self) {
+			if let Err(e) = remove_dir_all(self.as_path()) {
+				panic!("failed to remove temp directory, probably something failed to destroyed ({})", e);
+			}
+		}
+	}
+
+
+	#[test]
+	fn table_save_load() {
+		let temp_path = RandomTempPath::new();
+		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
+		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
+		let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
+		{
+			let mut table = NodeTable::new(Some(temp_path.as_str().to_owned()));
+			table.add_node(node1);
+			table.add_node(node2);
+			table.note_failure(&id2);
+		}
+
+		{
+			let table = NodeTable::new(Some(temp_path.as_str().to_owned()));
+			let r = table.nodes();
+			assert_eq!(r[0][..], id1[..]);
+			assert_eq!(r[1][..], id2[..]);
+		}
 	}
 }
diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs
index c1b59df9b..a3d5290c9 100644
--- a/util/src/network/tests.rs
+++ b/util/src/network/tests.rs
@@ -85,7 +85,7 @@ impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
 
 #[test]
 fn net_service() {
-	let mut service = NetworkService::<TestProtocolMessage>::start(NetworkConfiguration::new()).expect("Error creating network service");
+	let mut service = NetworkService::<TestProtocolMessage>::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service");
 	service.register_protocol(Arc::new(TestProtocol::default()), "myproto", &[1u8]).unwrap();
 }
 

From 4d40991c1a33effbc0b13fd2a0f71b6406118ff3 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 16:01:45 +0100
Subject: [PATCH 14/45] Discovery test

---
 util/src/network/discovery.rs | 60 +++++++++++++++++++++++++++++++----
 1 file changed, 54 insertions(+), 6 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index c580c8507..da8ce9e34 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -368,7 +368,7 @@ impl Discovery {
 		// TODO: validate pong packet
 		let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0))));
 		let timestamp: u64 = try!(rlp.val_at(2));
-		if timestamp > time::get_time().sec as u64 {
+		if timestamp < time::get_time().sec as u64 {
 			return Err(NetworkError::Expired);
 		}
 		let mut entry = NodeEntry { id: node.clone(), endpoint: dest };
@@ -386,7 +386,7 @@ impl Discovery {
 		trace!(target: "discovery", "Got FindNode from {:?}", &from);
 		let target: NodeId = try!(rlp.val_at(0));
 		let timestamp: u64 = try!(rlp.val_at(1));
-		if timestamp > time::get_time().sec as u64 {
+		if timestamp < time::get_time().sec as u64 {
 			return Err(NetworkError::Expired);
 		}
 
@@ -395,8 +395,8 @@ impl Discovery {
 		if nearest.is_empty() {
 			return Ok(None);
 		}
-		let mut rlp = RlpStream::new_list(cmp::min(limit, nearest.len()));
-		rlp.begin_list(1);
+		let mut rlp = RlpStream::new_list(1);
+		rlp.begin_list(cmp::min(limit, nearest.len()));
 		for n in 0 .. nearest.len() {
 			rlp.begin_list(4);
 			nearest[n].endpoint.to_rlp(&mut rlp);
@@ -404,8 +404,8 @@ impl Discovery {
 			if (n + 1) % limit == 0 || n == nearest.len() - 1 {
 				self.send_packet(PACKET_NEIGHBOURS, &from, &rlp.drain());
 				trace!(target: "discovery", "Sent {} Neighbours to {:?}", n, &from);
-				rlp = RlpStream::new_list(cmp::min(limit, nearest.len() - n));
-				rlp.begin_list(1);
+				rlp = RlpStream::new_list(1);
+				rlp.begin_list(cmp::min(limit, nearest.len() - n));
 			}
 		}
 		Ok(None)
@@ -422,6 +422,9 @@ impl Discovery {
 				continue;
 			}
 			let node_id: NodeId = try!(r.val_at(3));
+			if node_id == self.id {
+				continue;
+			}
 			let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint };
 			added.insert(node_id, entry.clone());
 			self.ping(&entry.endpoint);
@@ -476,3 +479,48 @@ impl Discovery {
 		Ok(())
 	}
 }
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use hash::*;
+	use std::net::*;
+	use network::node_table::*;
+	use crypto::KeyPair;
+	use std::str::FromStr;
+
+	#[test]
+	fn discovery() {
+		let key1 = KeyPair::create().unwrap();
+		let key2 = KeyPair::create().unwrap();
+		let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
+		let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
+		let mut discovery1 = Discovery::new(&key1, ep1.clone(), 0);
+		let mut discovery2 = Discovery::new(&key2, ep2.clone(), 0);
+
+		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
+		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
+		discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1. endpoint.clone() });
+		discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2. endpoint.clone() });
+
+		discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() });
+		discovery2.refresh();
+
+		for _ in 0 .. 10 {
+			while !discovery1.send_queue.is_empty() {
+				let datagramm = discovery1.send_queue.pop_front().unwrap();
+				if datagramm.address == ep2.address {
+					discovery2.on_packet(&datagramm.payload, ep1.address.clone()).ok();
+				}
+			}
+			while !discovery2.send_queue.is_empty() {
+				let datagramm = discovery2.send_queue.pop_front().unwrap();
+				if datagramm.address == ep1.address {
+					discovery1.on_packet(&datagramm.payload, ep2.address.clone()).ok();
+				}
+			}
+			discovery2.round();
+		}
+		assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3)
+	}
+}

From 0e1e80477a0efd49fac14a7e4ddfa6f86b216c8c Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 18:36:34 +0100
Subject: [PATCH 15/45] Save key to a file

---
 parity/main.rs                 |  4 +++
 util/src/network/host.rs       | 63 +++++++++++++++++++++++++++++++++-
 util/src/network/node_table.rs |  2 +-
 3 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/parity/main.rs b/parity/main.rs
index 460922b64..903b471c5 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -36,6 +36,7 @@ extern crate ethcore_rpc as rpc;
 
 use std::net::{SocketAddr};
 use std::env;
+use std::path::PathBuf;
 use rlog::{LogLevelFilter};
 use env_logger::LogBuilder;
 use ctrlc::CtrlC;
@@ -207,6 +208,9 @@ fn main() {
 	net_settings.listen_address = listen;
 	net_settings.public_address = public;
 	net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string"));
+	let mut net_path = PathBuf::from(&conf.path());
+	net_path.push("network");
+	net_settings.config_path = Some(net_path.to_str().unwrap().to_owned());
 
 	// Build client
 	let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap();
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 7366e129b..fb3bcee62 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -21,6 +21,9 @@ use std::str::{FromStr};
 use std::sync::*;
 use std::ops::*;
 use std::cmp::min;
+use std::path::{Path, PathBuf};
+use std::io::{Read, Write};
+use std::fs;
 use mio::*;
 use mio::tcp::*;
 use target_info::Target;
@@ -340,7 +343,19 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let addr = config.listen_address;
 		// Setup the server socket
 		let tcp_listener = TcpListener::bind(&addr).unwrap();
-		let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() };
+		let keys = if let Some(ref secret) = config.use_secret { 
+			KeyPair::from_secret(secret.clone()).unwrap() 
+		} else { 
+			config.config_path.clone().and_then(|ref p| load_key(&Path::new(&p)))
+				.map_or_else(|| {
+				let key = KeyPair::create().unwrap();
+				if let Some(path) = config.config_path.clone() {
+					save_key(&Path::new(&path), &key.secret());
+				}
+				key
+			},
+			|s| KeyPair::from_secret(s).expect("Error creating node secret key"))
+		};
 		let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() };
 		let discovery = Discovery::new(&keys, endpoint, DISCOVERY);
 		let path = config.config_path.clone();
@@ -914,3 +929,49 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 		}
 	}
 }
+
+fn save_key(path: &Path, key: &Secret) {
+	let mut path_buf = PathBuf::from(path);
+	if let Err(e) = fs::create_dir_all(path_buf.as_path()) {
+		warn!("Error creating key directory: {:?}", e);
+		return;
+	};
+	path_buf.push("key");
+	let mut file = match fs::File::create(path_buf.as_path()) {
+		Ok(file) => file,
+		Err(e) => {
+			warn!("Error creating key file: {:?}", e);
+			return;
+		}
+	};
+	if let Err(e) = file.write(&key.hex().into_bytes()) {
+		warn!("Error writing key file: {:?}", e);
+	}
+}
+
+fn load_key(path: &Path) -> Option<Secret> {
+	let mut path_buf = PathBuf::from(path);
+	path_buf.push("key");
+	let mut file = match fs::File::open(path_buf.as_path()) {
+		Ok(file) => file,
+		Err(e) => {
+			debug!("Error opening key file: {:?}", e);
+			return None;
+		}
+	};
+	let mut buf = String::new();
+	match file.read_to_string(&mut buf) {
+		Ok(_) => {},
+		Err(e) => { 
+			warn!("Error reading key file: {:?}", e);
+			return None;
+		}
+	}
+	match Secret::from_str(&buf) {
+		Ok(key) => Some(key),
+		Err(e) => { 
+			warn!("Error parsing key file: {:?}", e);
+			None
+		}
+	}
+}
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 2b02748b4..e5c47cafb 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -273,7 +273,7 @@ impl NodeTable {
 			let mut file = match fs::File::open(path_buf.as_path()) {
 				Ok(file) => file,
 				Err(e) => {
-					warn!("Error opening node table file: {:?}", e);
+					debug!("Error opening node table file: {:?}", e);
 					return nodes;
 				}
 			};

From 4b9c7f7517eb79e95d7c9326cca734508614b1e0 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 19:54:27 +0100
Subject: [PATCH 16/45] Add incoming connection to node table

---
 util/src/network/connection.rs | 11 +++++++++++
 util/src/network/host.rs       |  9 +++++++++
 util/src/network/node_table.rs |  5 ++++-
 util/src/network/session.rs    |  7 +++++++
 4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs
index 242e8935e..9e9304ca6 100644
--- a/util/src/network/connection.rs
+++ b/util/src/network/connection.rs
@@ -16,6 +16,7 @@
 
 use std::sync::Arc;
 use std::collections::VecDeque;
+use std::net::SocketAddr;
 use mio::{Handler, Token, EventSet, EventLoop, PollOpt, TryRead, TryWrite};
 use mio::tcp::*;
 use hash::*;
@@ -169,6 +170,11 @@ impl Connection {
 		self.token = token;
 	}
 
+	/// Get remote peer address
+	pub fn remote_addr(&self) -> io::Result<SocketAddr> {
+		self.socket.peer_addr()
+	}
+
 	/// Register this connection with the IO event loop.
 	pub fn register_socket<Host: Handler>(&self, reg: Token, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
 		trace!(target: "net", "connection register; token={:?}", reg);
@@ -253,6 +259,11 @@ impl EncryptedConnection {
 		self.connection.set_token(token);
 	}
 
+	/// Get remote peer address
+	pub fn remote_addr(&self) -> io::Result<SocketAddr> {
+		self.connection.remote_addr()
+	}
+
 	/// Create an encrypted connection out of the handshake. Consumes a handshake object.
 	pub fn new(mut handshake: Handshake) -> Result<EncryptedConnection, UtilError> {
 		let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public));
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index fb3bcee62..5f0bf19b9 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -663,6 +663,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			}
 		}
 		let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap();
+		let originated = h.originated;
 		let mut session = match Session::new(h, &self.info.read().unwrap()) {
 			Ok(s) => s,
 			Err(e) => {
@@ -674,6 +675,14 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			session.set_token(session_token);
 			io.update_registration(session_token).expect("Error updating session registration");
 			self.stats.inc_sessions();
+			if !originated {
+				// Add it no node table
+				if let Ok(address) = session.remote_addr() {
+					let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
+					self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
+					self.discovery.lock().unwrap().add_node(entry);
+				}
+			}
 			Arc::new(Mutex::new(session))
 		});
 		if result.is_none() {
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index e5c47cafb..40cc14743 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -200,7 +200,10 @@ impl NodeTable {
 	}
 
 	/// Add a node to table
-	pub fn add_node(&mut self, node: Node) {
+	pub fn add_node(&mut self, mut node: Node) {
+		// preserve failure counter
+		let failures = self.nodes.get(&node.id).map_or(0, |n| n.failures);
+		node.failures = failures;
 		self.nodes.insert(node.id.clone(), node);
 	}
 
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 5cda00567..f08fef385 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
+use std::net::SocketAddr;
+use std::io;
 use mio::*;
 use hash::*;
 use rlp::*;
@@ -144,6 +146,11 @@ impl Session {
 		self.connection.set_token(token);
 	}
 
+	/// Get remote peer address
+	pub fn remote_addr(&self) -> io::Result<SocketAddr> {
+		self.connection.remote_addr()
+	}
+
 	/// Readable IO handler. Returns packet data if available.
 	pub fn readable<Message>(&mut self, io: &IoContext<Message>, host: &HostInfo) -> Result<SessionData, UtilError>  where Message: Send + Sync + Clone {
 		match try!(self.connection.readable(io)) {

From 01a83e603140e82faf9586c4c824fececa69a791 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 20:28:27 +0100
Subject: [PATCH 17/45] Populate discovery from node table

---
 util/src/network/discovery.rs  | 10 +++++++++-
 util/src/network/host.rs       |  1 +
 util/src/network/node_table.rs |  8 +++++++-
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index da8ce9e34..08f5e5cf1 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -110,12 +110,20 @@ impl Discovery {
 		}
 	}
 
-	pub fn add_node(&mut self, e: NodeEntry) {
+	/// Add a new node to discovery table. Pings the node.
+	pub fn add_node(&mut self, e: NodeEntry) { 
 		let endpoint = e.endpoint.clone();
 		self.update_node(e);
 		self.ping(&endpoint);
 	}
 
+	/// Add a list of known nodes to the table.
+	pub fn init_node_list(&mut self, mut nodes: Vec<NodeEntry>) { 
+		for n in nodes.drain(..) {
+			self.update_node(n);
+		}
+	}
+
 	fn update_node(&mut self, e: NodeEntry) {
 		trace!(target: "discovery", "Inserting {:?}", &e);
 		let ping = {
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 5f0bf19b9..c548d07cf 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -386,6 +386,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		for n in boot_nodes {
 			host.add_node(&n);
 		}
+		host.discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries());
 		host
 	}
 
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 40cc14743..9bce2d334 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -29,7 +29,7 @@ use hash::*;
 use rlp::*;
 use time::Tm;
 use error::*;
-use network::discovery::TableUpdates;
+use network::discovery::{TableUpdates, NodeEntry};
 pub use rustc_serialize::json::Json;
 
 /// Node public key
@@ -214,6 +214,12 @@ impl NodeTable {
 		refs.iter().map(|n| n.id.clone()).collect()
 	}
 
+	/// Unordered list of all entries
+	pub fn unordered_entries(&self) -> Vec<NodeEntry> {
+		// preserve failure counter
+		self.nodes.values().map(|n| NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }).collect()
+	}
+
 	/// Get particular node
 	pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
 		self.nodes.get_mut(id)

From 0bef355494754507efc546bf80dc5634367c546e Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 20:34:05 +0100
Subject: [PATCH 18/45] Removed temp test code

---
 util/src/network/node_table.rs | 42 ++++------------------------------
 1 file changed, 4 insertions(+), 38 deletions(-)

diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 9bce2d334..69d12dc87 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -330,6 +330,7 @@ mod tests {
 	use std::str::FromStr;
 	use std::net::*;
 	use hash::*;
+	use tests::helpers::*;
 
 	#[test]
 	fn endpoint_parse() {
@@ -380,57 +381,22 @@ mod tests {
 		assert_eq!(r[2][..], id1[..]);
 	}
 
-	use std::path::PathBuf;
-	use std::env;
-	use std::fs::{remove_dir_all};
-	// TODO: use common impl
-	pub struct RandomTempPath {
-		path: PathBuf
-	}
-
-	impl RandomTempPath {
-		pub fn new() -> RandomTempPath {
-			let mut dir = env::temp_dir();
-			dir.push(H32::random().hex());
-			RandomTempPath {
-				path: dir.clone()
-			}
-		}
-
-		pub fn as_path(&self) -> &PathBuf {
-			&self.path
-		}
-
-		pub fn as_str(&self) -> &str {
-			self.path.to_str().unwrap()
-		}
-	}
-
-	impl Drop for RandomTempPath {
-		fn drop(&mut self) {
-			if let Err(e) = remove_dir_all(self.as_path()) {
-				panic!("failed to remove temp directory, probably something failed to destroyed ({})", e);
-			}
-		}
-	}
-
-
 	#[test]
 	fn table_save_load() {
-		let temp_path = RandomTempPath::new();
+		let temp_path = RandomTempPath::create_dir();
 		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
 		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
 		let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
 		let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
 		{
-			let mut table = NodeTable::new(Some(temp_path.as_str().to_owned()));
+			let mut table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned()));
 			table.add_node(node1);
 			table.add_node(node2);
 			table.note_failure(&id2);
 		}
 
 		{
-			let table = NodeTable::new(Some(temp_path.as_str().to_owned()));
+			let table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned()));
 			let r = table.nodes();
 			assert_eq!(r[0][..], id1[..]);
 			assert_eq!(r[1][..], id2[..]);

From 64913d5009816e23adff19fdb96e402baa8f6952 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Mon, 15 Feb 2016 21:43:30 +0100
Subject: [PATCH 19/45] Additional address filter

---
 util/src/network/discovery.rs  | 6 +++++-
 util/src/network/host.rs       | 8 ++++----
 util/src/network/node_table.rs | 7 +++++++
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 08f5e5cf1..8ed49b274 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -356,7 +356,11 @@ impl Discovery {
 		}
 		let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() };
 		if !entry.endpoint.is_valid() {
-			debug!(target: "discovery", "Bad address: {:?}", entry);
+			debug!(target: "discovery", "Got bad address: {:?}, using {:?} instead", entry, from);
+			entry.endpoint.address = from.clone();
+		}
+		if !entry.endpoint.is_global() {
+			debug!(target: "discovery", "Got local address: {:?}, using {:?} instead", entry, from);
 			entry.endpoint.address = from.clone();
 		}
 		self.update_node(entry.clone());
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index c548d07cf..806ef2b92 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -39,7 +39,7 @@ use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
 use network::node_table::*;
 use network::stats::NetworkStats;
 use network::error::DisconnectReason;
-use igd::{PortMappingProtocol,search_gateway};
+use igd::{PortMappingProtocol, search_gateway};
 use network::discovery::{Discovery, TableUpdates, NodeEntry};
 
 type Slab<T> = ::slab::Slab<T, usize>;
@@ -105,12 +105,12 @@ impl NetworkConfiguration {
 		if self.nat_enabled {
 			info!("Enabling NAT...");
 			match search_gateway() {
-				Err(ref err) => info!("Error: {}", err),
+				Err(ref err) => warn!("Port mapping error: {}", err),
 				Ok(gateway) => {
 					let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap();
 					match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") {
 						Err(ref err) => {
-							info!("There was an error! {}", err);
+							warn!("Port mapping error: {}", err);
 						},
 						Ok(ext_addr) => {
 							info!("Local gateway: {}, External ip address: {}", gateway, ext_addr);
@@ -356,7 +356,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			},
 			|s| KeyPair::from_secret(s).expect("Error creating node secret key"))
 		};
-		let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() };
+		let endpoint = NodeEndpoint { address: config.public_address.clone(), udp_port: addr.port() };
 		let discovery = Discovery::new(&keys, endpoint, DISCOVERY);
 		let path = config.config_path.clone();
 		let mut host = Host::<Message> {
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 69d12dc87..c152efd4f 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -96,6 +96,13 @@ impl NodeEndpoint {
 			SocketAddr::V6(a) => !a.ip().is_unspecified()
 		}
 	}
+
+	pub fn is_global(&self) -> bool {
+		match self.address {
+			SocketAddr::V4(a) => a.ip().is_global(),
+			SocketAddr::V6(a) => a.ip().is_global()
+		}
+	}
 }
 
 impl FromStr for NodeEndpoint {

From fb0b5b2e5ba49ed0799e9efed0978be3cf981273 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 00:22:44 +0100
Subject: [PATCH 20/45] Raise fd limit in linux

---
 util/fdlimit/src/raise_fd_limit.rs | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/util/fdlimit/src/raise_fd_limit.rs b/util/fdlimit/src/raise_fd_limit.rs
index f57ac2785..92127da35 100644
--- a/util/fdlimit/src/raise_fd_limit.rs
+++ b/util/fdlimit/src/raise_fd_limit.rs
@@ -57,5 +57,28 @@ pub unsafe fn raise_fd_limit() {
     }
 }
 
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+#[cfg(any(target_os = "linux"))]
+#[allow(non_camel_case_types)]
+pub unsafe fn raise_fd_limit() {
+    use libc;
+    use std::io;
+
+    // Fetch the current resource limits
+    let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
+    if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
+        let err = io::Error::last_os_error();
+        panic!("raise_fd_limit: error calling getrlimit: {}", err);
+    }
+
+    // Set soft limit to hard imit
+    rlim.rlim_cur = rlim.rlim_max;
+
+    // Set our newly-increased resource limit
+    if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
+        let err = io::Error::last_os_error();
+        panic!("raise_fd_limit: error calling setrlimit: {}", err);
+    }
+}
+
+#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
 pub unsafe fn raise_fd_limit() {}

From dbf3691c22870e7079d5976c19658c70232ad363 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 01:13:13 +0100
Subject: [PATCH 21/45] Return nothing on state requests instead of panicing

---
 ethcore/src/client.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs
index 09f7417e8..03c470bdb 100644
--- a/ethcore/src/client.rs
+++ b/ethcore/src/client.rs
@@ -419,11 +419,11 @@ impl BlockChainClient for Client {
 	}
 
 	fn state_data(&self, _hash: &H256) -> Option<Bytes> {
-		unimplemented!();
+		None
 	}
 
 	fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
-		unimplemented!();
+		None
 	}
 
 	fn import_block(&self, bytes: Bytes) -> ImportResult {

From 203947388b9f7fe6a6dda5e5e55c76c3fe66646a Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 02:05:36 +0100
Subject: [PATCH 22/45] Get public address/UPNP refactoring

---
 Cargo.lock                    |   1 +
 parity/main.rs                |  40 ++++++++-----
 util/Cargo.toml               |   1 +
 util/src/lib.rs               |   1 +
 util/src/network/discovery.rs |  14 ++---
 util/src/network/host.rs      | 105 +++++++++++++++-------------------
 util/src/network/mod.rs       |   1 +
 util/src/network/service.rs   |   2 +-
 8 files changed, 84 insertions(+), 81 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c451a6477..2e38f5aeb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -214,6 +214,7 @@ dependencies = [
  "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "json-tests 0.1.0",
  "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/parity/main.rs b/parity/main.rs
index 903b471c5..5fec05eb4 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -64,8 +64,8 @@ Options:
   -d --db-path PATH        Specify the database & configuration directory path [default: $HOME/.parity]
 
   --no-bootstrap           Don't bother trying to connect to any nodes initially.
-  --listen-address URL     Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304].
-  --public-address URL     Specify the IP/port on which peers may connect [default: 0.0.0.0:30304].
+  --listen-address URL     Specify the IP/port on which to listen for peers.
+  --public-address URL     Specify the IP/port on which peers may connect.
   --address URL            Equivalent to --listen-address URL --public-address URL.
   --upnp                   Use UPnP to try to figure out the correct network settings.
   --node-key KEY           Specify node secret key as hex string.
@@ -79,7 +79,12 @@ Options:
   -l --logging LOGGING     Specify the logging level.
   -v --version             Show information about version.
   -h --help                Show this screen.
-", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option<String>, flag_node_key: Option<String>);
+", 	flag_cache_pref_size: usize,
+	flag_cache_max_size: usize, 
+	flag_address: Option<String>, 
+	flag_listen_address: Option<String>, 
+	flag_public_address: Option<String>, 
+	flag_node_key: Option<String>);
 
 fn setup_log(init: &str) {
 	let mut builder = LogBuilder::new();
@@ -155,21 +160,26 @@ impl Configuration {
 		}
 	}
 
-	fn net_addresses(&self) -> (SocketAddr, SocketAddr) {
-		let listen_address;
-		let public_address;
+	fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) {
+		let mut listen_address = None;
+		let mut public_address = None;
 
-		match self.args.flag_address {
-			None => {
-				listen_address = SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address");
-				public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address");
+		if let Some(ref a) = self.args.flag_address {
+			public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"));
+			listen_address = public_address;
+		}
+		if let Some(ref a) = self.args.flag_listen_address {
+			if listen_address.is_some() {
+				panic!("Conflicting flags: --address and --listen-address");
 			}
-			Some(ref a) => {
-				public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address");
-				listen_address = public_address;
+			listen_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --listen-address"));
+		}
+		if let Some(ref a) = self.args.flag_public_address {
+			if public_address.is_some() {
+				panic!("Conflicting flags: --address and --public-address");
 			}
-		};
-
+			public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --public-address"));
+		}
 		(listen_address, public_address)
 	}
 }
diff --git a/util/Cargo.toml b/util/Cargo.toml
index b1e9bbc1e..5bdf8c5a6 100644
--- a/util/Cargo.toml
+++ b/util/Cargo.toml
@@ -30,3 +30,4 @@ clippy = "0.0.41"
 json-tests = { path = "json-tests" }
 target_info = "0.1.0"
 igd = "0.4.2"
+libc = "0.2.7"
diff --git a/util/src/lib.rs b/util/src/lib.rs
index 6dde49a01..7592cd17a 100644
--- a/util/src/lib.rs
+++ b/util/src/lib.rs
@@ -110,6 +110,7 @@ extern crate serde;
 #[macro_use]
 extern crate log as rlog;
 extern crate igd;
+extern crate libc;
 
 pub mod standard;
 #[macro_use]
diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 8ed49b274..c15dbbbc4 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -78,7 +78,7 @@ struct Datagramm {
 pub struct Discovery {
 	id: NodeId,
 	secret: Secret,
-	address: NodeEndpoint,
+	public_endpoint: NodeEndpoint,
 	udp_socket: UdpSocket,
 	token: StreamToken,
 	discovery_round: u16,
@@ -94,12 +94,12 @@ pub struct TableUpdates {
 }
 
 impl Discovery {
-	pub fn new(key: &KeyPair, address: NodeEndpoint, token: StreamToken) -> Discovery {
-		let socket = UdpSocket::bound(&address.udp_address()).expect("Error binding UDP socket");
+	pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken) -> Discovery {
+		let socket = UdpSocket::bound(&listen).expect("Error binding UDP socket");
 		Discovery {
 			id: key.public().clone(),
 			secret: key.secret().clone(),
-			address: address,
+			public_endpoint: public,
 			token: token,
 			discovery_round: 0,
 			discovery_id: NodeId::new(),
@@ -199,7 +199,7 @@ impl Discovery {
 	fn ping(&mut self, node: &NodeEndpoint) {
 		let mut rlp = RlpStream::new_list(3);
 		rlp.append(&PROTOCOL_VERSION);
-		self.address.to_rlp_list(&mut rlp);
+		self.public_endpoint.to_rlp_list(&mut rlp);
 		node.to_rlp_list(&mut rlp);
 		trace!(target: "discovery", "Sent Ping to {:?}", &node);
 		self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain());
@@ -507,8 +507,8 @@ mod tests {
 		let key2 = KeyPair::create().unwrap();
 		let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
 		let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
-		let mut discovery1 = Discovery::new(&key1, ep1.clone(), 0);
-		let mut discovery2 = Discovery::new(&key2, ep2.clone(), 0);
+		let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0);
+		let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0);
 
 		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
 		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 806ef2b92..3d55430bd 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 
-use std::net::{SocketAddr, SocketAddrV4};
+use std::net::{SocketAddr};
 use std::collections::{HashMap};
 use std::hash::{Hasher};
 use std::str::{FromStr};
@@ -39,8 +39,8 @@ use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
 use network::node_table::*;
 use network::stats::NetworkStats;
 use network::error::DisconnectReason;
-use igd::{PortMappingProtocol, search_gateway};
 use network::discovery::{Discovery, TableUpdates, NodeEntry};
+use network::ip_utils::{map_external_address, select_public_address};
 
 type Slab<T> = ::slab::Slab<T, usize>;
 
@@ -55,10 +55,12 @@ const MAINTENANCE_TIMEOUT: u64 = 1000;
 pub struct NetworkConfiguration {
 	/// Directory path to store network configuration. None means nothing will be saved
 	pub config_path: Option<String>,
-	/// IP address to listen for incoming connections
-	pub listen_address: SocketAddr,
-	/// IP address to advertise
-	pub public_address: SocketAddr,
+	/// IP address to listen for incoming connections. Listen to all connections by default
+	pub listen_address: Option<SocketAddr>,
+	/// IP address to advertise. Detected automatically if none.
+	pub public_address: Option<SocketAddr>,
+	/// Port for UDP connections, same as TCP by default
+	pub udp_port: Option<u16>,
 	/// Enable NAT configuration
 	pub nat_enabled: bool,
 	/// Enable discovery
@@ -78,8 +80,9 @@ impl NetworkConfiguration {
 	pub fn new() -> NetworkConfiguration {
 		NetworkConfiguration {
 			config_path: None,
-			listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
-			public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(),
+			listen_address: None,
+			public_address: None,
+			udp_port: None,
 			nat_enabled: true,
 			discovery_enabled: true,
 			pin: false,
@@ -92,48 +95,9 @@ impl NetworkConfiguration {
 	/// Create new default configuration with sepcified listen port.
 	pub fn new_with_port(port: u16) -> NetworkConfiguration {
 		let mut config = NetworkConfiguration::new();
-		config.listen_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap();
-		config.public_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap();
+		config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap());
 		config
 	}
-
-	/// Conduct NAT if needed.
-	pub fn prepared(self) -> Self {
-		let mut listen = self.listen_address;
-		let mut public = self.public_address;
-
-		if self.nat_enabled {
-			info!("Enabling NAT...");
-			match search_gateway() {
-				Err(ref err) => warn!("Port mapping error: {}", err),
-				Ok(gateway) => {
-					let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap();
-					match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") {
-						Err(ref err) => {
-							warn!("Port mapping error: {}", err);
-						},
-						Ok(ext_addr) => {
-							info!("Local gateway: {}, External ip address: {}", gateway, ext_addr);
-							public = SocketAddr::V4(ext_addr);
-							listen = SocketAddr::V4(int_addr);
-						},
-					}
-				},
-			}
-		}
-
-		NetworkConfiguration {
-			config_path: self.config_path,
-			listen_address: listen,
-			public_address: public,
-			nat_enabled: false,
-			discovery_enabled: self.discovery_enabled,
-			pin: self.pin,
-			boot_nodes: self.boot_nodes,
-			use_secret: self.use_secret,
-			ideal_peers: self.ideal_peers,
-		}
-	}
 }
 
 // Tokens
@@ -333,16 +297,39 @@ pub struct Host<Message> where Message: Send + Sync + Clone {
 	timers: RwLock<HashMap<TimerToken, ProtocolTimer>>,
 	timer_counter: RwLock<usize>,
 	stats: Arc<NetworkStats>,
+	public_endpoint: NodeEndpoint,
 }
 
 impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	/// Create a new instance
 	pub fn new(config: NetworkConfiguration) -> Host<Message> {
-		let config = config.prepared();
+		let listen_address = match config.listen_address {
+			None => SocketAddr::from_str("0.0.0.0:30304").unwrap(),
+			Some(addr) => addr,
+		};
+
+		let udp_port = config.udp_port.unwrap_or(listen_address.port());
+		let public_endpoint = match config.public_address {
+			None => {
+				let public_address = select_public_address(listen_address.port());
+				let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port };
+				if config.nat_enabled {
+					match map_external_address(&local_endpoint) {
+						Some(endpoint) => {
+							info!("NAT Mappped to external address {}", endpoint.address);
+							endpoint
+						},
+						None => local_endpoint
+					}
+				} else {
+					local_endpoint
+				}
+			}
+			Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port }
+		};
 
-		let addr = config.listen_address;
 		// Setup the server socket
-		let tcp_listener = TcpListener::bind(&addr).unwrap();
+		let tcp_listener = TcpListener::bind(&listen_address).unwrap();
 		let keys = if let Some(ref secret) = config.use_secret { 
 			KeyPair::from_secret(secret.clone()).unwrap() 
 		} else { 
@@ -356,8 +343,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			},
 			|s| KeyPair::from_secret(s).expect("Error creating node secret key"))
 		};
-		let endpoint = NodeEndpoint { address: config.public_address.clone(), udp_port: addr.port() };
-		let discovery = Discovery::new(&keys, endpoint, DISCOVERY);
+		let discovery = Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY);
 		let path = config.config_path.clone();
 		let mut host = Host::<Message> {
 			info: RwLock::new(HostInfo {
@@ -378,8 +364,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			timers: RwLock::new(HashMap::new()),
 			timer_counter: RwLock::new(USER_TIMER),
 			stats: Arc::new(NetworkStats::default()),
+			public_endpoint: public_endpoint,
 		};
-		let port = host.info.read().unwrap().config.listen_address.port();
+		let port = listen_address.port();
 		host.info.write().unwrap().deref_mut().listen_port = port;
 
 		let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone();
@@ -409,8 +396,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		self.info.read().unwrap().client_version.clone()
 	}
 
-	pub fn client_id(&self) -> NodeId {
-		self.info.read().unwrap().id().clone()
+	pub fn client_url(&self) -> String {
+		format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.public_endpoint.clone()))
 	}
 
 	fn maintain_network(&self, io: &IoContext<NetworkIoMessage<Message>>) {
@@ -456,13 +443,15 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		}
 
 		let handshake_count = self.handshake_count();
-		if handshake_count >= MAX_HANDSHAKES {
+		// allow 16 slots for incoming connections
+		let handshake_limit = MAX_HANDSHAKES - 16;
+		if handshake_count >= handshake_limit {
 			return;
 		}
 
 		let nodes = { self.nodes.read().unwrap().nodes() };
 		for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id))
-			.take(min(MAX_HANDSHAKES_PER_ROUND, MAX_HANDSHAKES - handshake_count)) {
+			.take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) {
 			self.connect_peer(&id, io);
 		}
 		debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count());
diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index c5066ff99..ff52212af 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -73,6 +73,7 @@ mod service;
 mod error;
 mod node_table;
 mod stats;
+mod ip_utils;
 
 #[cfg(test)]
 mod tests;
diff --git a/util/src/network/service.rs b/util/src/network/service.rs
index 60f0ec415..1cd48abe1 100644
--- a/util/src/network/service.rs
+++ b/util/src/network/service.rs
@@ -42,7 +42,7 @@ impl<Message> NetworkService<Message> where Message: Send + Sync + Clone + 'stat
 		let host = Arc::new(Host::new(config));
 		let stats = host.stats().clone();
 		let host_info = host.client_version();
-		info!("Host ID={:?}", host.client_id());
+		info!("Node URL: {}", host.client_url());
 		try!(io_service.register_handler(host));
 		Ok(NetworkService {
 			io_service: io_service,

From f771306867121d4dbe30c289305994dba50c9fed Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 02:05:45 +0100
Subject: [PATCH 23/45] Get public address/UPNP refactoring

---
 util/src/network/ip_utils.rs | 176 +++++++++++++++++++++++++++++++++++
 1 file changed, 176 insertions(+)
 create mode 100644 util/src/network/ip_utils.rs

diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs
new file mode 100644
index 000000000..8f94073b3
--- /dev/null
+++ b/util/src/network/ip_utils.rs
@@ -0,0 +1,176 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
+
+// Based on original work by David Levy https://raw.githubusercontent.com/dlevy47/rust-interfaces
+
+use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use std::io;
+use igd::{PortMappingProtocol, search_gateway_from_timeout};
+use std::time::Duration;
+use network::node_table::{NodeEndpoint};
+
+pub enum IpAddr{
+	V4(Ipv4Addr),
+	V6(Ipv6Addr),
+}
+
+#[cfg(not(windows))]
+mod getinterfaces {
+	use std::{mem, io, ptr};
+	use libc::{AF_INET, AF_INET6};
+	use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6};
+	use std::net::{Ipv4Addr, Ipv6Addr};
+	use super::IpAddr;
+
+	fn convert_sockaddr (sa: *mut sockaddr) -> Option<IpAddr> {
+		if sa == ptr::null_mut() { return None; }
+
+		let (addr, _) = match unsafe { *sa }.sa_family as i32 {
+			AF_INET => {
+				let sa: *const sockaddr_in = unsafe { mem::transmute(sa) };
+				let sa = & unsafe { *sa };
+				let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port);
+				(
+					IpAddr::V4(Ipv4Addr::new(
+							(addr & 0x000000FF) as u8,
+							((addr & 0x0000FF00) >>  8) as u8,
+							((addr & 0x00FF0000) >> 16) as u8,
+							((addr & 0xFF000000) >> 24) as u8,
+							)),
+							port
+				)
+			},
+			AF_INET6 => {
+				let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) };
+				let sa = & unsafe { *sa };
+				let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port);
+				let addr: [u16; 8] = unsafe { mem::transmute(addr) };
+				(
+					IpAddr::V6(Ipv6Addr::new(
+							addr[0],
+							addr[1],
+							addr[2],
+							addr[3],
+							addr[4],
+							addr[5],
+							addr[6],
+							addr[7],
+							)),
+							port
+				)
+			},
+			_ => return None,
+		};
+		Some(addr)
+	}
+
+	fn convert_ifaddrs (ifa: *mut ifaddrs) -> Option<IpAddr> {
+		let ifa = unsafe { &mut *ifa };
+		convert_sockaddr(ifa.ifa_addr)
+	}
+
+	pub fn get_all() -> io::Result<Vec<IpAddr>> {
+		let mut ifap: *mut ifaddrs = unsafe { mem::zeroed() };
+		if unsafe { getifaddrs(&mut ifap as *mut _) } != 0 {
+			return Err(io::Error::last_os_error());
+		}
+
+		let mut ret = Vec::new();
+		let mut cur: *mut ifaddrs = ifap;
+		while cur != ptr::null_mut() {
+			if let Some(ip_addr) = convert_ifaddrs(cur) {
+				ret.push(ip_addr);
+			}
+
+			//TODO: do something else maybe?
+			cur = unsafe { (*cur).ifa_next };
+		}
+
+		unsafe { freeifaddrs(ifap) };
+		Ok(ret)
+	}
+}
+
+#[cfg(not(windows))]
+fn get_if_addrs() -> io::Result<Vec<IpAddr>> {
+	getinterfaces::get_all()
+}
+
+#[cfg(windows)]
+fn get_if_addrs() -> io::Result<Vec<IpAddr>> {
+	Ok(Vec::new())
+}
+
+/// Select the best available public address
+pub fn select_public_address(port: u16) -> SocketAddr {
+	match get_if_addrs() {
+		Ok(list) => {
+			//prefer IPV4 bindings
+			for addr in &list { //TODO: use better criteria than just the first in the list
+				match *addr {
+					IpAddr::V4(a) if !a.is_unspecified() && !a.is_loopback() && !a.is_link_local() => {
+						return SocketAddr::V4(SocketAddrV4::new(a, port));
+					},
+					_ => {},
+				}
+			}
+			for addr in list {
+				match addr {
+					IpAddr::V6(a) if !a.is_unspecified() && !a.is_loopback() => {
+						return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0));
+					},
+					_ => {},
+				}
+			}
+		},
+		Err(e) => debug!("Error listing public interfaces: {:?}", e)
+	}
+	SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
+}
+
+pub fn map_external_address(local: &NodeEndpoint) -> Option<NodeEndpoint> {
+	if let SocketAddr::V4(ref local_addr) = local.address {
+		match search_gateway_from_timeout(local_addr.ip().clone(), Duration::new(5, 0)) {
+			Err(ref err) => debug!("Gateway search error: {}", err),
+			Ok(gateway) => {
+				match gateway.get_external_ip() {
+					Err(ref err) => {
+						debug!("IP request error: {}", err);
+					},
+					Ok(external_addr) => {
+						match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(local_addr.ip().clone(), local_addr.port()), 0, "Parity Node/TCP") {
+							Err(ref err) => {
+								debug!("Port mapping error: {}", err);
+							},
+							Ok(tcp_port) => {
+								match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(local_addr.ip().clone(), local.udp_port), 0, "Parity Node/UDP") {
+									Err(ref err) => {
+										debug!("Port mapping error: {}", err);
+									},
+									Ok(udp_port) => {
+										return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port: udp_port });
+									},
+								}
+							},
+						}
+					},
+				}
+			},
+		}
+	}
+	None
+}
+

From 58fdfe77d3c93a2599805bd718401f7ebedba645 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 02:31:17 +0100
Subject: [PATCH 24/45] Handle pinning and enable_discovery options

---
 util/src/network/host.rs | 44 ++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 3d55430bd..004410466 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -291,13 +291,14 @@ pub struct Host<Message> where Message: Send + Sync + Clone {
 	tcp_listener: Mutex<TcpListener>,
 	handshakes: Arc<RwLock<Slab<SharedHandshake>>>,
 	sessions: Arc<RwLock<Slab<SharedSession>>>,
-	discovery: Mutex<Discovery>,
+	discovery: Option<Mutex<Discovery>>,
 	nodes: RwLock<NodeTable>,
 	handlers: RwLock<HashMap<ProtocolId, Arc<NetworkProtocolHandler<Message>>>>,
 	timers: RwLock<HashMap<TimerToken, ProtocolTimer>>,
 	timer_counter: RwLock<usize>,
 	stats: Arc<NetworkStats>,
 	public_endpoint: NodeEndpoint,
+	pinned_nodes: Vec<NodeId>,
 }
 
 impl<Message> Host<Message> where Message: Send + Sync + Clone {
@@ -343,7 +344,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			},
 			|s| KeyPair::from_secret(s).expect("Error creating node secret key"))
 		};
-		let discovery = Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY);
+		let discovery = if config.discovery_enabled && !config.pin {
+			Some(Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY)) 
+		} else { None };
 		let path = config.config_path.clone();
 		let mut host = Host::<Message> {
 			info: RwLock::new(HostInfo {
@@ -355,7 +358,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				listen_port: 0,
 				capabilities: Vec::new(),
 			}),
-			discovery: Mutex::new(discovery),
+			discovery: discovery.map(Mutex::new),
 			tcp_listener: Mutex::new(tcp_listener),
 			handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))),
 			sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))),
@@ -365,6 +368,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			timer_counter: RwLock::new(USER_TIMER),
 			stats: Arc::new(NetworkStats::default()),
 			public_endpoint: public_endpoint,
+			pinned_nodes: Vec::new(),
 		};
 		let port = listen_address.port();
 		host.info.write().unwrap().deref_mut().listen_port = port;
@@ -373,7 +377,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		for n in boot_nodes {
 			host.add_node(&n);
 		}
-		host.discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries());
+		if let Some(ref mut discovery) = host.discovery {
+			discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries());
+		}
 		host
 	}
 
@@ -386,8 +392,11 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			Err(e) => { warn!("Could not add node: {:?}", e); },
 			Ok(n) => {
 				let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
+				self.pinned_nodes.push(n.id.clone());
 				self.nodes.write().unwrap().add_node(n);
-				self.discovery.lock().unwrap().add_node(entry);
+				if let Some(ref mut discovery) = self.discovery {
+					discovery.lock().unwrap().add_node(entry);
+				}
 			}
 		}
 	}
@@ -437,6 +446,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 
 	fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
 		let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers };
+		let pin = { self.info.read().unwrap().deref().config.pin };
 		let session_count = self.session_count();
 		if session_count >= ideal_peers as usize {
 			return;
@@ -449,7 +459,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			return;
 		}
 
-		let nodes = { self.nodes.read().unwrap().nodes() };
+		let nodes = if pin { self.pinned_nodes.clone() } else { self.nodes.read().unwrap().nodes() };
 		for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id))
 			.take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) {
 			self.connect_peer(&id, io);
@@ -670,7 +680,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 				if let Ok(address) = session.remote_addr() {
 					let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
 					self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
-					self.discovery.lock().unwrap().add_node(entry);
+					if let Some(ref discovery) = self.discovery {
+						discovery.lock().unwrap().add_node(entry);
+					}
 				}
 			}
 			Arc::new(Mutex::new(session))
@@ -759,8 +771,10 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 		io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener");
 		io.register_stream(DISCOVERY).expect("Error registering UDP listener");
 		io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer");
-		io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer");
-		io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer");
+		if self.discovery.is_some() {
+			io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer");
+			io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer");
+		}
 	}
 
 	fn stream_hup(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
@@ -777,7 +791,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io),
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io),
 			DISCOVERY => {
-				if let Some(node_changes) = self.discovery.lock().unwrap().readable() {
+				if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() {
 					self.update_nodes(io, node_changes);
 				}
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
@@ -792,7 +806,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io),
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io),
 			DISCOVERY => {
-				self.discovery.lock().unwrap().writable();
+				self.discovery.as_ref().unwrap().lock().unwrap().writable();
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
 			}
 			_ => panic!("Received unknown writable token"),
@@ -805,11 +819,11 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io),
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io),
 			DISCOVERY_REFRESH => {
-				self.discovery.lock().unwrap().refresh();
+				self.discovery.as_ref().unwrap().lock().unwrap().refresh();
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
 			},
 			DISCOVERY_ROUND => {
-				if let Some(node_changes) = self.discovery.lock().unwrap().round() {
+				if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() {
 					self.update_nodes(io, node_changes);
 				}
 				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
@@ -880,7 +894,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 					connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket");
 				}
 			}
-			DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"),
+			DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"),
 			TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"),
 			_ => warn!("Unexpected stream registration")
 		}
@@ -922,7 +936,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 					connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket");
 				}
 			}
-			DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"),
+			DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"),
 			TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"),
 			_ => warn!("Unexpected stream update")
 		}

From 33e8d749d2da4bc56213d4348bd163bccfea3c88 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 03:05:05 +0100
Subject: [PATCH 25/45] Max handhsakes reached is now a debug warning

---
 util/src/network/host.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 004410466..24f24fc6f 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -513,7 +513,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			});
 			Arc::new(Mutex::new(handshake))
 		}).is_none() {
-			warn!("Max handshakes reached");
+			debug!("Max handshakes reached");
 		}
 	}
 

From d95e9710306e95552a2ba3ad4df66067c77bea96 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 17:53:31 +0100
Subject: [PATCH 26/45] Prevent deadlocks

---
 ethcore/src/block_queue.rs |  8 ++++----
 util/src/io/worker.rs      | 15 +++++++++++----
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs
index 1a1dee48e..f11519067 100644
--- a/ethcore/src/block_queue.rs
+++ b/ethcore/src/block_queue.rs
@@ -153,7 +153,7 @@ impl BlockQueue {
 	}
 
 	fn verify(verification: Arc<Mutex<Verification>>, engine: Arc<Box<Engine>>, wait: Arc<Condvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>, empty: Arc<Condvar>) {
-		while !deleting.load(AtomicOrdering::Relaxed) {
+		while !deleting.load(AtomicOrdering::Acquire) {
 			{
 				let mut lock = verification.lock().unwrap();
 
@@ -161,11 +161,11 @@ impl BlockQueue {
 					empty.notify_all();
 				}
 
-				while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) {
+				while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) {
 					lock = wait.wait(lock).unwrap();
 				}
 
-				if deleting.load(AtomicOrdering::Relaxed) {
+				if deleting.load(AtomicOrdering::Acquire) {
 					return;
 				}
 			}
@@ -347,7 +347,7 @@ impl MayPanic for BlockQueue {
 impl Drop for BlockQueue {
 	fn drop(&mut self) {
 		self.clear();
-		self.deleting.store(true, AtomicOrdering::Relaxed);
+		self.deleting.store(true, AtomicOrdering::Release);
 		self.more_to_verify.notify_all();
 		for t in self.verifiers.drain(..) {
 			t.join().unwrap();
diff --git a/util/src/io/worker.rs b/util/src/io/worker.rs
index 1ba0318bc..b874ea0a4 100644
--- a/util/src/io/worker.rs
+++ b/util/src/io/worker.rs
@@ -44,6 +44,7 @@ pub struct Worker {
 	thread: Option<JoinHandle<()>>,
 	wait: Arc<Condvar>,
 	deleting: Arc<AtomicBool>,
+	wait_mutex: Arc<Mutex<()>>,
 }
 
 impl Worker {
@@ -61,6 +62,7 @@ impl Worker {
 			thread: None,
 			wait: wait.clone(),
 			deleting: deleting.clone(),
+			wait_mutex: wait_mutex.clone(),
 		};
 		worker.thread = Some(thread::Builder::new().name(format!("IO Worker #{}", index)).spawn(
 			move || {
@@ -77,13 +79,17 @@ impl Worker {
 						wait_mutex: Arc<Mutex<()>>,
 						deleting: Arc<AtomicBool>)
 						where Message: Send + Sync + Clone + 'static {
-		while !deleting.load(AtomicOrdering::Relaxed) {
+		loop {
 			{
 				let lock = wait_mutex.lock().unwrap();
-				let _ = wait.wait(lock).unwrap();
-				if deleting.load(AtomicOrdering::Relaxed) {
+				if deleting.load(AtomicOrdering::Acquire) {
 					return;
 				}
+				let _ = wait.wait(lock).unwrap();
+			}
+
+			if deleting.load(AtomicOrdering::Acquire) {
+				return;
 			}
 			while let chase_lev::Steal::Data(work) = stealer.steal() {
 				Worker::do_work(work, channel.clone());
@@ -114,7 +120,8 @@ impl Worker {
 
 impl Drop for Worker {
 	fn drop(&mut self) {
-		self.deleting.store(true, AtomicOrdering::Relaxed);
+		let _ = self.wait_mutex.lock();
+		self.deleting.store(true, AtomicOrdering::Release);
 		self.wait.notify_all();
 		let thread = mem::replace(&mut self.thread, None).unwrap();
 		thread.join().ok();

From a4ea0737b25ae4953e16f3b87ebaa84e8994c745 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 17:54:34 +0100
Subject: [PATCH 27/45] Fixed some tests

---
 util/src/network/host.rs  |  6 +++---
 util/src/network/tests.rs | 10 ++++++----
 util/src/sha3.rs          |  2 +-
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 24f24fc6f..140625eea 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -493,8 +493,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 			};
 			match TcpStream::connect(&address) {
 				Ok(socket) => socket,
-				Err(_) => {
-					warn!("Cannot connect to node");
+				Err(e) => {
+					warn!("Can't connect to node: {:?}", e);
 					return;
 				}
 			}
@@ -769,9 +769,9 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 	/// Initialize networking
 	fn initialize(&self, io: &IoContext<NetworkIoMessage<Message>>) {
 		io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener");
-		io.register_stream(DISCOVERY).expect("Error registering UDP listener");
 		io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer");
 		if self.discovery.is_some() {
+			io.register_stream(DISCOVERY).expect("Error registering UDP listener");
 			io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer");
 			io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer");
 		}
diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs
index a3d5290c9..925c95396 100644
--- a/util/src/network/tests.rs
+++ b/util/src/network/tests.rs
@@ -92,16 +92,18 @@ fn net_service() {
 #[test]
 fn net_connect() {
 	let key1 = KeyPair::create().unwrap();
-	let mut config1 = NetworkConfiguration::new_with_port(30344);
+	let mut config1 = NetworkConfiguration::new_with_port(30354);
 	config1.use_secret = Some(key1.secret().clone());
+	config1.nat_enabled = false;
 	config1.boot_nodes = vec![ ];
-	let mut config2 = NetworkConfiguration::new_with_port(30345);
-	config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30344", key1.public().hex()) ];
+	let mut config2 = NetworkConfiguration::new_with_port(30355);
+	config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30354", key1.public().hex()) ];
+	config2.nat_enabled = false;
 	let mut service1 = NetworkService::<TestProtocolMessage>::start(config1).unwrap();
 	let mut service2 = NetworkService::<TestProtocolMessage>::start(config2).unwrap();
 	let handler1 = TestProtocol::register(&mut service1);
 	let handler2 = TestProtocol::register(&mut service2);
-	while !handler1.got_packet() && !handler2.got_packet() {
+	while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) {
 		thread::sleep(Duration::from_millis(50));
 	}
 	assert!(service1.stats().sessions() >= 1);
diff --git a/util/src/sha3.rs b/util/src/sha3.rs
index 4079e8ba4..7e8382250 100644
--- a/util/src/sha3.rs
+++ b/util/src/sha3.rs
@@ -66,7 +66,7 @@ impl<T> Hashable for T where T: BytesConvertable {
 
 #[test]
 fn sha3_empty() {
-	assert_eq!((&[0u8; 0]).sha3(), SHA3_EMPTY);
+	assert_eq!([0u8; 0].sha3(), SHA3_EMPTY);
 }
 #[test]
 fn sha3_as() {

From f4fa747cd0683b16d670ae4f446dd5155ffd1df4 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 17:55:37 +0100
Subject: [PATCH 28/45] ip_utils tests

---
 util/src/network/ip_utils.rs | 50 ++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 22 deletions(-)

diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs
index 8f94073b3..da50f8ddf 100644
--- a/util/src/network/ip_utils.rs
+++ b/util/src/network/ip_utils.rs
@@ -43,34 +43,28 @@ mod getinterfaces {
 				let sa: *const sockaddr_in = unsafe { mem::transmute(sa) };
 				let sa = & unsafe { *sa };
 				let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port);
-				(
-					IpAddr::V4(Ipv4Addr::new(
-							(addr & 0x000000FF) as u8,
-							((addr & 0x0000FF00) >>  8) as u8,
-							((addr & 0x00FF0000) >> 16) as u8,
-							((addr & 0xFF000000) >> 24) as u8,
-							)),
-							port
-				)
+				(IpAddr::V4(Ipv4Addr::new(
+					(addr & 0x000000FF) as u8,
+					((addr & 0x0000FF00) >>  8) as u8,
+					((addr & 0x00FF0000) >> 16) as u8,
+					((addr & 0xFF000000) >> 24) as u8)),
+					port)
 			},
 			AF_INET6 => {
 				let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) };
 				let sa = & unsafe { *sa };
 				let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port);
 				let addr: [u16; 8] = unsafe { mem::transmute(addr) };
-				(
-					IpAddr::V6(Ipv6Addr::new(
-							addr[0],
-							addr[1],
-							addr[2],
-							addr[3],
-							addr[4],
-							addr[5],
-							addr[6],
-							addr[7],
-							)),
-							port
-				)
+				(IpAddr::V6(Ipv6Addr::new(
+					addr[0],
+					addr[1],
+					addr[2],
+					addr[3],
+					addr[4],
+					addr[5],
+					addr[6],
+					addr[7])),
+					port)
 			},
 			_ => return None,
 		};
@@ -174,3 +168,15 @@ pub fn map_external_address(local: &NodeEndpoint) -> Option<NodeEndpoint> {
 	None
 }
 
+#[test]
+fn can_select_public_address() {
+	let pub_address = select_public_address(40477);
+	assert!(pub_address.port() == 40477);
+}
+
+#[test]
+fn can_map_external_address_or_fail() {
+	let pub_address = select_public_address(40478);
+	let _ = map_external_address(&NodeEndpoint { address: pub_address, udp_port: 40478 });
+}
+

From 217cbec50ed6c2cccec386dd3daedbf95b92c64e Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 19:08:58 +0100
Subject: [PATCH 29/45] Disconnect test

---
 util/src/network/host.rs    |  1 -
 util/src/network/session.rs |  5 +++
 util/src/network/tests.rs   | 65 +++++++++++++++++++++++++++----------
 3 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 140625eea..4afb790ae 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -634,7 +634,6 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		} 
 		if kill {
 			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
-			return;
 		}
 		for p in ready_data {
 			let h = self.handlers.read().unwrap().get(p).unwrap().clone();
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index f08fef385..04fb6d930 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -318,7 +318,12 @@ impl Session {
 		trace!(target: "net", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps);
 		self.info.client_version = client_version;
 		self.info.capabilities = caps;
+		if self.info.capabilities.is_empty() {
+			trace!("No common capabilities with peer.");
+			return Err(From::from(self.disconnect(DisconnectReason::UselessPeer)));
+		}
 		if protocol != host.protocol_version {
+			trace!("Peer protocol version mismatch: {}", protocol);
 			return Err(From::from(self.disconnect(DisconnectReason::UselessPeer)));
 		}
 		self.had_hello = true;
diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs
index 925c95396..dc80936d2 100644
--- a/util/src/network/tests.rs
+++ b/util/src/network/tests.rs
@@ -23,17 +23,10 @@ use io::TimerToken;
 use crypto::KeyPair;
 
 pub struct TestProtocol {
+	drop_session: bool,
 	pub packet: Mutex<Bytes>,
 	pub got_timeout: AtomicBool,
-}
-
-impl Default for TestProtocol {
-	fn default() -> Self {
-		TestProtocol { 
-			packet: Mutex::new(Vec::new()), 
-			got_timeout: AtomicBool::new(false), 
-		}
-	}
+	pub got_disconnect: AtomicBool,
 }
 
 #[derive(Clone)]
@@ -42,9 +35,17 @@ pub struct TestProtocolMessage {
 }
 
 impl TestProtocol {
+	pub fn new(drop_session: bool) -> Self {
+		TestProtocol { 
+			packet: Mutex::new(Vec::new()), 
+			got_timeout: AtomicBool::new(false), 
+			got_disconnect: AtomicBool::new(false), 
+			drop_session: drop_session,
+		}
+	}
 	/// Creates and register protocol with the network service
-	pub fn register(service: &mut NetworkService<TestProtocolMessage>) -> Arc<TestProtocol> {
-		let handler = Arc::new(TestProtocol::default());
+	pub fn register(service: &mut NetworkService<TestProtocolMessage>, drop_session: bool) -> Arc<TestProtocol> {
+		let handler = Arc::new(TestProtocol::new(drop_session));
 		service.register_protocol(handler.clone(), "test", &[42u8, 43u8]).expect("Error registering test protocol handler");
 		handler
 	}
@@ -56,6 +57,10 @@ impl TestProtocol {
 	pub fn got_timeout(&self) -> bool {
 		self.got_timeout.load(AtomicOrdering::Relaxed)
 	}
+
+	pub fn got_disconnect(&self) -> bool {
+		self.got_disconnect.load(AtomicOrdering::Relaxed)
+	}
 }
 
 impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
@@ -68,11 +73,16 @@ impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
 		self.packet.lock().unwrap().extend(data);
 	}
 
-	fn connected(&self, io: &NetworkContext<TestProtocolMessage>, _peer: &PeerId) {
-		io.respond(33, "hello".to_owned().into_bytes()).unwrap();
+	fn connected(&self, io: &NetworkContext<TestProtocolMessage>, peer: &PeerId) {
+		if self.drop_session {
+			io.disconnect_peer(*peer)
+		} else {
+			io.respond(33, "hello".to_owned().into_bytes()).unwrap();
+		}
 	}
 
 	fn disconnected(&self, _io: &NetworkContext<TestProtocolMessage>, _peer: &PeerId) {
+		self.got_disconnect.store(true, AtomicOrdering::Relaxed);
 	}
 
 	/// Timer function called after a timeout created with `NetworkContext::timeout`.
@@ -86,7 +96,7 @@ impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
 #[test]
 fn net_service() {
 	let mut service = NetworkService::<TestProtocolMessage>::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service");
-	service.register_protocol(Arc::new(TestProtocol::default()), "myproto", &[1u8]).unwrap();
+	service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap();
 }
 
 #[test]
@@ -101,8 +111,8 @@ fn net_connect() {
 	config2.nat_enabled = false;
 	let mut service1 = NetworkService::<TestProtocolMessage>::start(config1).unwrap();
 	let mut service2 = NetworkService::<TestProtocolMessage>::start(config2).unwrap();
-	let handler1 = TestProtocol::register(&mut service1);
-	let handler2 = TestProtocol::register(&mut service2);
+	let handler1 = TestProtocol::register(&mut service1, false);
+	let handler2 = TestProtocol::register(&mut service2, false);
 	while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) {
 		thread::sleep(Duration::from_millis(50));
 	}
@@ -110,11 +120,32 @@ fn net_connect() {
 	assert!(service2.stats().sessions() >= 1);
 }
 
+#[test]
+fn net_disconnect() {
+	let key1 = KeyPair::create().unwrap();
+	let mut config1 = NetworkConfiguration::new_with_port(30364);
+	config1.use_secret = Some(key1.secret().clone());
+	config1.nat_enabled = false;
+	config1.boot_nodes = vec![ ];
+	let mut config2 = NetworkConfiguration::new_with_port(30365);
+	config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30364", key1.public().hex()) ];
+	config2.nat_enabled = false;
+	let mut service1 = NetworkService::<TestProtocolMessage>::start(config1).unwrap();
+	let mut service2 = NetworkService::<TestProtocolMessage>::start(config2).unwrap();
+	let handler1 = TestProtocol::register(&mut service1, false);
+	let handler2 = TestProtocol::register(&mut service2, true);
+	while !(handler1.got_disconnect() && handler2.got_disconnect()) {
+		thread::sleep(Duration::from_millis(50));
+	}
+	assert!(handler1.got_disconnect());
+	assert!(handler2.got_disconnect());
+}
+
 #[test]
 fn net_timeout() {
 	let config = NetworkConfiguration::new_with_port(30346);
 	let mut service = NetworkService::<TestProtocolMessage>::start(config).unwrap();
-	let handler = TestProtocol::register(&mut service);
+	let handler = TestProtocol::register(&mut service, false);
 	while !handler.got_timeout() {
 		thread::sleep(Duration::from_millis(50));
 	}

From 4f73d63f90154140d6dadeaed3700ca623eed0ab Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 19:51:51 +0100
Subject: [PATCH 30/45] Tweaked CLI options

---
 parity/main.rs | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/parity/main.rs b/parity/main.rs
index 5fec05eb4..516609615 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -64,9 +64,11 @@ Options:
   -d --db-path PATH        Specify the database & configuration directory path [default: $HOME/.parity]
 
   --no-bootstrap           Don't bother trying to connect to any nodes initially.
-  --listen-address URL     Specify the IP/port on which to listen for peers.
+  --listen-address URL     Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304].
   --public-address URL     Specify the IP/port on which peers may connect.
   --address URL            Equivalent to --listen-address URL --public-address URL.
+  --peers NUM  	           Try to manintain that many peers [default: 25].
+  --no-discovery   	       Disable new peer discovery.
   --upnp                   Use UPnP to try to figure out the correct network settings.
   --node-key KEY           Specify node secret key as hex string.
 
@@ -81,8 +83,8 @@ Options:
   -h --help                Show this screen.
 ", 	flag_cache_pref_size: usize,
 	flag_cache_max_size: usize, 
+	flag_peers: u32, 
 	flag_address: Option<String>, 
-	flag_listen_address: Option<String>, 
 	flag_public_address: Option<String>, 
 	flag_node_key: Option<String>);
 
@@ -168,11 +170,8 @@ impl Configuration {
 			public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"));
 			listen_address = public_address;
 		}
-		if let Some(ref a) = self.args.flag_listen_address {
-			if listen_address.is_some() {
-				panic!("Conflicting flags: --address and --listen-address");
-			}
-			listen_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --listen-address"));
+		if listen_address.is_none() {
+			listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address"));
 		}
 		if let Some(ref a) = self.args.flag_public_address {
 			if public_address.is_some() {
@@ -218,6 +217,8 @@ fn main() {
 	net_settings.listen_address = listen;
 	net_settings.public_address = public;
 	net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string"));
+	net_settings.discovery_enabled = !conf.args.flag_no_discovery;
+	net_settings.ideal_peers = conf.args.flag_peers;
 	let mut net_path = PathBuf::from(&conf.path());
 	net_path.push("network");
 	net_settings.config_path = Some(net_path.to_str().unwrap().to_owned());

From fbe06d3f2f85275cc6ec4c9c3b17344a3778def0 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 21:25:01 +0100
Subject: [PATCH 31/45] More tests

---
 util/src/network/discovery.rs | 22 +++++++++++++++++-----
 util/src/network/host.rs      | 10 ++++++++++
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index c15dbbbc4..0064a34db 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -445,13 +445,13 @@ impl Discovery {
 		Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
 	}
 
-	fn check_expired(&mut self) -> HashSet<NodeId> {
+	fn check_expired(&mut self, force: bool) -> HashSet<NodeId> {
 		let now = time::precise_time_ns();
 		let mut removed: HashSet<NodeId> = HashSet::new();
 		for bucket in &mut self.node_buckets {
 			bucket.nodes.retain(|node| {
 				if let Some(timeout) = node.timeout {
-					if now - timeout < PING_TIMEOUT_MS * 1000_0000 {
+					if !force && now - timeout < PING_TIMEOUT_MS * 1000_0000 {
 						true
 					}
 					else {
@@ -466,7 +466,7 @@ impl Discovery {
 	}
 
 	pub fn round(&mut self) -> Option<TableUpdates> {
-		let removed = self.check_expired();
+		let removed = self.check_expired(false);
 		self.discover();
 		if !removed.is_empty() { 
 			Some(TableUpdates { added: HashMap::new(), removed: removed }) 
@@ -512,8 +512,8 @@ mod tests {
 
 		let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
 		let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
-		discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1. endpoint.clone() });
-		discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2. endpoint.clone() });
+		discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1.endpoint.clone() });
+		discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2.endpoint.clone() });
 
 		discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() });
 		discovery2.refresh();
@@ -535,4 +535,16 @@ mod tests {
 		}
 		assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3)
 	}
+
+	#[test]
+	fn removes_expired() {
+		let key = KeyPair::create().unwrap();
+		let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40444 };
+		let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0);
+		for _ in 0..1200 {
+			discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
+		}
+		let removed = discovery.check_expired(true).len();
+		assert!(removed > 0);
+	}
 }
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 4afb790ae..080a8b5cc 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -987,3 +987,13 @@ fn load_key(path: &Path) -> Option<Secret> {
 		}
 	}
 }
+
+#[test]
+fn key_save_load() {
+	use tests::helpers::RandomTempPath;
+	let temp_path = RandomTempPath::create_dir();
+	let key = H256::random();
+	save_key(temp_path.as_path(), &key);
+	let r = load_key(temp_path.as_path());
+	assert_eq!(key, r.unwrap());
+}

From 7e0dfb41d08bc4a47084a61a7b745eed00de1690 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 23:33:32 +0100
Subject: [PATCH 32/45] Minor test tweaks and code cleanup

---
 util/src/network/discovery.rs |  1 +
 util/src/network/host.rs      | 26 ++++----------------------
 2 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 0064a34db..f383b74f7 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -544,6 +544,7 @@ mod tests {
 		for _ in 0..1200 {
 			discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
 		}
+		assert!(Discovery::nearest_node_entries(&NodeId::new(), &discovery.node_buckets).len() <= 16);
 		let removed = discovery.check_expired(true).len();
 		assert!(removed > 0);
 	}
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 080a8b5cc..bcb1c7585 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -534,42 +534,24 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 	}
 
 	fn handshake_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		let mut create_session = false;
-		let mut kill = false;
 		let handshake = { self.handshakes.read().unwrap().get(token).cloned() };
 		if let Some(handshake) = handshake {
 			let mut h = handshake.lock().unwrap();
 			if let Err(e) = h.writable(io, &self.info.read().unwrap()) {
 				debug!(target: "net", "Handshake write error: {}:{:?}", token, e);
-				kill = true;
-			}
-			if h.done() {
-				create_session = true;
 			}
 		} 
-		if kill {
-			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
-			return;
-		} else if create_session {
-			self.start_session(token, io);
-			io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
-		}
 	}
 
 	fn session_writable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
-		let mut kill = false;
 		let session = { self.sessions.read().unwrap().get(token).cloned() };
 		if let Some(session) = session {
 			let mut s = session.lock().unwrap();
 			if let Err(e) = s.writable(io, &self.info.read().unwrap()) {
 				debug!(target: "net", "Session write error: {}:{:?}", token, e);
-				kill = true;
 			}
 			io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e));
 		} 
-		if kill {
-			self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
-		}
 	}
 
 	fn connection_closed(&self, token: TimerToken, io: &IoContext<NetworkIoMessage<Message>>) {
@@ -793,7 +775,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 				if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() {
 					self.update_nodes(io, node_changes);
 				}
-				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
+				io.update_registration(DISCOVERY).expect("Error updating discovery registration");
 			},
 			TCP_ACCEPT => self.accept(io), 
 			_ => panic!("Received unknown readable token"),
@@ -806,7 +788,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io),
 			DISCOVERY => {
 				self.discovery.as_ref().unwrap().lock().unwrap().writable();
-				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
+				io.update_registration(DISCOVERY).expect("Error updating discovery registration");
 			}
 			_ => panic!("Received unknown writable token"),
 		}
@@ -819,13 +801,13 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io),
 			DISCOVERY_REFRESH => {
 				self.discovery.as_ref().unwrap().lock().unwrap().refresh();
-				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
+				io.update_registration(DISCOVERY).expect("Error updating discovery registration");
 			},
 			DISCOVERY_ROUND => {
 				if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() {
 					self.update_nodes(io, node_changes);
 				}
-				io.update_registration(DISCOVERY).expect("Error updating disicovery registration");
+				io.update_registration(DISCOVERY).expect("Error updating discovery registration");
 			},
 			_ => match self.timers.read().unwrap().get(&token).cloned() {
 				Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() {

From b6ccbdb6949a3d2a3a9b85b34fa7a6ece0fd1e0c Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Tue, 16 Feb 2016 23:37:24 +0100
Subject: [PATCH 33/45] Lower max handshakes to reduce network load

---
 util/src/network/host.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index bcb1c7585..9560ca81e 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -46,8 +46,8 @@ type Slab<T> = ::slab::Slab<T, usize>;
 
 const _DEFAULT_PORT: u16 = 30304;
 const MAX_SESSIONS: usize = 1024;
-const MAX_HANDSHAKES: usize = 256;
-const MAX_HANDSHAKES_PER_ROUND: usize = 64;
+const MAX_HANDSHAKES: usize = 64;
+const MAX_HANDSHAKES_PER_ROUND: usize = 8;
 const MAINTENANCE_TIMEOUT: u64 = 1000;
 
 #[derive(Debug)]

From 39a98cd555dbb48caf1c9ff1632f5ff9993a9170 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Wed, 17 Feb 2016 01:39:16 +0100
Subject: [PATCH 34/45] Prevent connection deletion until unregister is called;
 minor tweaks

---
 sync/src/chain.rs           | 2 +-
 util/src/network/host.rs    | 6 ++----
 util/src/network/session.rs | 2 +-
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/sync/src/chain.rs b/sync/src/chain.rs
index 8f3d7440b..bbfefb78d 100644
--- a/sync/src/chain.rs
+++ b/sync/src/chain.rs
@@ -1179,7 +1179,7 @@ impl ChainSync {
 		for (peer_id, peer_number) in updated_peers {
 			let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone();
 			if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber {
-				// If we think peer is too far behind just end one latest hash
+				// If we think peer is too far behind just send one latest hash
 				peer_best = last_parent.clone();
 			}
 			sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) {
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index 9560ca81e..fc4e07306 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -682,14 +682,13 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		let mut failure_id = None;
 		match token {
 			FIRST_HANDSHAKE ... LAST_HANDSHAKE => {
-				let mut handshakes = self.handshakes.write().unwrap();
+				let handshakes = self.handshakes.write().unwrap();
 				if let Some(handshake) = handshakes.get(token).cloned() {
 					failure_id = Some(handshake.lock().unwrap().id().clone());
-					handshakes.remove(token);
 				}
 			},
 			FIRST_SESSION ... LAST_SESSION => {
-				let mut sessions = self.sessions.write().unwrap();
+				let sessions = self.sessions.write().unwrap();
 				if let Some(session) = sessions.get(token).cloned() {
 					let s = session.lock().unwrap();
 					if s.is_ready() {
@@ -700,7 +699,6 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 						}
 					}
 					failure_id = Some(s.id().clone());
-					sessions.remove(token);
 				}
 			},
 			_ => {},
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 04fb6d930..572b91a18 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -91,7 +91,7 @@ impl Decodable for PeerCapabilityInfo {
 	}
 }
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug)]
 struct SessionCapabilityInfo {
 	pub protocol: &'static str,
 	pub version: u8,

From e4baf37bf87fe29aa9355412a41016ade2897129 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Wed, 17 Feb 2016 02:55:46 +0100
Subject: [PATCH 35/45] Fixed adding boot nodes to discovery table; Ping
 optimization

---
 util/src/network/discovery.rs | 11 +++++++++--
 util/src/network/host.rs      |  6 +++---
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index f383b74f7..950c66dae 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -149,6 +149,13 @@ impl Discovery {
 		}
 	}
 
+	fn clear_ping(&mut self, id: &NodeId) {
+		let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &id) as usize).unwrap();
+		if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) {
+			node.timeout = None;
+		}
+	}
+
 	fn start(&mut self) {
 		trace!(target: "discovery", "Starting discovery");
 		self.discovery_round = 0;
@@ -388,10 +395,10 @@ impl Discovery {
 			debug!(target: "discovery", "Bad address: {:?}", entry);
 			entry.endpoint.address = from.clone();
 		}
-		self.update_node(entry.clone());
+		self.clear_ping(node);
 		let mut added_map = HashMap::new();
 		added_map.insert(node.clone(), entry); 
-		Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() }))
+		Ok(None)
 	}
 
 	fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index fc4e07306..e470d47d8 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -374,12 +374,12 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 		host.info.write().unwrap().deref_mut().listen_port = port;
 
 		let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone();
-		for n in boot_nodes {
-			host.add_node(&n);
-		}
 		if let Some(ref mut discovery) = host.discovery {
 			discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries());
 		}
+		for n in boot_nodes {
+			host.add_node(&n);
+		}
 		host
 	}
 

From eef193e8bd377b1d9483b814a2999980b5bfb613 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Wed, 17 Feb 2016 14:06:19 +0100
Subject: [PATCH 36/45] Don't add useless peers to table

---
 util/src/network/discovery.rs | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs
index 950c66dae..b12e3b2a1 100644
--- a/util/src/network/discovery.rs
+++ b/util/src/network/discovery.rs
@@ -361,24 +361,21 @@ impl Discovery {
 			debug!(target: "discovery", "Expired ping");
 			return Err(NetworkError::Expired);
 		}
-		let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() };
-		if !entry.endpoint.is_valid() {
-			debug!(target: "discovery", "Got bad address: {:?}, using {:?} instead", entry, from);
-			entry.endpoint.address = from.clone();
+		let mut added_map = HashMap::new();
+		let entry = NodeEntry { id: node.clone(), endpoint: source.clone() };
+		if !entry.endpoint.is_valid() || !entry.endpoint.is_global() {
+			debug!(target: "discovery", "Got bad address: {:?}", entry);
 		}
-		if !entry.endpoint.is_global() {
-			debug!(target: "discovery", "Got local address: {:?}, using {:?} instead", entry, from);
-			entry.endpoint.address = from.clone();
+		else {
+			self.update_node(entry.clone());
+			added_map.insert(node.clone(), entry); 
 		}
-		self.update_node(entry.clone());
 		let hash = rlp.as_raw().sha3();
 		let mut response = RlpStream::new_list(2);
 		dest.to_rlp_list(&mut response);
 		response.append(&hash);
-		self.send_packet(PACKET_PONG, &entry.endpoint.udp_address(), &response.drain());
+		self.send_packet(PACKET_PONG, from, &response.drain());
 		
-		let mut added_map = HashMap::new();
-		added_map.insert(node.clone(), entry); 
 		Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() }))
 	}
 

From c9f3f5e54482e592fb8e36e149dd596b46078efe Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Wed, 17 Feb 2016 14:07:11 +0100
Subject: [PATCH 37/45] Tweaked connection limits to be a bit more aggressive

---
 util/src/network/handshake.rs |  2 +-
 util/src/network/host.rs      | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs
index 1fd830ea0..5d43decd7 100644
--- a/util/src/network/handshake.rs
+++ b/util/src/network/handshake.rs
@@ -68,7 +68,7 @@ pub struct Handshake {
 
 const AUTH_PACKET_SIZE: usize = 307;
 const ACK_PACKET_SIZE: usize = 210;
-const HANDSHAKE_TIMEOUT: u64 = 30000;
+const HANDSHAKE_TIMEOUT: u64 = 5000;
 
 impl Handshake {
 	/// Create a new handshake object
diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index e470d47d8..460cabc7c 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -46,8 +46,8 @@ type Slab<T> = ::slab::Slab<T, usize>;
 
 const _DEFAULT_PORT: u16 = 30304;
 const MAX_SESSIONS: usize = 1024;
-const MAX_HANDSHAKES: usize = 64;
-const MAX_HANDSHAKES_PER_ROUND: usize = 8;
+const MAX_HANDSHAKES: usize = 80;
+const MAX_HANDSHAKES_PER_ROUND: usize = 32;
 const MAINTENANCE_TIMEOUT: u64 = 1000;
 
 #[derive(Debug)]
@@ -977,3 +977,13 @@ fn key_save_load() {
 	let r = load_key(temp_path.as_path());
 	assert_eq!(key, r.unwrap());
 }
+
+
+#[test]
+fn host_client_url() {
+	let mut config = NetworkConfiguration::new();
+	let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2");
+	config.use_secret = Some(key);
+	let host: Host<u32> = Host::new(config);
+	assert!(host.client_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@"));
+}

From 0cfc4cbb3437d9547fc78e85ef5e5b08f08490fb Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Wed, 17 Feb 2016 14:07:26 +0100
Subject: [PATCH 38/45] More tests

---
 util/src/network/error.rs   | 60 ++++++++++++++++++++++++++++++-------
 util/src/network/session.rs |  6 +++-
 2 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/util/src/network/error.rs b/util/src/network/error.rs
index 74babb110..31e1d785b 100644
--- a/util/src/network/error.rs
+++ b/util/src/network/error.rs
@@ -18,21 +18,42 @@ use io::IoError;
 use crypto::CryptoError;
 use rlp::*;
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum DisconnectReason
 {
 	DisconnectRequested,
-	_TCPError,
-	_BadProtocol,
+	TCPError,
+	BadProtocol,
 	UselessPeer,
-	_TooManyPeers,
-	_DuplicatePeer,
-	_IncompatibleProtocol,
-	_NullIdentity,
-	_ClientQuit,
-	_UnexpectedIdentity,
-	_LocalIdentity,
+	TooManyPeers,
+	DuplicatePeer,
+	IncompatibleProtocol,
+	NullIdentity,
+	ClientQuit,
+	UnexpectedIdentity,
+	LocalIdentity,
 	PingTimeout,
+	Unknown,
+}
+
+impl DisconnectReason {
+	pub fn from_u8(n: u8) -> DisconnectReason {
+		match n {
+			0 => DisconnectReason::DisconnectRequested,
+			1 => DisconnectReason::TCPError,
+			2 => DisconnectReason::BadProtocol,
+			3 => DisconnectReason::UselessPeer,
+			4 => DisconnectReason::TooManyPeers,
+			5 => DisconnectReason::DuplicatePeer,
+			6 => DisconnectReason::IncompatibleProtocol,
+			7 => DisconnectReason::NullIdentity,
+			8 => DisconnectReason::ClientQuit,
+			9 => DisconnectReason::UnexpectedIdentity,
+			10 => DisconnectReason::LocalIdentity,
+			11 => DisconnectReason::PingTimeout,
+			_ => DisconnectReason::Unknown,
+		}
+	}
 }
 
 #[derive(Debug)]
@@ -70,3 +91,22 @@ impl From<CryptoError> for NetworkError {
 	}
 }
 
+#[test]
+fn test_errors() {
+	assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8));
+	let mut r = DisconnectReason::DisconnectRequested;
+	for i in 0 .. 20 {
+		r = DisconnectReason::from_u8(i);
+	}
+	assert_eq!(DisconnectReason::Unknown, r);
+
+	match <NetworkError as From<DecoderError>>::from(DecoderError::RlpIsTooBig) {
+		NetworkError::Auth => {},
+		_ => panic!("Unexpeceted error"),
+	}
+
+	match <NetworkError as From<CryptoError>>::from(CryptoError::InvalidSecret) {
+		NetworkError::Auth => {},
+		_ => panic!("Unexpeceted error"),
+	}
+}
diff --git a/util/src/network/session.rs b/util/src/network/session.rs
index 572b91a18..b0db5f7ef 100644
--- a/util/src/network/session.rs
+++ b/util/src/network/session.rs
@@ -231,7 +231,11 @@ impl Session {
 				try!(self.read_hello(&rlp, host));
 				Ok(SessionData::Ready)
 			},
-			PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))),
+			PACKET_DISCONNECT => {
+				let rlp = UntrustedRlp::new(&packet.data[1..]);
+				let reason: u8 = try!(rlp.val_at(0));
+				Err(From::from(NetworkError::Disconnect(DisconnectReason::from_u8(reason))))
+			}
 			PACKET_PING => {
 				try!(self.send_pong());
 				Ok(SessionData::None)

From 2cc690f31f27adb5e761cc676d90b7c94c1afec9 Mon Sep 17 00:00:00 2001
From: Gav Wood <gav@ethcore.io>
Date: Fri, 19 Feb 2016 12:54:51 +0100
Subject: [PATCH 39/45] Better user errors. Fixed up README.

---
 Cargo.lock     |  2 ++
 Cargo.toml     |  2 ++
 README.md      |  2 +-
 parity/main.rs | 64 ++++++++++++++++++++++++++++++++++++--------------
 4 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index b69736c2e..34b618c2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12,7 +12,9 @@ dependencies = [
  "ethcore-util 0.9.99",
  "ethsync 0.9.99",
  "fdlimit 0.1.0",
+ "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 5b59b26f1..f4163253b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,8 @@ ethcore-rpc = { path = "rpc", optional = true }
 fdlimit = { path = "util/fdlimit" }
 target_info = "0.1"
 daemonize = "0.2"
+regex = "0.1"
+lazy_static = "0.1"
 
 [features]
 default = ["rpc"]
diff --git a/README.md b/README.md
index b840195d8..4e238fd6f 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ cd ..
 curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
 
 # install beta and make it default
-sudo multirust default beta
+multirust default beta
 
 # download and build parity
 git clone https://github.com/ethcore/parity
diff --git a/parity/main.rs b/parity/main.rs
index 3279e1fed..aca2b9c03 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -26,17 +26,21 @@ extern crate ethcore;
 extern crate ethsync;
 #[macro_use]
 extern crate log as rlog;
+#[macro_use]
+extern crate lazy_static;
 extern crate env_logger;
 extern crate ctrlc;
 extern crate fdlimit;
 extern crate target_info;
 extern crate daemonize;
+extern crate regex;
 
 #[cfg(feature = "rpc")]
 extern crate ethcore_rpc as rpc;
 
 use std::net::{SocketAddr};
 use std::env;
+use std::process::exit;
 use rlog::{LogLevelFilter};
 use env_logger::LogBuilder;
 use ctrlc::CtrlC;
@@ -51,6 +55,7 @@ use ethsync::EthSync;
 use docopt::Docopt;
 use target_info::Target;
 use daemonize::Daemonize;
+use regex::Regex;
 
 const USAGE: &'static str = "
 Parity. Ethereum Client.
@@ -150,6 +155,16 @@ By Wood/Paronyan/Kotewicz/Drwięga/Volf.\
 ", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os());
 }
 
+fn die_with_message(msg: &str) -> ! {
+	println!("ERROR: {}", msg);
+	exit(1);
+}
+
+#[macro_export]
+macro_rules! die {
+	($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*))));
+}
+
 struct Configuration {
 	args: Args
 }
@@ -174,7 +189,17 @@ impl Configuration {
 			"frontier" | "mainnet" => ethereum::new_frontier(),
 			"morden" | "testnet" => ethereum::new_morden(),
 			"olympic" => ethereum::new_olympic(),
-			f => Spec::from_json_utf8(contents(f).expect("Couldn't read chain specification file. Sure it exists?").as_ref()),
+			f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| die!("{}: Couldn't read chain specification file. Sure it exists?", f)).as_ref()),
+		}
+	}
+
+	fn normalize_enode(e: &str) -> Option<String> {
+		lazy_static! {
+			static ref RE: Regex = Regex::new(r"^enode://([0-9a-fA-F]{64})@(\d+\.\d+\.\d+\.\d+):(\d+)$").unwrap();
+		}
+		match RE.is_match(e) {
+			true => Some(e.to_owned()),
+			false => None,
 		}
 	}
 
@@ -182,7 +207,7 @@ impl Configuration {
 		if self.args.flag_no_bootstrap { Vec::new() } else {
 			match self.args.arg_enode.len() {
 				0 => spec.nodes().clone(),
-				_ => self.args.arg_enode.clone(),	// TODO check format first.
+				_ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s))).collect(),
 			}
 		}
 	}
@@ -197,7 +222,7 @@ impl Configuration {
 				public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address");
 			}
 			Some(ref a) => {
-				public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address");
+				public_address = SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_|die!("{}: Invalid listen/public address given with --address", a));
 				listen_address = public_address;
 			}
 		};
@@ -205,17 +230,28 @@ impl Configuration {
 		(listen_address, public_address)
 	}
 
+	fn net_settings(&self, spec: &Spec) -> NetworkConfiguration {
+		let mut ret = NetworkConfiguration::new();
+		ret.nat_enabled = self.args.flag_upnp;
+		ret.boot_nodes = self.init_nodes(spec);
+		let (listen, public) = self.net_addresses();
+		ret.listen_address = listen;
+		ret.public_address = public;
+		ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.as_bytes().sha3()));
+		ret
+	}
+
 	fn execute(&self) {
 		if self.args.flag_version {
 			print_version();
 			return;
 		}
 		if self.args.cmd_daemon {
-			let daemonize = Daemonize::new().pid_file(self.args.arg_pid_file.clone()).chown_pid_file(true);
-			match daemonize.start() {
-				Ok(_) => info!("Daemonized"),
-				Err(e) => { error!("{}", e); return; },
-			}				
+			Daemonize::new()
+				.pid_file(self.args.arg_pid_file.clone())
+				.chown_pid_file(true)
+				.start()
+				.unwrap_or_else(|e| die!("Couldn't daemonize; {}", e));
 		}
 		self.execute_client();
 	}
@@ -227,15 +263,7 @@ impl Configuration {
 		unsafe { ::fdlimit::raise_fd_limit(); }
 
 		let spec = self.spec();
-
-		// Configure network
-		let mut net_settings = NetworkConfiguration::new();
-		net_settings.nat_enabled = self.args.flag_upnp;
-		net_settings.boot_nodes = self.init_nodes(&spec);
-		let (listen, public) = self.net_addresses();
-		net_settings.listen_address = listen;
-		net_settings.public_address = public;
-		net_settings.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string"));
+		let net_settings = self.net_settings(&spec);
 
 		// Build client
 		let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap();
@@ -265,11 +293,13 @@ impl Configuration {
 
 fn wait_for_exit(client_service: &ClientService) {
 	let exit = Arc::new(Condvar::new());
+
 	// Handle possible exits
 	let e = exit.clone();
 	CtrlC::set_handler(move || { e.notify_all(); });
 	let e = exit.clone();
 	client_service.on_panic(move |_reason| { e.notify_all(); });
+
 	// Wait for signal
 	let mutex = Mutex::new(());
 	let _ = exit.wait(mutex.lock().unwrap()).unwrap();

From 85c842b7fd52c08215ff09eca88d28db18eba103 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Fri, 19 Feb 2016 13:47:13 +0100
Subject: [PATCH 40/45] Restored service test

---
 ethcore/src/service.rs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs
index 9389f1db1..db0260b06 100644
--- a/ethcore/src/service.rs
+++ b/ethcore/src/service.rs
@@ -124,8 +124,6 @@ impl IoHandler<NetSyncMessage> for ClientIoHandler {
 	}
 }
 
-// TODO: rewrite into something that doesn't dependent on the testing environment having a particular port ready for use.
-/*
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -136,8 +134,7 @@ mod tests {
 	fn it_can_be_started() {
 		let spec = get_test_spec();
 		let temp_path = RandomTempPath::new();
-		let service = ClientService::start(spec, NetworkConfiguration::new(), &temp_path.as_path());
+		let service = ClientService::start(spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path());
 		assert!(service.is_ok());
 	}
 }
-*/
\ No newline at end of file

From beab90c70715aaddf6c325e40aa8f125d062a4ef Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Fri, 19 Feb 2016 14:13:20 +0100
Subject: [PATCH 41/45] Added is_valid_node_url

---
 util/src/network/mod.rs        | 1 +
 util/src/network/node_table.rs | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs
index ff52212af..50645f2be 100644
--- a/util/src/network/mod.rs
+++ b/util/src/network/mod.rs
@@ -89,6 +89,7 @@ pub use network::host::NetworkConfiguration;
 pub use network::stats::NetworkStats;
 
 use io::TimerToken;
+pub use network::node_table::is_valid_node_url;
 
 const PROTOCOL_VERSION: u32 = 4;
 
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index 065990a63..f528f7134 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -332,6 +332,11 @@ impl Drop for NodeTable {
 	}
 }
 
+pub fn is_valid_node_url(url: &str) -> bool {
+	use std::str::FromStr;
+	Node::from_str(url).is_ok()
+}
+
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -353,6 +358,7 @@ mod tests {
 
 	#[test]
 	fn node_parse() {
+		assert!(is_valid_node_url("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"));
 		let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
 		assert!(node.is_ok());
 		let node = node.unwrap();

From ab233a941f83fd4f162de2c6a8a10ca5fc917ddd Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Fri, 19 Feb 2016 16:34:31 +0100
Subject: [PATCH 42/45] Slightly improved tests

---
 util/src/network/host.rs       | 7 +++++++
 util/src/network/node_table.rs | 1 +
 util/src/network/tests.rs      | 4 +++-
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/util/src/network/host.rs b/util/src/network/host.rs
index b2be68a32..78fb274fa 100644
--- a/util/src/network/host.rs
+++ b/util/src/network/host.rs
@@ -209,6 +209,12 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 		}
 	}
 
+	/// Send an IO message
+	pub fn message(&self, msg: Message) {
+		self.io.message(NetworkIoMessage::User(msg));
+	}
+
+
 	/// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected.
 	pub fn disable_peer(&self, peer: PeerId) {
 		//TODO: remove capability, disconnect if no capabilities left
@@ -754,6 +760,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
 			io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer");
 			io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer");
 		}
+		self.maintain_network(io)
 	}
 
 	fn stream_hup(&self, io: &IoContext<NetworkIoMessage<Message>>, stream: StreamToken) {
diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs
index f528f7134..7ca060f75 100644
--- a/util/src/network/node_table.rs
+++ b/util/src/network/node_table.rs
@@ -332,6 +332,7 @@ impl Drop for NodeTable {
 	}
 }
 
+/// Check if node url is valid
 pub fn is_valid_node_url(url: &str) -> bool {
 	use std::str::FromStr;
 	Node::from_str(url).is_ok()
diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs
index dc80936d2..44d53bdbe 100644
--- a/util/src/network/tests.rs
+++ b/util/src/network/tests.rs
@@ -74,6 +74,7 @@ impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
 	}
 
 	fn connected(&self, io: &NetworkContext<TestProtocolMessage>, peer: &PeerId) {
+		assert!(io.peer_info(*peer).contains("parity"));
 		if self.drop_session {
 			io.disconnect_peer(*peer)
 		} else {
@@ -86,7 +87,8 @@ impl NetworkProtocolHandler<TestProtocolMessage> for TestProtocol {
 	}
 
 	/// Timer function called after a timeout created with `NetworkContext::timeout`.
-	fn timeout(&self, _io: &NetworkContext<TestProtocolMessage>, timer: TimerToken) {
+	fn timeout(&self, io: &NetworkContext<TestProtocolMessage>, timer: TimerToken) {
+		io.message(TestProtocolMessage { payload: 22 });
 		assert_eq!(timer, 0);
 		self.got_timeout.store(true, AtomicOrdering::Relaxed);
 	}

From 5572d1792d3546df050785e34ebfe3f8712d0961 Mon Sep 17 00:00:00 2001
From: arkpar <arkady.paronyan@gmail.com>
Date: Fri, 19 Feb 2016 18:42:54 +0100
Subject: [PATCH 43/45] Back to original slab crate

---
 Cargo.lock      | 7 +------
 util/Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 250acb5a8..d4d1ceaff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -226,7 +226,7 @@ dependencies = [
  "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "sha3 0.1.0",
- "slab 0.1.4 (git+https://github.com/arkpar/slab.git)",
+ "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -643,11 +643,6 @@ name = "slab"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "slab"
-version = "0.1.4"
-source = "git+https://github.com/arkpar/slab.git#3c9284e1f010e394c9d0359b27464e8fb5c87bf0"
-
 [[package]]
 name = "solicit"
 version = "0.4.4"
diff --git a/util/Cargo.toml b/util/Cargo.toml
index 2675ba56c..c27d4bdc3 100644
--- a/util/Cargo.toml
+++ b/util/Cargo.toml
@@ -23,7 +23,7 @@ elastic-array = "0.4"
 heapsize = "0.3"
 itertools = "0.4"
 crossbeam = "0.2"
-slab = { git = "https://github.com/arkpar/slab.git" }
+slab = "0.1"
 sha3 = { path = "sha3" }
 serde = "0.6.7"
 clippy = { version = "0.0.42", optional = true }

From 6c82e405ddae5de03b784d2608c66a9dc4f8b683 Mon Sep 17 00:00:00 2001
From: Gav Wood <gav@ethcore.io>
Date: Fri, 19 Feb 2016 19:42:23 +0100
Subject: [PATCH 44/45] Remove regex &c., use network code for enode ID.

---
 Cargo.lock     |  1 -
 Cargo.toml     |  2 --
 parity/main.rs | 12 +++---------
 3 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 34b618c2b..8891e4658 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12,7 +12,6 @@ dependencies = [
  "ethcore-util 0.9.99",
  "ethsync 0.9.99",
  "fdlimit 0.1.0",
- "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index f4163253b..5b59b26f1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,8 +19,6 @@ ethcore-rpc = { path = "rpc", optional = true }
 fdlimit = { path = "util/fdlimit" }
 target_info = "0.1"
 daemonize = "0.2"
-regex = "0.1"
-lazy_static = "0.1"
 
 [features]
 default = ["rpc"]
diff --git a/parity/main.rs b/parity/main.rs
index aca2b9c03..0f1f77606 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -26,8 +26,6 @@ extern crate ethcore;
 extern crate ethsync;
 #[macro_use]
 extern crate log as rlog;
-#[macro_use]
-extern crate lazy_static;
 extern crate env_logger;
 extern crate ctrlc;
 extern crate fdlimit;
@@ -40,11 +38,13 @@ extern crate ethcore_rpc as rpc;
 
 use std::net::{SocketAddr};
 use std::env;
+use std::from_str::FromStr;
 use std::process::exit;
 use rlog::{LogLevelFilter};
 use env_logger::LogBuilder;
 use ctrlc::CtrlC;
 use util::*;
+use util::network::node::Node;
 use util::panics::MayPanic;
 use ethcore::spec::*;
 use ethcore::client::*;
@@ -194,13 +194,7 @@ impl Configuration {
 	}
 
 	fn normalize_enode(e: &str) -> Option<String> {
-		lazy_static! {
-			static ref RE: Regex = Regex::new(r"^enode://([0-9a-fA-F]{64})@(\d+\.\d+\.\d+\.\d+):(\d+)$").unwrap();
-		}
-		match RE.is_match(e) {
-			true => Some(e.to_owned()),
-			false => None,
-		}
+		Node::from_str(e).ok().map(|_| e.to_owned())
 	}
 
 	fn init_nodes(&self, spec: &Spec) -> Vec<String> {

From dc3ceeb5bb89d731d9ad2b0bf2431d76cabd84c0 Mon Sep 17 00:00:00 2001
From: Gav Wood <gav@ethcore.io>
Date: Fri, 19 Feb 2016 20:02:23 +0100
Subject: [PATCH 45/45] Use new is_valid_node_url function.

---
 Cargo.lock     |  1 -
 parity/main.rs | 10 +++++-----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index d475f81e1..250acb5a8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13,7 +13,6 @@ dependencies = [
  "ethsync 0.9.99",
  "fdlimit 0.1.0",
  "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
diff --git a/parity/main.rs b/parity/main.rs
index 8930c60e9..58d3a6f4c 100644
--- a/parity/main.rs
+++ b/parity/main.rs
@@ -31,21 +31,18 @@ extern crate ctrlc;
 extern crate fdlimit;
 extern crate target_info;
 extern crate daemonize;
-extern crate regex;
 
 #[cfg(feature = "rpc")]
 extern crate ethcore_rpc as rpc;
 
 use std::net::{SocketAddr};
 use std::env;
-use std::from_str::FromStr;
 use std::process::exit;
 use std::path::PathBuf;
 use rlog::{LogLevelFilter};
 use env_logger::LogBuilder;
 use ctrlc::CtrlC;
 use util::*;
-use util::network::node::Node;
 use util::panics::MayPanic;
 use ethcore::spec::*;
 use ethcore::client::*;
@@ -56,7 +53,6 @@ use ethsync::EthSync;
 use docopt::Docopt;
 use target_info::Target;
 use daemonize::Daemonize;
-use regex::Regex;
 
 const USAGE: &'static str = "
 Parity. Ethereum Client.
@@ -199,7 +195,10 @@ impl Configuration {
 	}
 
 	fn normalize_enode(e: &str) -> Option<String> {
-		Node::from_str(e).ok().map(|_| e.to_owned())
+		match is_valid_node_url(e) {
+			true => Some(e.to_owned()),
+			false => None,
+		}
 	}
 
 	fn init_nodes(&self, spec: &Spec) -> Vec<String> {
@@ -244,6 +243,7 @@ impl Configuration {
 		let mut net_path = PathBuf::from(&self.path());
 		net_path.push("network");
 		ret.config_path = Some(net_path.to_str().unwrap().to_owned());
+		ret
 	}
 
 	fn execute(&self) {