{"action":"created","comment":{"url":"https://api.github.com/repos/paritytech/polkadot/pulls/comments/201068338","pull_request_review_id":135497818,"id":201068338,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMTA2ODMzOA==","diff_hunk":"@@ -0,0 +1,1038 @@\n+// Copyright 2018 Parity Technologies (UK) Ltd.\n+// This file is part of Polkadot.\n+\n+// Polkadot is free software: you can redistribute it and/or modify\n+// it under the terms of the GNU General Public License as published by\n+// the Free Software Foundation, either version 3 of the License, or\n+// (at your option) any later version.\n+\n+// Polkadot is distributed in the hope that it will be useful,\n+// but WITHOUT ANY WARRANTY; without even the implied warranty of\n+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+// GNU General Public License for more details.\n+\n+// You should have received a copy of the GNU General Public License\n+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.?\n+\n+use bytes::Bytes;\n+use network::{Error, ErrorKind, NetworkConfiguration, NetworkProtocolHandler, NonReservedPeerMode};\n+use network::{NetworkContext, PeerId, ProtocolId};\n+use parking_lot::{Mutex, RwLock};\n+use libp2p;\n+use libp2p::multiaddr::{AddrComponent, Multiaddr};\n+use libp2p::kad::{KadSystem, KadConnecConfig, KadSystemConfig, KadIncomingRequest, KadConnecController, KadPeer, KadConnectionType, KadQueryEvent};\n+use libp2p::identify::{IdentifyInfo, IdentifyOutput, IdentifyTransportOutcome, IdentifyProtocolConfig, PeerIdTransport};\n+use libp2p::core::{upgrade, Transport, MuxedTransport, ConnectionUpgrade, Endpoint, PeerId as PeerstorePeerId, PublicKey, SwarmController};\n+use libp2p::ping;\n+use network::{PacketId, SessionInfo, ConnectionFilter, TimerToken};\n+use rand;\n+use std::io::{Error as IoError, ErrorKind as IoErrorKind};\n+use std::iter;\n+use std::net::{IpAddr, Ipv4Addr, SocketAddr};\n+use std::sync::Arc;\n+use std::sync::mpsc as sync_mpsc;\n+use std::thread;\n+use std::time::{Duration, Instant};\n+use futures::{future, Future, Stream, IntoFuture};\n+use futures::sync::{mpsc, oneshot};\n+use tokio_core::reactor::{Core, Handle};\n+use tokio_io::{AsyncRead, AsyncWrite};\n+use tokio_timer;\n+\n+use custom_proto::{RegisteredProtocol, RegisteredProtocols, RegisteredProtocolOutput};\n+use network_state::NetworkState;\n+use timeouts;\n+use transport;\n+\n+/// IO Service with networking.\n+pub struct NetworkService {\n+\tshared: Arc<Shared>,\n+\n+\t/// Holds the networking-running background thread alive. The `Option` is `None` if the service\n+\t/// is stopped.\n+\t/// Sending a message on the channel will trigger the end of the background thread. We can\n+\t/// then wait on the join handle.\n+\tbg_thread: Mutex<Option<(oneshot::Sender<()>, thread::JoinHandle<()>)>>,\n+}\n+\n+/// Common struct shared throughout all the components of the service.\n+struct Shared {\n+\t/// Original configuration of the service.\n+\tconfig: NetworkConfiguration,\n+\n+\t/// Contains the state of the network.\n+\tnetwork_state: NetworkState,\n+\n+\t/// Kademlia system. Contains the DHT.\n+\tkad_system: KadSystem,\n+\n+\t/// Configuration for the Kademlia upgrade.\n+\tkad_upgrade: KadConnecConfig,\n+\n+\t/// List of protocols available on the network. It is a logic error to remote protocols from\n+\t/// this list, and the code may assume that protocols stay at the same index forever.\n+\tprotocols: RwLock<RegisteredProtocols<Arc<NetworkProtocolHandler + Send + Sync>>>,\n+\n+\t/// Use this channel to send a timeout request to the background thread's events loop.\n+\t/// After the timeout, elapsed, it will call `timeout` on the `NetworkProtocolHandler`.\n+\t/// This can be closed if the background thread is not running. The sender will be overwritten\n+\t/// every time we start the service.\n+\ttimeouts_register_tx: RwLock<mpsc::UnboundedSender<(Instant, (Arc<NetworkProtocolHandler + Send + Sync>, ProtocolId, TimerToken))>>,\n+\n+\t/// Original address from the configuration, after being adjusted by the `Transport`.\n+\t/// Contains `None` if the network hasn't started yet.\n+\toriginal_listened_addr: RwLock<Option<Multiaddr>>,\n+\n+\t/// Contains the addresses we known about ourselves.\n+\tlistened_addrs: RwLock<Vec<Multiaddr>>,\n+}\n+\n+impl NetworkService {\n+\t/// Starts IO event loop\n+\tpub fn new(config: NetworkConfiguration, filter: Option<Arc<ConnectionFilter>>) -> Result<NetworkService, Error> {\n+\t\t// TODO: for now `filter` is always `None` ; remove it from the code or implement it\n+\t\tassert!(filter.is_none());\n+\n+\t\tlet network_state = NetworkState::new(&config)?;\n+\n+\t\tlet local_peer_id = network_state.local_public_key().clone().into_peer_id();\n+\t\tinfo!(target: \"sub-libp2p\", \"Local node id = {:?}\", local_peer_id);\t// TODO: debug! instead?\n+\n+\t\tlet kad_system = KadSystem::without_init(KadSystemConfig {\n+\t\t\tparallelism: 3,\n+\t\t\tlocal_peer_id: local_peer_id.clone(),\n+\t\t\tkbuckets_timeout: Duration::from_secs(10),\n+\t\t\trequest_timeout: Duration::from_secs(10),\n+\t\t\tknown_initial_peers: network_state.known_peers().collect(),\n+\t\t});\n+\n+\t\tlet shared = Arc::new(Shared {\n+\t\t\tnetwork_state,\n+\t\t\tprotocols: RwLock::new(Default::default()),\n+\t\t\tkad_system,\n+\t\t\tkad_upgrade: KadConnecConfig::new(),\n+\t\t\tconfig,\n+\t\t\ttimeouts_register_tx: RwLock::new(mpsc::unbounded().0),\n+\t\t\toriginal_listened_addr: RwLock::new(None),\n+\t\t\tlistened_addrs: RwLock::new(Vec::new()),\n+\t\t});\n+\n+\t\tOk(NetworkService {\n+\t\t\tshared,\n+\t\t\tbg_thread: Mutex::new(None),\n+\t\t})\n+\t}\n+\n+\t/// Register a new protocol handler with the event loop.\n+\tpub fn register_protocol(&self, handler: Arc<NetworkProtocolHandler + Send + Sync>, protocol: ProtocolId, versions: &[(u8, u8)]) {\n+\t\tif self.shared.network_state.has_connected_peer() {\n+\t\t\t// TODO: figure out if that's correct\n+\t\t\twarn!(target: \"sub-libp2p\", \"a new network protocol was registered while the service \\\n+\t\t\t\twas already active ; this is a programmer error\");\n+\t\t}\n+\n+\t\tself.shared.protocols.write().0\n+\t\t\t.push(RegisteredProtocol::new(handler.clone(), protocol, versions));\n+\n+\t\thandler.initialize(&NetworkContextImpl {\n+\t\t\tinner: self.shared.clone(),\n+\t\t\tprotocol: protocol.clone(),\n+\t\t\tcurrent_peer: None,\n+\t\t});\n+\t}\n+\n+\t/// Returns network configuration.\n+\tpub fn config(&self) -> &NetworkConfiguration {\n+\t\t&self.shared.config\n+\t}\n+\n+\tpub fn external_url(&self) -> Option<String> {\n+\t\t// TODO: in the context of libp2p, it is hard to define what an external URL is, as\n+\t\t//\t\t different nodes can have multiple different ways to reach us\n+\t\tself.shared.original_listened_addr.read().as_ref()\n+\t\t\t.map(|addr|\n+\t\t\t\tformat!(\"{}/p2p/{}\", addr, self.shared.kad_system.local_peer_id().to_base58())\n+\t\t\t)\n+\t}\n+\n+\t/// Start network IO\n+\t// TODO (design): the notion of having a `NetworkService` alive should mean that it is \n+\t// running ; the `start` and `stop` functions are bad design\n+\tpub fn start(&self) -> Result<(), (Error, Option<SocketAddr>)> {\n+\t\t// TODO: check that service is started already?\n+\n+\t\t*self.shared.protocols.write() = Default::default();\n+\n+\t\t// channel we use to signal success or failure of the bg thread initialization process\n+\t\tlet (init_tx, init_rx) = sync_mpsc::channel();\n+\t\t// channel the main thread uses to signal the bg thread that it should stop\n+\t\tlet (close_tx, close_rx) = oneshot::channel();\n+\t\tlet (timeouts_register_tx, timeouts_register_rx) = mpsc::unbounded();\n+\t\tlet shared = self.shared.clone();\n+\t\tlet join_handle = thread::spawn(move || {\n+\t\t\t// Tokio core that is going to run everything in this thread.\n+\t\t\tlet mut core = match Core::new() {\n+\t\t\t\tOk(c) => c,\n+\t\t\t\tErr(err) => { let _ = init_tx.send(Err(err.into())); return; }\n+\t\t\t};\n+\n+\t\t\tlet fut = match init_thread(core.handle(), shared, timeouts_register_rx, close_rx) {\n+\t\t\t\tOk(future) => {\n+\t\t\t\t\tdebug!(target: \"sub-libp2p\", \"Successfully started networking service\");\n+\t\t\t\t\tlet _ = init_tx.send(Ok(()));\n+\t\t\t\t\tfuture\n+\t\t\t\t},\n+\t\t\t\tErr(err) => {\n+\t\t\t\t\tlet _ = init_tx.send(Err(err));\n+\t\t\t\t\treturn;\n+\t\t\t\t}\n+\t\t\t};\n+\n+\t\t\tmatch core.run(fut) {\n+\t\t\t\tOk(()) => debug!(target: \"sub-libp2p\", \"libp2p future finished\"),\n+\t\t\t\tErr(err) => error!(target: \"sub-libp2p\", \"error while running libp2p: {:?}\", err),\n+\t\t\t}\n+\t\t});\n+\n+\t\tinit_rx.recv().expect(\"libp2p background thread panicked\")\n+\t\t\t.map_err(|err| (err, self.shared.config.listen_address.clone()))?;\n+\n+\t\t*self.bg_thread.lock() = Some((close_tx, join_handle));\n+\t\t*self.shared.timeouts_register_tx.write() = timeouts_register_tx;\n+\t\tOk(())\n+\t}\n+\n+\t/// Stop network IO.\n+\tpub fn stop(&self) {\n+\t\tif let Some((close_tx, join)) = self.bg_thread.lock().take() {\n+\t\t\tlet _ = close_tx.send(());\n+\t\t\tif let Err(e) = join.join() {\n+\t\t\t\twarn!(target: \"sub-libp2p\", \"error while waiting on libp2p background \\\n+\t\t\t\t\tthread: {:?}\", e);\n+\t\t\t}\n+\t\t}\n+\n+\t\tdebug_assert!(!self.shared.network_state.has_connected_peer());\n+\t}\n+\n+\t/// Get a list of all connected peers by id.\n+\tpub fn connected_peers(&self) -> Vec<PeerId> {\n+\t\tself.shared.network_state.connected_peers()\n+\t}\n+\n+\t/// Try to add a reserved peer.\n+\tpub fn add_reserved_peer(&self, peer: &str) -> Result<(), Error> {\n+\t\t// TODO: try to dial the peer?\n+\t\tself.shared.network_state.add_reserved_peer(peer)\n+\t}\n+\n+\t/// Try to remove a reserved peer.\n+\tpub fn remove_reserved_peer(&self, peer: &str) -> Result<(), Error> {\n+\t\tself.shared.network_state.remove_reserved_peer(peer)\n+\t}\n+\n+\t/// Set the non-reserved peer mode.\n+\tpub fn set_non_reserved_mode(&self, mode: NonReservedPeerMode) {\n+\t\tself.shared.network_state.set_non_reserved_mode(mode)\n+\t}\n+\n+\t/// Executes action in the network context\n+\tpub fn with_context<F>(&self, protocol: ProtocolId, action: F) where F: FnOnce(&NetworkContext) {\n+\t\tself.with_context_eval(protocol, action);\n+\t}\n+\n+\t/// Evaluates function in the network context\n+\tpub fn with_context_eval<F, T>(&self, protocol: ProtocolId, action: F) -> Option<T>\n+\t\twhere F: FnOnce(&NetworkContext) -> T\n+\t{\n+\t\tif !self.shared.protocols.read().has_protocol(protocol) {\n+\t\t\treturn None;\n+\t\t}\n+\n+\t\tSome(action(&NetworkContextImpl {\n+\t\t\tinner: self.shared.clone(),\n+\t\t\tprotocol: protocol.clone(),\n+\t\t\tcurrent_peer: None,\n+\t\t}))\n+\t}\n+}\n+\n+impl Drop for NetworkService {\n+\tfn drop(&mut self) {\n+\t\tself.stop();\n+\t}\n+}\n+\n+#[derive(Clone)]\n+struct NetworkContextImpl {\n+\tinner: Arc<Shared>,\n+\tprotocol: ProtocolId,\n+\tcurrent_peer: Option<PeerId>,\n+}\n+\n+impl NetworkContext for NetworkContextImpl {\n+\tfn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {\n+\t\tself.send_protocol(self.protocol, peer, packet_id, data)\n+\t}\n+\n+\tfn send_protocol(&self, protocol: ProtocolId, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {\n+\t\tdebug_assert!(self.inner.protocols.read().has_protocol(protocol),\n+\t\t\t\"invalid protocol id requested in the API of the libp2p networking\");\n+\t\t// TODO: restore\n+\t\t//debug_assert!(packet_id < self.inner.protocols.read().iter().find(|p| p.id == protocol).unwrap().packet_count,\n+\t\t//\t\t\t  \"invalid packet id requested in the API of the libp2p networking\");\n+\t\t// TODO: could be \"optimized\" by building `message` only after checking the validity of\n+\t\t// \t\tthe peer, but that's probably not worth the effort\n+\t\tlet mut message = Bytes::with_capacity(1 + data.len());\n+\t\tmessage.extend_from_slice(&[packet_id]);\n+\t\tmessage.extend_from_slice(&data);\n+\t\tself.inner.network_state.send(protocol, peer, message)\n+\t}\n+\n+\tfn respond(&self, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {\n+\t\tif let Some(peer) = self.current_peer {\n+\t\t\tself.send_protocol(self.protocol, peer, packet_id, data)\n+\t\t} else {\n+\t\t\tpanic!(\"respond() called outside of a received message\");\n+\t\t}\n+\t}\n+\n+\tfn disable_peer(&self, peer: PeerId) {\n+\t\tdebug!(target: \"sub-libp2p\", \"Request to disable peer {}\", peer);\n+\t\tself.inner.network_state.disable_peer(peer);\n+\t}\n+\n+\tfn disconnect_peer(&self, peer: PeerId) {\n+\t\tdebug!(target: \"sub-libp2p\", \"Request to disconnect peer {}\", peer);\n+\t\tself.inner.network_state.disconnect_peer(peer);\n+\t}\n+\n+\tfn is_expired(&self) -> bool {\n+\t\tif let Some(current_peer) = self.current_peer {\n+\t\t\t!self.inner.network_state.is_peer_connected(current_peer)\n+\t\t} else {\n+\t\t\t// TODO: is this correct?\n+\t\t\ttrue\n+\t\t}\n+\t}\n+\n+\tfn register_timer(&self, token: usize, duration: Duration) -> Result<(), Error> {\n+\t\tlet handler = self.inner.protocols\n+\t\t\t.read()\n+\t\t\t.find_protocol(self.protocol)\n+\t\t\t.ok_or(ErrorKind::BadProtocol)?\n+\t\t\t.custom_data()\n+\t\t\t.clone();\n+\t\tlet at = Instant::now() + duration;\n+\t\tself.inner.timeouts_register_tx.read()\n+\t\t\t.unbounded_send((at, (handler, self.protocol, token)))\n+\t\t\t.map_err(|err| {\n+\t\t\t\tErrorKind::Io(IoError::new(IoErrorKind::Other, err))\n+\t\t\t})?;\n+\t\tOk(())\n+\t}\n+\n+\tfn peer_client_version(&self, peer: PeerId) -> String {\n+\t\t// Devp2p returns \"unknown\" on unknown peer ID, so we do the same.\n+\t\tself.inner.network_state.peer_client_version(peer, self.protocol)\n+\t\t\t.unwrap_or_else(|| \"unknown\".to_string())\n+\t}\n+\n+\tfn session_info(&self, peer: PeerId) -> Option<SessionInfo> {\n+\t\tself.inner.network_state.session_info(peer, self.protocol)\n+\t}\n+\n+\tfn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option<u8> {\n+\t\tself.inner.network_state.protocol_version(peer, protocol)\n+\t}\n+\n+\tfn subprotocol_name(&self) -> ProtocolId {\n+\t\tself.protocol.clone()\n+\t}\n+}\n+\n+/// Builds the main `Future` for the network service.\n+///\n+/// - `timeouts_register_rx` should receive newly-registered timeouts.\n+/// - `close_rx` should be triggered when we want to close the network.\n+fn init_thread(\n+\tcore: Handle,\n+\tshared: Arc<Shared>,\n+\ttimeouts_register_rx: mpsc::UnboundedReceiver<(Instant, (Arc<NetworkProtocolHandler + Send + Sync + 'static>, ProtocolId, TimerToken))>,\n+\tclose_rx: oneshot::Receiver<()>\n+) -> Result<impl Future<Item = (), Error = IoError>, Error> {\n+\t// Build the transport layer.\n+\tlet transport = {\n+\t\tlet base = transport::build_transport(core.clone(), transport::UnencryptedAllowed::Denied,\n+\t\t\tshared.network_state.local_private_key().clone());\n+\n+\t\tlet addr_resolver = {\n+\t\t\tlet shared = shared.clone();\n+\t\t\tmove |peer_id| {\n+\t\t\t\tlet addrs = shared.network_state.addrs_of_peer(&peer_id);\n+\t\t\t\ttrace!(target: \"sub-libp2p\", \"Peer store: loaded {} addresses for {:?}\",\n+\t\t\t\t\taddrs.len(), peer_id);\n+\t\t\t\taddrs.into_iter()\n+\t\t\t}\n+\t\t};\n+\n+\t\tPeerIdTransport::new(base.clone(), addr_resolver).and_then({\n+\t\t\tlet shared = shared.clone();\n+\t\t\tmove |out, endpoint, remote_addr| {\n+\t\t\t\tlet original_addr = out.original_addr.clone();\n+\t\t\t\tlet info = out.info.and_then(move |info| {\n+\t\t\t\t\tprocess_identify_info(shared, &info, original_addr, endpoint, &base)?;\n+\t\t\t\t\tOk(info)\n+\t\t\t\t});\n+\n+\t\t\t\tlet out = TransportOutput {\n+\t\t\t\t\tsocket: out.socket,\n+\t\t\t\t\tinfo: Box::new(info) as Box<_>,\n+\t\t\t\t\toriginal_addr: out.original_addr,\n+\t\t\t\t};\n+\n+\t\t\t\tfuture::ok((out, remote_addr))\n+\t\t\t}\n+\t\t})\n+\t};\n+\n+\t// Build the swarm. The swarm is the single entry point where successfully negotiated protocols\n+\t// arrive.\n+\tlet (swarm_controller, swarm_future) = {\n+\t\tlet upgraded_transport = transport.clone()\n+\t\t\t.and_then({\n+\t\t\t\tlet shared = shared.clone();\n+\t\t\t\tmove |out, endpoint, client_addr| {\n+\t\t\t\t\tlet original_addr = out.original_addr;\n+\t\t\t\t\tlet listener_upgrade = upgrade::or(upgrade::or(upgrade::or(\n+\t\t\t\t\t\tupgrade::map(shared.kad_upgrade.clone(), FinalUpgrade::Kad),\n+\t\t\t\t\t\tupgrade::map(IdentifyProtocolConfig, |id| FinalUpgrade::Identify(id, original_addr))),\n+\t\t\t\t\t\tupgrade::map(ping::Ping, |(p, f)| FinalUpgrade::Ping(p, f))),\n+\t\t\t\t\t\tupgrade::map(DelayedProtosList(shared), FinalUpgrade::Custom));\n+\t\t\t\t\tupgrade::apply(out.socket, listener_upgrade, endpoint, client_addr)\n+\t\t\t\t}\n+\t\t\t})\n+\t\t\t.map(|out, _| (out, Endpoint::Listener));\n+\t\tlet shared = shared.clone();\n+\n+\t\tlibp2p::core::swarm(\n+\t\t\tupgraded_transport,\n+\t\t\tmove |(upgrade, endpoint), client_addr| {","path":"substrate/network-libp2p/src/service.rs","position":420,"original_position":420,"commit_id":"e5390ab9f81105847484edce32c4d7c350b74fbb","original_commit_id":"e5390ab9f81105847484edce32c4d7c350b74fbb","user":{"login":"gavofyork","id":138296,"node_id":"MDQ6VXNlcjEzODI5Ng==","avatar_url":"https://avatars0.githubusercontent.com/u/138296?v=4","gravatar_id":"","url":"https://api.github.com/users/gavofyork","html_url":"https://github.com/gavofyork","followers_url":"https://api.github.com/users/gavofyork/followers","following_url":"https://api.github.com/users/gavofyork/following{/other_user}","gists_url":"https://api.github.com/users/gavofyork/gists{/gist_id}","starred_url":"https://api.github.com/users/gavofyork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gavofyork/subscriptions","organizations_url":"https://api.github.com/users/gavofyork/orgs","repos_url":"https://api.github.com/users/gavofyork/repos","events_url":"https://api.github.com/users/gavofyork/events{/privacy}","received_events_url":"https://api.github.com/users/gavofyork/received_events","type":"User","site_admin":false},"body":"unneeded `{`","created_at":"2018-07-09T16:35:00Z","updated_at":"2018-07-09T16:35:00Z","html_url":"https://github.com/paritytech/polkadot/pull/268#discussion_r201068338","pull_request_url":"https://api.github.com/repos/paritytech/polkadot/pulls/268","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/comments/201068338"},"html":{"href":"https://github.com/paritytech/polkadot/pull/268#discussion_r201068338"},"pull_request":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/268"}}},"pull_request":{"url":"https://api.github.com/repos/paritytech/polkadot/pulls/268","id":198464942,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk4NDY0OTQy","html_url":"https://github.com/paritytech/polkadot/pull/268","diff_url":"https://github.com/paritytech/polkadot/pull/268.diff","patch_url":"https://github.com/paritytech/polkadot/pull/268.patch","issue_url":"https://api.github.com/repos/paritytech/polkadot/issues/268","number":268,"state":"open","locked":false,"title":"Switch from devp2p to libp2p","user":{"login":"tomaka","id":1412254,"node_id":"MDQ6VXNlcjE0MTIyNTQ=","avatar_url":"https://avatars1.githubusercontent.com/u/1412254?v=4","gravatar_id":"","url":"https://api.github.com/users/tomaka","html_url":"https://github.com/tomaka","followers_url":"https://api.github.com/users/tomaka/followers","following_url":"https://api.github.com/users/tomaka/following{/other_user}","gists_url":"https://api.github.com/users/tomaka/gists{/gist_id}","starred_url":"https://api.github.com/users/tomaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomaka/subscriptions","organizations_url":"https://api.github.com/users/tomaka/orgs","repos_url":"https://api.github.com/users/tomaka/repos","events_url":"https://api.github.com/users/tomaka/events{/privacy}","received_events_url":"https://api.github.com/users/tomaka/received_events","type":"User","site_admin":false},"body":"Close #187 \r\nFollow-up of #263 \r\n\r\nRemoves the `ethcore-network-devp2p` crate and integrates a new `substrate-libp2p` crate.\r\nThe API of this crate is exactly the same as devp2p, so the replacement is quite straight-forward.\r\nOnce this is merged I would like to refactor a bit the networking API in order to make it less error-prone.\r\n\r\nWhat the code does on the wire is it performs a random Kademlia `FIND_NODE` request every 30 seconds, and tries to open the `/substrate/dot/0` protocol with each of the resulting nodes (until we reach `min_peers`, after which it only listens to connections).\r\nConsequently, in practice the bootstrap nodes should be used only for Kademlia and not for substrate/dot, unless there are not enough nodes available.\r\n\r\nThe format of a peer address in libp2p is not `enode://...@...`, but `/ip4/1.2.3.4/tcp/10000/p2p/Qm...` (or `/ip6/::1/tcp/10000/p2p/Qm...`) where the `Qm` part is the base56 encoding of a peer ID.\r\n\r\nNAT traversal \"works\" in the sense that nodes have knowledge of their external IP and report it. However there is no such thing as UDP hole punching implemented yet.\r\n\r\nNote that the code can be greatly simplified by having the network immediately start when we create the service, and by passing a list of protocols to the constructor instead of registering them afterwards.\r\n\r\nI will only do these changes after this PR has been merged, in order to not introduce merge conflicts.\r\n\r\nI will continue to push commits on this branch in order to improve readability and reliability, but you can can start playing with it if you want. Since the change surface is really low, it should be easily rebasable on any other branch.\r\n","created_at":"2018-06-30T07:40:57Z","updated_at":"2018-07-09T16:35:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bc9e28a3e0f3bea4e0360ff1337ec1a60ca51910","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":746560607,"node_id":"MDU6TGFiZWw3NDY1NjA2MDc=","url":"https://api.github.com/repos/paritytech/polkadot/labels/A0-pleasereview","name":"A0-pleasereview","color":"666666","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/paritytech/polkadot/pulls/268/commits","review_comments_url":"https://api.github.com/repos/paritytech/polkadot/pulls/268/comments","review_comment_url":"https://api.github.com/repos/paritytech/polkadot/pulls/comments{/number}","comments_url":"https://api.github.com/repos/paritytech/polkadot/issues/268/comments","statuses_url":"https://api.github.com/repos/paritytech/polkadot/statuses/e5390ab9f81105847484edce32c4d7c350b74fbb","head":{"label":"paritytech:tka-libp2p","ref":"tka-libp2p","sha":"e5390ab9f81105847484edce32c4d7c350b74fbb","user":{"login":"paritytech","id":14176906,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTc2OTA2","avatar_url":"https://avatars2.githubusercontent.com/u/14176906?v=4","gravatar_id":"","url":"https://api.github.com/users/paritytech","html_url":"https://github.com/paritytech","followers_url":"https://api.github.com/users/paritytech/followers","following_url":"https://api.github.com/users/paritytech/following{/other_user}","gists_url":"https://api.github.com/users/paritytech/gists{/gist_id}","starred_url":"https://api.github.com/users/paritytech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paritytech/subscriptions","organizations_url":"https://api.github.com/users/paritytech/orgs","repos_url":"https://api.github.com/users/paritytech/repos","events_url":"https://api.github.com/users/paritytech/events{/privacy}","received_events_url":"https://api.github.com/users/paritytech/received_events","type":"Organization","site_admin":false},"repo":{"id":109872620,"node_id":"MDEwOlJlcG9zaXRvcnkxMDk4NzI2MjA=","name":"polkadot","full_name":"paritytech/polkadot","owner":{"login":"paritytech","id":14176906,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTc2OTA2","avatar_url":"https://avatars2.githubusercontent.com/u/14176906?v=4","gravatar_id":"","url":"https://api.github.com/users/paritytech","html_url":"https://github.com/paritytech","followers_url":"https://api.github.com/users/paritytech/followers","following_url":"https://api.github.com/users/paritytech/following{/other_user}","gists_url":"https://api.github.com/users/paritytech/gists{/gist_id}","starred_url":"https://api.github.com/users/paritytech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paritytech/subscriptions","organizations_url":"https://api.github.com/users/paritytech/orgs","repos_url":"https://api.github.com/users/paritytech/repos","events_url":"https://api.github.com/users/paritytech/events{/privacy}","received_events_url":"https://api.github.com/users/paritytech/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/paritytech/polkadot","description":"Polkadot Node Implementation","fork":false,"url":"https://api.github.com/repos/paritytech/polkadot","forks_url":"https://api.github.com/repos/paritytech/polkadot/forks","keys_url":"https://api.github.com/repos/paritytech/polkadot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/paritytech/polkadot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/paritytech/polkadot/teams","hooks_url":"https://api.github.com/repos/paritytech/polkadot/hooks","issue_events_url":"https://api.github.com/repos/paritytech/polkadot/issues/events{/number}","events_url":"https://api.github.com/repos/paritytech/polkadot/events","assignees_url":"https://api.github.com/repos/paritytech/polkadot/assignees{/user}","branches_url":"https://api.github.com/repos/paritytech/polkadot/branches{/branch}","tags_url":"https://api.github.com/repos/paritytech/polkadot/tags","blobs_url":"https://api.github.com/repos/paritytech/polkadot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/paritytech/polkadot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/paritytech/polkadot/git/refs{/sha}","trees_url":"https://api.github.com/repos/paritytech/polkadot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/paritytech/polkadot/statuses/{sha}","languages_url":"https://api.github.com/repos/paritytech/polkadot/languages","stargazers_url":"https://api.github.com/repos/paritytech/polkadot/stargazers","contributors_url":"https://api.github.com/repos/paritytech/polkadot/contributors","subscribers_url":"https://api.github.com/repos/paritytech/polkadot/subscribers","subscription_url":"https://api.github.com/repos/paritytech/polkadot/subscription","commits_url":"https://api.github.com/repos/paritytech/polkadot/commits{/sha}","git_commits_url":"https://api.github.com/repos/paritytech/polkadot/git/commits{/sha}","comments_url":"https://api.github.com/repos/paritytech/polkadot/comments{/number}","issue_comment_url":"https://api.github.com/repos/paritytech/polkadot/issues/comments{/number}","contents_url":"https://api.github.com/repos/paritytech/polkadot/contents/{+path}","compare_url":"https://api.github.com/repos/paritytech/polkadot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/paritytech/polkadot/merges","archive_url":"https://api.github.com/repos/paritytech/polkadot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/paritytech/polkadot/downloads","issues_url":"https://api.github.com/repos/paritytech/polkadot/issues{/number}","pulls_url":"https://api.github.com/repos/paritytech/polkadot/pulls{/number}","milestones_url":"https://api.github.com/repos/paritytech/polkadot/milestones{/number}","notifications_url":"https://api.github.com/repos/paritytech/polkadot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/paritytech/polkadot/labels{/name}","releases_url":"https://api.github.com/repos/paritytech/polkadot/releases{/id}","deployments_url":"https://api.github.com/repos/paritytech/polkadot/deployments","created_at":"2017-11-07T18:08:53Z","updated_at":"2018-07-09T16:01:40Z","pushed_at":"2018-07-09T09:26:09Z","git_url":"git://github.com/paritytech/polkadot.git","ssh_url":"git@github.com:paritytech/polkadot.git","clone_url":"https://github.com/paritytech/polkadot.git","svn_url":"https://github.com/paritytech/polkadot","homepage":null,"size":26547,"stargazers_count":254,"watchers_count":254,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":53,"mirror_url":null,"archived":false,"open_issues_count":49,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":53,"open_issues":49,"watchers":254,"default_branch":"master"}},"base":{"label":"paritytech:master","ref":"master","sha":"6f7f8bf93e1aabf4659b4fb2a84eaa294c326751","user":{"login":"paritytech","id":14176906,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTc2OTA2","avatar_url":"https://avatars2.githubusercontent.com/u/14176906?v=4","gravatar_id":"","url":"https://api.github.com/users/paritytech","html_url":"https://github.com/paritytech","followers_url":"https://api.github.com/users/paritytech/followers","following_url":"https://api.github.com/users/paritytech/following{/other_user}","gists_url":"https://api.github.com/users/paritytech/gists{/gist_id}","starred_url":"https://api.github.com/users/paritytech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paritytech/subscriptions","organizations_url":"https://api.github.com/users/paritytech/orgs","repos_url":"https://api.github.com/users/paritytech/repos","events_url":"https://api.github.com/users/paritytech/events{/privacy}","received_events_url":"https://api.github.com/users/paritytech/received_events","type":"Organization","site_admin":false},"repo":{"id":109872620,"node_id":"MDEwOlJlcG9zaXRvcnkxMDk4NzI2MjA=","name":"polkadot","full_name":"paritytech/polkadot","owner":{"login":"paritytech","id":14176906,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTc2OTA2","avatar_url":"https://avatars2.githubusercontent.com/u/14176906?v=4","gravatar_id":"","url":"https://api.github.com/users/paritytech","html_url":"https://github.com/paritytech","followers_url":"https://api.github.com/users/paritytech/followers","following_url":"https://api.github.com/users/paritytech/following{/other_user}","gists_url":"https://api.github.com/users/paritytech/gists{/gist_id}","starred_url":"https://api.github.com/users/paritytech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paritytech/subscriptions","organizations_url":"https://api.github.com/users/paritytech/orgs","repos_url":"https://api.github.com/users/paritytech/repos","events_url":"https://api.github.com/users/paritytech/events{/privacy}","received_events_url":"https://api.github.com/users/paritytech/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/paritytech/polkadot","description":"Polkadot Node Implementation","fork":false,"url":"https://api.github.com/repos/paritytech/polkadot","forks_url":"https://api.github.com/repos/paritytech/polkadot/forks","keys_url":"https://api.github.com/repos/paritytech/polkadot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/paritytech/polkadot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/paritytech/polkadot/teams","hooks_url":"https://api.github.com/repos/paritytech/polkadot/hooks","issue_events_url":"https://api.github.com/repos/paritytech/polkadot/issues/events{/number}","events_url":"https://api.github.com/repos/paritytech/polkadot/events","assignees_url":"https://api.github.com/repos/paritytech/polkadot/assignees{/user}","branches_url":"https://api.github.com/repos/paritytech/polkadot/branches{/branch}","tags_url":"https://api.github.com/repos/paritytech/polkadot/tags","blobs_url":"https://api.github.com/repos/paritytech/polkadot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/paritytech/polkadot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/paritytech/polkadot/git/refs{/sha}","trees_url":"https://api.github.com/repos/paritytech/polkadot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/paritytech/polkadot/statuses/{sha}","languages_url":"https://api.github.com/repos/paritytech/polkadot/languages","stargazers_url":"https://api.github.com/repos/paritytech/polkadot/stargazers","contributors_url":"https://api.github.com/repos/paritytech/polkadot/contributors","subscribers_url":"https://api.github.com/repos/paritytech/polkadot/subscribers","subscription_url":"https://api.github.com/repos/paritytech/polkadot/subscription","commits_url":"https://api.github.com/repos/paritytech/polkadot/commits{/sha}","git_commits_url":"https://api.github.com/repos/paritytech/polkadot/git/commits{/sha}","comments_url":"https://api.github.com/repos/paritytech/polkadot/comments{/number}","issue_comment_url":"https://api.github.com/repos/paritytech/polkadot/issues/comments{/number}","contents_url":"https://api.github.com/repos/paritytech/polkadot/contents/{+path}","compare_url":"https://api.github.com/repos/paritytech/polkadot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/paritytech/polkadot/merges","archive_url":"https://api.github.com/repos/paritytech/polkadot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/paritytech/polkadot/downloads","issues_url":"https://api.github.com/repos/paritytech/polkadot/issues{/number}","pulls_url":"https://api.github.com/repos/paritytech/polkadot/pulls{/number}","milestones_url":"https://api.github.com/repos/paritytech/polkadot/milestones{/number}","notifications_url":"https://api.github.com/repos/paritytech/polkadot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/paritytech/polkadot/labels{/name}","releases_url":"https://api.github.com/repos/paritytech/polkadot/releases{/id}","deployments_url":"https://api.github.com/repos/paritytech/polkadot/deployments","created_at":"2017-11-07T18:08:53Z","updated_at":"2018-07-09T16:01:40Z","pushed_at":"2018-07-09T09:26:09Z","git_url":"git://github.com/paritytech/polkadot.git","ssh_url":"git@github.com:paritytech/polkadot.git","clone_url":"https://github.com/paritytech/polkadot.git","svn_url":"https://github.com/paritytech/polkadot","homepage":null,"size":26547,"stargazers_count":254,"watchers_count":254,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":53,"mirror_url":null,"archived":false,"open_issues_count":49,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":53,"open_issues":49,"watchers":254,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/268"},"html":{"href":"https://github.com/paritytech/polkadot/pull/268"},"issue":{"href":"https://api.github.com/repos/paritytech/polkadot/issues/268"},"comments":{"href":"https://api.github.com/repos/paritytech/polkadot/issues/268/comments"},"review_comments":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/268/comments"},"review_comment":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/paritytech/polkadot/pulls/268/commits"},"statuses":{"href":"https://api.github.com/repos/paritytech/polkadot/statuses/e5390ab9f81105847484edce32c4d7c350b74fbb"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"gavofyork"}}