From b3916c2999f961ab5dfbe1caf192e62061727faf Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sun, 15 Jul 2018 19:25:29 +0200 Subject: [PATCH] Remove dependency on parity/network (#323) * Remove dependency on parity/network * Remove dependency on RLP as well * Fix tests * Fix tests again --- substrate/Cargo.lock | 34 +- substrate/substrate/network-libp2p/Cargo.toml | 7 +- .../network-libp2p/src/connection_filter.rs | 31 ++ .../network-libp2p/src/custom_proto.rs | 4 +- .../substrate/network-libp2p/src/error.rs | 221 ++++++++++ substrate/substrate/network-libp2p/src/lib.rs | 23 +- .../network-libp2p/src/network_state.rs | 4 +- .../substrate/network-libp2p/src/service.rs | 6 +- .../substrate/network-libp2p/src/traits.rs | 385 ++++++++++++++++++ .../substrate/network-libp2p/tests/tests.rs | 4 +- substrate/substrate/network/Cargo.toml | 1 - substrate/substrate/network/src/blocks.rs | 2 +- .../substrate/network/src/consensus_gossip.rs | 2 +- substrate/substrate/network/src/error.rs | 2 +- substrate/substrate/network/src/io.rs | 2 +- substrate/substrate/network/src/lib.rs | 3 +- substrate/substrate/network/src/on_demand.rs | 4 +- substrate/substrate/network/src/protocol.rs | 2 +- substrate/substrate/network/src/service.rs | 2 +- substrate/substrate/network/src/sync.rs | 2 +- substrate/substrate/network/src/test/mod.rs | 2 +- 21 files changed, 687 insertions(+), 56 deletions(-) create mode 100644 substrate/substrate/network-libp2p/src/connection_filter.rs create mode 100644 substrate/substrate/network-libp2p/src/error.rs create mode 100644 substrate/substrate/network-libp2p/src/traits.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 45febf685d..f5984faf03 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -659,22 +659,6 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-network" -version = "1.12.0" -source = "git+https://github.com/paritytech/parity.git#4145be863bec10038fc0ac5d36a41365b5087344" -dependencies = [ - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-crypto 0.1.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", - "ipnetwork 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1 (git+https://github.com/paritytech/parity.git)", - "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", -] - [[package]] name = "ethereum-types" version = "0.3.2" @@ -2584,15 +2568,6 @@ name = "smallvec" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "snappy" -version = "0.1.0" -source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" -dependencies = [ - "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", - "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", -] - [[package]] name = "snappy-sys" version = "0.1.0" @@ -2786,7 +2761,6 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2811,14 +2785,18 @@ dependencies = [ name = "substrate-network-libp2p" version = "0.1.0" dependencies = [ + "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)", "ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)", "ethcore-logger 1.12.0 (git+https://github.com/paritytech/parity.git)", - "ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)", "libp2p 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=77b1c445807e53b8c5e4e5e2da751222da15b8cc)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3915,7 +3893,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ethcore-crypto 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-io 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-logger 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" -"checksum ethcore-network 1.12.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)" = "" @@ -4093,7 +4070,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum smallvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "872c0ff227000041c520cca51e883b858d388ab0ecf646bab76f065cebaec025" "checksum smallvec 0.6.0 (git+https://github.com/Vurich/rust-smallvec.git?branch=array-zero)" = "" "checksum smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03dab98ab5ded3a8b43b2c80751194608d0b2aa0f1d46cf95d1c35e192844aa7" -"checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" diff --git a/substrate/substrate/network-libp2p/Cargo.toml b/substrate/substrate/network-libp2p/Cargo.toml index 442b807ad2..3292bd4cd9 100644 --- a/substrate/substrate/network-libp2p/Cargo.toml +++ b/substrate/substrate/network-libp2p/Cargo.toml @@ -8,12 +8,16 @@ authors = ["Parity Technologies "] [dependencies] bytes = "0.4" +error-chain = { version = "0.12", default-features = false } fnv = "1.0" futures = "0.1" libp2p = { git = "https://github.com/tomaka/libp2p-rs", rev = "77b1c445807e53b8c5e4e5e2da751222da15b8cc", default-features = false, features = ["libp2p-secio", "libp2p-secio-secp256k1"] } -ethcore-network = { git = "https://github.com/paritytech/parity.git" } +ethcore-io = { git = "https://github.com/paritytech/parity.git" } ethkey = { git = "https://github.com/paritytech/parity.git" } +ethereum-types = "0.3" +ipnetwork = "0.12.6" parking_lot = "0.5" +libc = "0.2" log = "0.3" rand = "0.5.0" tokio-core = "0.1" @@ -22,6 +26,7 @@ tokio-timer = "0.2" varint = { git = "https://github.com/libp2p/rust-libp2p" } [dev-dependencies] +assert_matches = "1.2" ethcore-bytes = { git = "https://github.com/paritytech/parity.git" } ethcore-io = { git = "https://github.com/paritytech/parity.git" } ethcore-logger = { git = "https://github.com/paritytech/parity.git" } diff --git a/substrate/substrate/network-libp2p/src/connection_filter.rs b/substrate/substrate/network-libp2p/src/connection_filter.rs new file mode 100644 index 0000000000..e146aee4c7 --- /dev/null +++ b/substrate/substrate/network-libp2p/src/connection_filter.rs @@ -0,0 +1,31 @@ +// Copyright 2015-2018 Parity Technologies (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 . + +//! Connection filter trait. + +use super::NodeId; + +/// Filtered connection direction. +pub enum ConnectionDirection { + Inbound, + Outbound, +} + +/// Connection filter. Each connection is checked against `connection_allowed`. +pub trait ConnectionFilter : Send + Sync { + /// Filter a connection. Returns `true` if connection should be allowed. `false` if rejected. + fn connection_allowed(&self, own_id: &NodeId, connecting_id: &NodeId, direction: ConnectionDirection) -> bool; +} diff --git a/substrate/substrate/network-libp2p/src/custom_proto.rs b/substrate/substrate/network-libp2p/src/custom_proto.rs index ed98377951..2d8f772659 100644 --- a/substrate/substrate/network-libp2p/src/custom_proto.rs +++ b/substrate/substrate/network-libp2p/src/custom_proto.rs @@ -15,9 +15,9 @@ // along with Polkadot. If not, see .? use bytes::{Bytes, BytesMut}; -use network::ProtocolId; +use ProtocolId; use libp2p::core::{Multiaddr, ConnectionUpgrade, Endpoint}; -use network::PacketId; +use PacketId; use std::io::Error as IoError; use std::vec::IntoIter as VecIntoIter; use futures::{future, Future, stream, Stream, Sink}; diff --git a/substrate/substrate/network-libp2p/src/error.rs b/substrate/substrate/network-libp2p/src/error.rs new file mode 100644 index 0000000000..b60ca6f706 --- /dev/null +++ b/substrate/substrate/network-libp2p/src/error.rs @@ -0,0 +1,221 @@ +// Copyright 2015-2018 Parity Technologies (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 . + +use std::{io, net, fmt}; +use libc::{ENFILE, EMFILE}; +use io::IoError; +use ethkey; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum DisconnectReason +{ + DisconnectRequested, + TCPError, + BadProtocol, + UselessPeer, + 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, + } + } +} + +impl fmt::Display for DisconnectReason { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::DisconnectReason::*; + + let msg = match *self { + DisconnectRequested => "disconnect requested", + TCPError => "TCP error", + BadProtocol => "bad protocol", + UselessPeer => "useless peer", + TooManyPeers => "too many peers", + DuplicatePeer => "duplicate peer", + IncompatibleProtocol => "incompatible protocol", + NullIdentity => "null identity", + ClientQuit => "client quit", + UnexpectedIdentity => "unexpected identity", + LocalIdentity => "local identity", + PingTimeout => "ping timeout", + Unknown => "unknown", + }; + + f.write_str(msg) + } +} + +error_chain! { + foreign_links { + SocketIo(IoError) #[doc = "Socket IO error."]; + } + + errors { + #[doc = "Error concerning the network address parsing subsystem."] + AddressParse { + description("Failed to parse network address"), + display("Failed to parse network address"), + } + + #[doc = "Error concerning the network address resolution subsystem."] + AddressResolve(err: Option) { + description("Failed to resolve network address"), + display("Failed to resolve network address {}", err.as_ref().map_or("".to_string(), |e| e.to_string())), + } + + #[doc = "Authentication failure"] + Auth { + description("Authentication failure"), + display("Authentication failure"), + } + + #[doc = "Unrecognised protocol"] + BadProtocol { + description("Bad protocol"), + display("Bad protocol"), + } + + #[doc = "Expired message"] + Expired { + description("Expired message"), + display("Expired message"), + } + + #[doc = "Peer not found"] + PeerNotFound { + description("Peer not found"), + display("Peer not found"), + } + + #[doc = "Peer is disconnected"] + Disconnect(reason: DisconnectReason) { + description("Peer disconnected"), + display("Peer disconnected: {}", reason), + } + + #[doc = "Invalid node id"] + InvalidNodeId { + description("Invalid node id"), + display("Invalid node id"), + } + + #[doc = "Packet size is over the protocol limit"] + OversizedPacket { + description("Packet is too large"), + display("Packet is too large"), + } + + #[doc = "Reached system resource limits for this process"] + ProcessTooManyFiles { + description("Too many open files in process."), + display("Too many open files in this process. Check your resource limits and restart parity"), + } + + #[doc = "Reached system wide resource limits"] + SystemTooManyFiles { + description("Too many open files on system."), + display("Too many open files on system. Consider closing some processes/release some file handlers or increas the system-wide resource limits and restart parity."), + } + + #[doc = "An unknown IO error occurred."] + Io(err: io::Error) { + description("IO Error"), + display("Unexpected IO error: {}", err), + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(ENFILE) => ErrorKind::ProcessTooManyFiles.into(), + Some(EMFILE) => ErrorKind::SystemTooManyFiles.into(), + _ => Error::from_kind(ErrorKind::Io(err)) + } + } +} + +impl From for Error { + fn from(_err: ethkey::Error) -> Self { + ErrorKind::Auth.into() + } +} + +impl From for Error { + fn from(_err: ethkey::crypto::Error) -> Self { + ErrorKind::Auth.into() + } +} + +impl From for Error { + fn from(_err: net::AddrParseError) -> Self { ErrorKind::AddressParse.into() } +} + +#[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); +} + +#[test] +fn test_io_errors() { + use libc::{EMFILE, ENFILE}; + + assert_matches!( + >::from( + io::Error::from_raw_os_error(ENFILE) + ).kind(), + ErrorKind::ProcessTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(EMFILE) + ).kind(), + ErrorKind::SystemTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(0) + ).kind(), + ErrorKind::Io(_)); +} diff --git a/substrate/substrate/network-libp2p/src/lib.rs b/substrate/substrate/network-libp2p/src/lib.rs index 59104fcd84..b94e7c64d1 100644 --- a/substrate/substrate/network-libp2p/src/lib.rs +++ b/substrate/substrate/network-libp2p/src/lib.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see .? +#![recursion_limit="128"] #![type_length_limit = "268435456"] extern crate parking_lot; @@ -23,27 +24,43 @@ extern crate tokio_core; extern crate tokio_io; extern crate tokio_timer; extern crate ethkey; -extern crate ethcore_network as network; +extern crate libc; extern crate libp2p; extern crate rand; extern crate bytes; extern crate varint; +extern crate ethcore_io as io; +extern crate ethereum_types; +extern crate ipnetwork; + +#[macro_use] +extern crate error_chain; #[macro_use] extern crate log; +#[cfg(test)] #[macro_use] +extern crate assert_matches; +pub use connection_filter::{ConnectionFilter, ConnectionDirection}; +pub use io::TimerToken; +pub use error::{Error, ErrorKind, DisconnectReason}; +pub use traits::*; + +mod connection_filter; mod custom_proto; +mod error; mod network_state; mod service; mod timeouts; +mod traits; mod transport; pub use service::NetworkService; /// Check if node url is valid -pub fn validate_node_url(url: &str) -> Result<(), network::Error> { +pub fn validate_node_url(url: &str) -> Result<(), Error> { match url.parse::() { Ok(_) => Ok(()), - Err(_) => Err(network::ErrorKind::InvalidNodeId.into()), + Err(_) => Err(ErrorKind::InvalidNodeId.into()), } } diff --git a/substrate/substrate/network-libp2p/src/network_state.rs b/substrate/substrate/network-libp2p/src/network_state.rs index 5ab87be061..f0977a69b0 100644 --- a/substrate/substrate/network-libp2p/src/network_state.rs +++ b/substrate/substrate/network-libp2p/src/network_state.rs @@ -24,8 +24,8 @@ use libp2p::peerstore::{Peerstore, PeerAccess}; use libp2p::peerstore::json_peerstore::JsonPeerstore; use libp2p::peerstore::memory_peerstore::MemoryPeerstore; use libp2p::secio; -use network::{Error, ErrorKind, NetworkConfiguration, NonReservedPeerMode}; -use network::{PeerId, ProtocolId, SessionInfo}; +use {Error, ErrorKind, NetworkConfiguration, NonReservedPeerMode}; +use {PeerId, ProtocolId, SessionInfo}; use parking_lot::{Mutex, RwLock}; use rand::{self, Rng}; use std::cmp; diff --git a/substrate/substrate/network-libp2p/src/service.rs b/substrate/substrate/network-libp2p/src/service.rs index 1983fc60eb..b8238edaf9 100644 --- a/substrate/substrate/network-libp2p/src/service.rs +++ b/substrate/substrate/network-libp2p/src/service.rs @@ -15,8 +15,8 @@ // along with Polkadot. If not, see .? use bytes::Bytes; -use network::{Error, ErrorKind, NetworkConfiguration, NetworkProtocolHandler}; -use network::{NonReservedPeerMode, NetworkContext, PeerId, ProtocolId}; +use {Error, ErrorKind, NetworkConfiguration, NetworkProtocolHandler}; +use {NonReservedPeerMode, NetworkContext, PeerId, ProtocolId}; use parking_lot::{Mutex, RwLock}; use libp2p; use libp2p::multiaddr::{AddrComponent, Multiaddr}; @@ -29,7 +29,7 @@ use libp2p::core::{upgrade, Transport, MuxedTransport, ConnectionUpgrade}; use libp2p::core::{Endpoint, PeerId as PeerstorePeerId, PublicKey}; use libp2p::core::SwarmController; use libp2p::ping; -use network::{PacketId, SessionInfo, ConnectionFilter, TimerToken}; +use {PacketId, SessionInfo, ConnectionFilter, TimerToken}; use rand; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::iter; diff --git a/substrate/substrate/network-libp2p/src/traits.rs b/substrate/substrate/network-libp2p/src/traits.rs new file mode 100644 index 0000000000..b707a664d8 --- /dev/null +++ b/substrate/substrate/network-libp2p/src/traits.rs @@ -0,0 +1,385 @@ +// Copyright 2015-2018 Parity Technologies (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 . + +use std::cmp::Ordering; +use std::collections::HashMap; +use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; +use std::str::{self, FromStr}; +use std::sync::Arc; +use std::time::Duration; +use io::TimerToken; +use ipnetwork::{IpNetwork, IpNetworkError}; +use error::Error; +use ethkey::Secret; +use ethereum_types::H512; + +/// Protocol handler level packet id +pub type PacketId = u8; +/// Protocol / handler id +pub type ProtocolId = [u8; 3]; + +/// Node public key +pub type NodeId = H512; + +/// Local (temporary) peer session ID. +pub type PeerId = usize; + +/// Messages used to communitate with the event loop from other threads. +#[derive(Clone)] +pub enum NetworkIoMessage { + /// Register a new protocol handler. + AddHandler { + /// Handler shared instance. + handler: Arc, + /// Protocol Id. + protocol: ProtocolId, + /// Supported protocol versions and number of packet IDs reserved by the protocol (packet count). + versions: Vec<(u8, u8)>, + }, + /// Register a new protocol timer + AddTimer { + /// Protocol Id. + protocol: ProtocolId, + /// Timer token. + token: TimerToken, + /// Timer delay. + delay: Duration, + }, + /// Initliaze public interface. + InitPublicInterface, + /// Disconnect a peer. + Disconnect(PeerId), + /// Disconnect and temporary disable peer. + DisablePeer(PeerId), + /// Network has been started with the host as the given enode. + NetworkStarted(String), +} + +/// Shared session information +#[derive(Debug, Clone)] +pub struct SessionInfo { + /// Peer public key + pub id: Option, + /// Peer client ID + pub client_version: String, + /// Peer RLPx protocol version + pub protocol_version: u32, + /// Session protocol capabilities + pub capabilities: Vec, + /// Peer protocol capabilities + pub peer_capabilities: Vec, + /// Peer ping delay + pub ping: Option, + /// True if this session was originated by us. + pub originated: bool, + /// Remote endpoint address of the session + pub remote_address: String, + /// Local endpoint address of the session + pub local_address: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PeerCapabilityInfo { + pub protocol: ProtocolId, + pub version: u8, +} + +impl ToString for PeerCapabilityInfo { + fn to_string(&self) -> String { + format!("{}/{}", str::from_utf8(&self.protocol[..]).unwrap_or("???"), self.version) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SessionCapabilityInfo { + pub protocol: [u8; 3], + pub version: u8, + pub packet_count: u8, + pub id_offset: u8, +} + +impl PartialOrd for SessionCapabilityInfo { + fn partial_cmp(&self, other: &SessionCapabilityInfo) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for SessionCapabilityInfo { + fn cmp(&self, b: &SessionCapabilityInfo) -> Ordering { + // By protocol id first + if self.protocol != b.protocol { + return self.protocol.cmp(&b.protocol); + } + // By version + self.version.cmp(&b.version) + } +} + +/// Network service configuration +#[derive(Debug, PartialEq, Clone)] +pub struct NetworkConfiguration { + /// Directory path to store general network configuration. None means nothing will be saved + pub config_path: Option, + /// Directory path to store network-specific configuration. None means nothing will be saved + pub net_config_path: Option, + /// IP address to listen for incoming connections. Listen to all connections by default + pub listen_address: Option, + /// IP address to advertise. Detected automatically if none. + pub public_address: Option, + /// Port for UDP connections, same as TCP by default + pub udp_port: Option, + /// Enable NAT configuration + pub nat_enabled: bool, + /// Enable discovery + pub discovery_enabled: bool, + /// List of initial node addresses + pub boot_nodes: Vec, + /// Use provided node key instead of default + pub use_secret: Option, + /// Minimum number of connected peers to maintain + pub min_peers: u32, + /// Maximum allowed number of peers + pub max_peers: u32, + /// Maximum handshakes + pub max_handshakes: u32, + /// Reserved protocols. Peers with protocol get additional connection slots. + pub reserved_protocols: HashMap, + /// List of reserved node addresses. + pub reserved_nodes: Vec, + /// The non-reserved peer mode. + pub non_reserved_mode: NonReservedPeerMode, + /// IP filter + pub ip_filter: IpFilter, + /// Client identifier + pub client_version: String, +} + +impl Default for NetworkConfiguration { + fn default() -> Self { + NetworkConfiguration::new() + } +} + +impl NetworkConfiguration { + /// Create a new instance of default settings. + pub fn new() -> Self { + NetworkConfiguration { + config_path: None, + net_config_path: None, + listen_address: None, + public_address: None, + udp_port: None, + nat_enabled: true, + discovery_enabled: true, + boot_nodes: Vec::new(), + use_secret: None, + min_peers: 25, + max_peers: 50, + max_handshakes: 64, + reserved_protocols: HashMap::new(), + ip_filter: IpFilter::default(), + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + client_version: "Parity-network".into(), + } + } + + /// Create new default configuration with specified listen port. + pub fn new_with_port(port: u16) -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port))); + config + } + + /// Create new default configuration for localhost-only connection with random port (usefull for testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0))); + config.nat_enabled = false; + config + } +} + +/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem. +pub trait NetworkContext { + /// Send a packet over the network to another peer. + fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), Error>; + + /// Send a packet over the network to another peer using specified protocol. + fn send_protocol(&self, protocol: ProtocolId, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), Error>; + + /// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing. + fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), Error>; + + /// Disconnect a peer and prevent it from connecting again. + fn disable_peer(&self, peer: PeerId); + + /// Disconnect peer. Reconnect can be attempted later. + fn disconnect_peer(&self, peer: PeerId); + + /// Check if the session is still active. + fn is_expired(&self) -> bool; + + /// Register a new IO timer. 'IoHandler::timeout' will be called with the token. + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error>; + + /// Returns peer identification string + fn peer_client_version(&self, peer: PeerId) -> String; + + /// Returns information on p2p session + fn session_info(&self, peer: PeerId) -> Option; + + /// Returns max version for a given protocol. + fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option; + + /// Returns this object's subprotocol name. + fn subprotocol_name(&self) -> ProtocolId; +} + +impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { + fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), Error> { + (**self).send(peer, packet_id, data) + } + + fn send_protocol(&self, protocol: ProtocolId, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), Error> { + (**self).send_protocol(protocol, peer, packet_id, data) + } + + fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), Error> { + (**self).respond(packet_id, data) + } + + fn disable_peer(&self, peer: PeerId) { + (**self).disable_peer(peer) + } + + fn disconnect_peer(&self, peer: PeerId) { + (**self).disconnect_peer(peer) + } + + fn is_expired(&self) -> bool { + (**self).is_expired() + } + + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> { + (**self).register_timer(token, delay) + } + + fn peer_client_version(&self, peer: PeerId) -> String { + (**self).peer_client_version(peer) + } + + fn session_info(&self, peer: PeerId) -> Option { + (**self).session_info(peer) + } + + fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option { + (**self).protocol_version(protocol, peer) + } + + fn subprotocol_name(&self) -> ProtocolId { + (**self).subprotocol_name() + } +} + +/// 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. +pub trait NetworkProtocolHandler: Sync + Send { + /// Initialize the handler + fn initialize(&self, _io: &NetworkContext) {} + /// Called when new network packet received. + fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]); + /// Called when new peer is connected. Only called when peer supports the same protocol. + fn connected(&self, io: &NetworkContext, peer: &PeerId); + /// Called when a previously connected peer disconnects. + fn disconnected(&self, io: &NetworkContext, peer: &PeerId); + /// Timer function called after a timeout created with `NetworkContext::timeout`. + fn timeout(&self, _io: &NetworkContext, _timer: TimerToken) {} +} + +/// Non-reserved peer modes. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonReservedPeerMode { + /// Accept them. This is the default. + Accept, + /// Deny them. + Deny, +} + +impl NonReservedPeerMode { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Option { + match s { + "accept" => Some(NonReservedPeerMode::Accept), + "deny" => Some(NonReservedPeerMode::Deny), + _ => None, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct IpFilter { + pub predefined: AllowIP, + pub custom_allow: Vec, + pub custom_block: Vec, +} + +impl Default for IpFilter { + fn default() -> Self { + IpFilter { + predefined: AllowIP::All, + custom_allow: vec![], + custom_block: vec![], + } + } +} + +impl IpFilter { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Result { + let mut filter = IpFilter::default(); + for f in s.split_whitespace() { + match f { + "all" => filter.predefined = AllowIP::All, + "private" => filter.predefined = AllowIP::Private, + "public" => filter.predefined = AllowIP::Public, + "none" => filter.predefined = AllowIP::None, + custom => { + if custom.starts_with("-") { + filter.custom_block.push(IpNetwork::from_str(&custom.to_owned().split_off(1))?) + } else { + filter.custom_allow.push(IpNetwork::from_str(custom)?) + } + } + } + } + Ok(filter) + } +} + +/// IP fiter +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum AllowIP { + /// Connect to any address + All, + /// Connect to private network only + Private, + /// Connect to public network only + Public, + /// Block all addresses + None, +} diff --git a/substrate/substrate/network-libp2p/tests/tests.rs b/substrate/substrate/network-libp2p/tests/tests.rs index a70baf0aaf..f763c87e90 100644 --- a/substrate/substrate/network-libp2p/tests/tests.rs +++ b/substrate/substrate/network-libp2p/tests/tests.rs @@ -18,7 +18,6 @@ extern crate parking_lot; extern crate ethcore_bytes; extern crate ethcore_io as io; extern crate ethcore_logger; -extern crate ethcore_network; extern crate substrate_network_libp2p; extern crate ethkey; @@ -28,8 +27,7 @@ use std::thread; use std::time::*; use parking_lot::Mutex; use ethcore_bytes::Bytes; -use ethcore_network::*; -use substrate_network_libp2p::NetworkService; +use substrate_network_libp2p::*; use ethkey::{Random, Generator}; use io::TimerToken; diff --git a/substrate/substrate/network/Cargo.toml b/substrate/substrate/network/Cargo.toml index eaa61d1114..930f5307c3 100644 --- a/substrate/substrate/network/Cargo.toml +++ b/substrate/substrate/network/Cargo.toml @@ -18,7 +18,6 @@ serde_derive = "1.0" serde_json = "1.0" futures = "0.1.17" linked-hash-map = "0.5" -ethcore-network = { git = "https://github.com/paritytech/parity.git" } ethcore-io = { git = "https://github.com/paritytech/parity.git" } ed25519 = { path = "../../substrate/ed25519" } substrate-primitives = { path = "../../substrate/primitives" } diff --git a/substrate/substrate/network/src/blocks.rs b/substrate/substrate/network/src/blocks.rs index d0f7c75744..075b2edc75 100644 --- a/substrate/substrate/network/src/blocks.rs +++ b/substrate/substrate/network/src/blocks.rs @@ -19,7 +19,7 @@ use std::cmp; use std::ops::Range; use std::collections::{HashMap, BTreeMap}; use std::collections::hash_map::Entry; -use network::PeerId; +use network_libp2p::PeerId; use runtime_primitives::traits::{Block as BlockT, NumberFor, As}; use message; diff --git a/substrate/substrate/network/src/consensus_gossip.rs b/substrate/substrate/network/src/consensus_gossip.rs index dfaae818d5..37925d302a 100644 --- a/substrate/substrate/network/src/consensus_gossip.rs +++ b/substrate/substrate/network/src/consensus_gossip.rs @@ -20,7 +20,7 @@ use std::collections::{HashMap, HashSet}; use futures::sync::mpsc; use std::time::{Instant, Duration}; -use network::PeerId; +use network_libp2p::PeerId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use runtime_primitives::generic::BlockId; use message::{self, generic::Message as GenericMessage}; diff --git a/substrate/substrate/network/src/error.rs b/substrate/substrate/network/src/error.rs index 120cfe0b4f..e5c860cf9a 100644 --- a/substrate/substrate/network/src/error.rs +++ b/substrate/substrate/network/src/error.rs @@ -16,7 +16,7 @@ //! Polkadot service possible errors. -use network::Error as NetworkError; +use network_libp2p::Error as NetworkError; use client; error_chain! { diff --git a/substrate/substrate/network/src/io.rs b/substrate/substrate/network/src/io.rs index 2a67888b65..d8f4c81254 100644 --- a/substrate/substrate/network/src/io.rs +++ b/substrate/substrate/network/src/io.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see .? -use network::{NetworkContext, PeerId, Error as NetworkError, SessionInfo}; +use network_libp2p::{NetworkContext, PeerId, Error as NetworkError, SessionInfo}; /// IO interface for the syncing handler. /// Provides peer connection management and an interface to the blockchain client. diff --git a/substrate/substrate/network/src/lib.rs b/substrate/substrate/network/src/lib.rs index d4982d5ef2..b0e3e7c7e4 100644 --- a/substrate/substrate/network/src/lib.rs +++ b/substrate/substrate/network/src/lib.rs @@ -19,7 +19,6 @@ //! Substrate-specific P2P networking: synchronizing blocks, propagating BFT messages. //! Allows attachment of an optional subprotocol for chain-specific requests. -extern crate ethcore_network as network; extern crate ethcore_io as core_io; extern crate linked_hash_map; extern crate rand; @@ -65,7 +64,7 @@ pub use service::{Service, FetchFuture, ConsensusService, BftMessageStream, TransactionPool, Params, ManageNetwork, SyncProvider}; pub use protocol::{ProtocolStatus, PeerInfo, Context}; pub use sync::{Status as SyncStatus, SyncState}; -pub use network::{NonReservedPeerMode, NetworkConfiguration, PeerId, ProtocolId, ConnectionFilter, ConnectionDirection}; +pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, PeerId, ProtocolId, ConnectionFilter, ConnectionDirection}; pub use message::{generic as generic_message, RequestId, BftMessage, LocalizedBftMessage, ConsensusVote, SignedConsensusVote, SignedConsensusMessage, SignedConsensusProposal, Status as StatusMessage}; pub use error::Error; pub use config::{Role, ProtocolConfig}; diff --git a/substrate/substrate/network/src/on_demand.rs b/substrate/substrate/network/src/on_demand.rs index 8ed0f06984..2011462622 100644 --- a/substrate/substrate/network/src/on_demand.rs +++ b/substrate/substrate/network/src/on_demand.rs @@ -28,7 +28,7 @@ use client; use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; use io::SyncIo; use message; -use network::PeerId; +use network_libp2p::PeerId; use service; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; @@ -325,7 +325,7 @@ mod tests { use client; use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; use message; - use network::PeerId; + use network_libp2p::PeerId; use service::{Role, ExecuteInContext}; use test::TestIo; use super::{REQUEST_TIMEOUT, OnDemand, OnDemandService}; diff --git a/substrate/substrate/network/src/protocol.rs b/substrate/substrate/network/src/protocol.rs index c0f5f2eabb..79ccbc419f 100644 --- a/substrate/substrate/network/src/protocol.rs +++ b/substrate/substrate/network/src/protocol.rs @@ -22,7 +22,7 @@ use parking_lot::RwLock; use serde_json; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash, HashFor, As}; use runtime_primitives::generic::BlockId; -use network::PeerId; +use network_libp2p::PeerId; use message::{self, Message}; use message::generic::Message as GenericMessage; diff --git a/substrate/substrate/network/src/service.rs b/substrate/substrate/network/src/service.rs index 9405455df3..8bcd800371 100644 --- a/substrate/substrate/network/src/service.rs +++ b/substrate/substrate/network/src/service.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::io; use std::time::Duration; use futures::sync::{oneshot, mpsc}; -use network::{NetworkProtocolHandler, NetworkContext, PeerId, ProtocolId, +use network_libp2p::{NetworkProtocolHandler, NetworkContext, PeerId, ProtocolId, NetworkConfiguration , NonReservedPeerMode, ErrorKind}; use network_libp2p::{NetworkService}; use core_io::{TimerToken}; diff --git a/substrate/substrate/network/src/sync.rs b/substrate/substrate/network/src/sync.rs index 878016b985..48a0d66557 100644 --- a/substrate/substrate/network/src/sync.rs +++ b/substrate/substrate/network/src/sync.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use protocol::Context; -use network::PeerId; +use network_libp2p::PeerId; use client::{ImportResult, BlockStatus, ClientInfo}; use blocks::{self, BlockCollection}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor}; diff --git a/substrate/substrate/network/src/test/mod.rs b/substrate/substrate/network/src/test/mod.rs index 0207108e2a..09b795e82f 100644 --- a/substrate/substrate/network/src/test/mod.rs +++ b/substrate/substrate/network/src/test/mod.rs @@ -28,7 +28,7 @@ use io::SyncIo; use protocol::{Context, Protocol}; use config::ProtocolConfig; use service::TransactionPool; -use network::{PeerId, SessionInfo, Error as NetworkError}; +use network_libp2p::{PeerId, SessionInfo, Error as NetworkError}; use keyring::Keyring; use codec::Slicable; use test_client::{self, TestClient};