mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
Update libp2p to v0.3 (#1634)
* Update libp2p * Some more diagnostics * 30 seconds back to 5 seconds * Bump libp2p-core and improve test * Fix runtime Cargo.lock * More work * Finish upgrade to libp2p 0.3 * Add a maximum of 60 seconds for the rounds * Remove env_logger * Update Cargo.lock * Update Cargo.lock in test-runtime * Fix test compilation * Make the test pass * Add identify addresses to Kademlia * Don't connect to nodes we're already connected to * Add warning for non-Substrate nodes * Fix external address not added * Start in Enabled mode
This commit is contained in:
committed by
Arkadiy Paronyan
parent
7d8ae2df5c
commit
b6fd967dfb
@@ -6,7 +6,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
substrate-primitives = { path = "../primitives" }
|
||||
crypto = { package = "parity-crypto", version = "0.2", default-features = false }
|
||||
crypto = { package = "parity-crypto", version = "0.3", default-features = false }
|
||||
error-chain = "0.12"
|
||||
hex = "0.3"
|
||||
rand = "0.6"
|
||||
|
||||
@@ -24,6 +24,7 @@ use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use error_chain::{error_chain, error_chain_processing, impl_error_chain_processed,
|
||||
@@ -60,11 +61,11 @@ struct EncryptedKey {
|
||||
salt: [u8; 32],
|
||||
ciphertext: Vec<u8>, // FIXME: switch to fixed-size when serde supports
|
||||
iv: [u8; 16],
|
||||
iterations: u32,
|
||||
iterations: NonZeroU32,
|
||||
}
|
||||
|
||||
impl EncryptedKey {
|
||||
fn encrypt(plain: &[u8; PKCS_LEN], password: &str, iterations: u32) -> Self {
|
||||
fn encrypt(plain: &[u8; PKCS_LEN], password: &str, iterations: NonZeroU32) -> Self {
|
||||
use rand::{Rng, rngs::OsRng};
|
||||
|
||||
let mut rng = OsRng::new().expect("OS Randomness available on all supported platforms; qed");
|
||||
@@ -149,7 +150,11 @@ impl Store {
|
||||
/// Generate a new key, placing it into the store.
|
||||
pub fn generate(&self, password: &str) -> Result<Pair> {
|
||||
let (pair, pkcs_bytes) = Pair::generate_with_pkcs8();
|
||||
let key_file = EncryptedKey::encrypt(&pkcs_bytes, password, KEY_ITERATIONS as u32);
|
||||
let key_file = EncryptedKey::encrypt(
|
||||
&pkcs_bytes,
|
||||
password,
|
||||
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
|
||||
);
|
||||
|
||||
let mut file = File::create(self.key_file_path(&pair.public()))?;
|
||||
::serde_json::to_writer(&file, &key_file)?;
|
||||
@@ -225,7 +230,7 @@ mod tests {
|
||||
#[test]
|
||||
fn encrypt_and_decrypt() {
|
||||
let plain = [1; PKCS_LEN];
|
||||
let encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", KEY_ITERATIONS as u32);
|
||||
let encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED"));
|
||||
|
||||
let decrypted_key = encrypted_key.decrypt("thepassword").unwrap();
|
||||
|
||||
@@ -235,7 +240,11 @@ mod tests {
|
||||
#[test]
|
||||
fn decrypt_wrong_password_fails() {
|
||||
let plain = [1; PKCS_LEN];
|
||||
let encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", KEY_ITERATIONS as u32);
|
||||
let encrypted_key = EncryptedKey::encrypt(
|
||||
&plain,
|
||||
"thepassword",
|
||||
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
|
||||
);
|
||||
|
||||
assert!(encrypted_key.decrypt("thepassword2").is_err());
|
||||
}
|
||||
@@ -243,9 +252,13 @@ mod tests {
|
||||
#[test]
|
||||
fn decrypt_wrong_iterations_fails() {
|
||||
let plain = [1; PKCS_LEN];
|
||||
let mut encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", KEY_ITERATIONS as u32);
|
||||
let mut encrypted_key = EncryptedKey::encrypt(
|
||||
&plain,
|
||||
"thepassword",
|
||||
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
|
||||
);
|
||||
|
||||
encrypted_key.iterations -= 64;
|
||||
encrypted_key.iterations = NonZeroU32::new(encrypted_key.iterations.get() - 64).unwrap();
|
||||
|
||||
assert!(encrypted_key.decrypt("thepassword").is_err());
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ bytes = "0.4"
|
||||
error-chain = { version = "0.12", default-features = false }
|
||||
fnv = "1.0"
|
||||
futures = "0.1"
|
||||
libp2p = { version = "0.2", default-features = false, features = ["secio-rsa", "secio-secp256k1", "libp2p-websocket"] }
|
||||
libp2p = { version = "0.3.1", default-features = false, features = ["secio-secp256k1", "libp2p-websocket"] }
|
||||
parking_lot = "0.7.1"
|
||||
lazy_static = "1.2"
|
||||
log = "0.4"
|
||||
|
||||
@@ -19,11 +19,11 @@ use crate::{NetworkConfiguration, ProtocolId};
|
||||
use bytes::Bytes;
|
||||
use futures::prelude::*;
|
||||
use libp2p::NetworkBehaviour;
|
||||
use libp2p::core::{PeerId, ProtocolsHandler};
|
||||
use libp2p::core::{Multiaddr, PeerId, ProtocolsHandler, PublicKey};
|
||||
use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction};
|
||||
use libp2p::core::swarm::{NetworkBehaviourEventProcess, PollParameters};
|
||||
use libp2p::identify::{Identify, IdentifyEvent, protocol::IdentifyInfo};
|
||||
use libp2p::kad::{Kademlia, KademliaOut, KademliaTopology};
|
||||
use libp2p::kad::{Kademlia, KademliaOut, KadConnectionType};
|
||||
use libp2p::ping::{Ping, PingEvent};
|
||||
use log::{debug, trace, warn};
|
||||
use std::{cmp, io, time::Duration, time::Instant};
|
||||
@@ -51,17 +51,20 @@ pub struct Behaviour<TSubstream> {
|
||||
|
||||
impl<TSubstream> Behaviour<TSubstream> {
|
||||
/// Builds a new `Behaviour`.
|
||||
// TODO: redundancy between config and local_peer_id (https://github.com/libp2p/rust-libp2p/issues/745)
|
||||
pub fn new(config: &NetworkConfiguration, local_peer_id: PeerId, protocols: RegisteredProtocols) -> Self {
|
||||
// TODO: redundancy between config and local_public_key (https://github.com/libp2p/rust-libp2p/issues/745)
|
||||
pub fn new(config: &NetworkConfiguration, local_public_key: PublicKey, protocols: RegisteredProtocols) -> Self {
|
||||
let identify = {
|
||||
let proto_version = "/substrate/1.0".to_string();
|
||||
let user_agent = format!("{} ({})", config.client_version, config.node_name);
|
||||
Identify::new(proto_version, user_agent)
|
||||
Identify::new(proto_version, user_agent, local_public_key.clone())
|
||||
};
|
||||
|
||||
let local_peer_id = local_public_key.into_peer_id();
|
||||
let custom_protocols = CustomProtos::new(config, &local_peer_id, protocols);
|
||||
|
||||
Behaviour {
|
||||
ping: Ping::new(),
|
||||
custom_protocols: CustomProtos::new(config, protocols),
|
||||
custom_protocols,
|
||||
discovery: DiscoveryBehaviour::new(local_peer_id),
|
||||
identify,
|
||||
events: Vec::new(),
|
||||
@@ -79,9 +82,26 @@ impl<TSubstream> Behaviour<TSubstream> {
|
||||
self.custom_protocols.send_packet(target, protocol_id, data)
|
||||
}
|
||||
|
||||
/// Returns the number of peers in the topology.
|
||||
pub fn num_topology_peers(&self) -> usize {
|
||||
self.custom_protocols.num_topology_peers()
|
||||
}
|
||||
|
||||
/// Flushes the topology to the disk.
|
||||
pub fn flush_topology(&mut self) -> Result<(), io::Error> {
|
||||
self.custom_protocols.flush_topology()
|
||||
}
|
||||
|
||||
/// Perform a cleanup pass, removing all obsolete addresses and peers.
|
||||
///
|
||||
/// This should be done from time to time.
|
||||
pub fn cleanup(&mut self) {
|
||||
self.custom_protocols.cleanup();
|
||||
}
|
||||
|
||||
/// Try to add a reserved peer.
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId) {
|
||||
self.custom_protocols.add_reserved_peer(peer_id)
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
self.custom_protocols.add_reserved_peer(peer_id, addr)
|
||||
}
|
||||
|
||||
/// Try to remove a reserved peer.
|
||||
@@ -218,6 +238,20 @@ impl<TSubstream> NetworkBehaviourEventProcess<IdentifyEvent> for Behaviour<TSubs
|
||||
// TODO: ideally we would delay the first identification to when we open the custom
|
||||
// protocol, so that we only report id info to the service about the nodes we
|
||||
// care about (https://github.com/libp2p/rust-libp2p/issues/876)
|
||||
if !info.protocol_version.contains("substrate") {
|
||||
warn!(target: "sub-libp2p", "Connected to a non-Substrate node: {:?}", info);
|
||||
}
|
||||
if info.listen_addrs.is_empty() {
|
||||
warn!(target: "sub-libp2p", "Received identify response with empty list of \
|
||||
addresses");
|
||||
}
|
||||
for addr in &info.listen_addrs {
|
||||
self.discovery.kademlia.add_address(&peer_id, addr.clone());
|
||||
}
|
||||
self.custom_protocols.add_discovered_addrs(
|
||||
&peer_id,
|
||||
info.listen_addrs.iter().map(|addr| (addr.clone(), true))
|
||||
);
|
||||
self.events.push(BehaviourOut::Identified { peer_id, info });
|
||||
}
|
||||
IdentifyEvent::Error { .. } => {}
|
||||
@@ -227,10 +261,13 @@ impl<TSubstream> NetworkBehaviourEventProcess<IdentifyEvent> for Behaviour<TSubs
|
||||
|
||||
impl<TSubstream> NetworkBehaviourEventProcess<KademliaOut> for Behaviour<TSubstream> {
|
||||
fn inject_event(&mut self, out: KademliaOut) {
|
||||
// We only ever use Kademlia for discovering nodes, and nodes discovered by Kademlia are
|
||||
// automatically added to the topology. Therefore we don't need to perform any further
|
||||
// action.
|
||||
match out {
|
||||
KademliaOut::Discovered { peer_id, addresses, ty } => {
|
||||
self.custom_protocols.add_discovered_addrs(
|
||||
&peer_id,
|
||||
addresses.into_iter().map(|addr| (addr, ty == KadConnectionType::Connected))
|
||||
);
|
||||
}
|
||||
KademliaOut::FindNodeResult { key, closer_peers } => {
|
||||
trace!(target: "sub-libp2p", "Kademlia query for {:?} yielded {:?} results",
|
||||
key, closer_peers.len());
|
||||
@@ -284,24 +321,31 @@ impl<TSubstream> DiscoveryBehaviour<TSubstream> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSubstream, TTopology> NetworkBehaviour<TTopology> for DiscoveryBehaviour<TSubstream>
|
||||
impl<TSubstream> NetworkBehaviour for DiscoveryBehaviour<TSubstream>
|
||||
where
|
||||
TSubstream: AsyncRead + AsyncWrite,
|
||||
TTopology: KademliaTopology,
|
||||
{
|
||||
type ProtocolsHandler = <Kademlia<TSubstream> as NetworkBehaviour<TTopology>>::ProtocolsHandler;
|
||||
type OutEvent = <Kademlia<TSubstream> as NetworkBehaviour<TTopology>>::OutEvent;
|
||||
type ProtocolsHandler = <Kademlia<TSubstream> as NetworkBehaviour>::ProtocolsHandler;
|
||||
type OutEvent = <Kademlia<TSubstream> as NetworkBehaviour>::OutEvent;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
NetworkBehaviour::<TTopology>::new_handler(&mut self.kademlia)
|
||||
NetworkBehaviour::new_handler(&mut self.kademlia)
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
self.kademlia.addresses_of_peer(peer_id)
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) {
|
||||
NetworkBehaviour::<TTopology>::inject_connected(&mut self.kademlia, peer_id, endpoint)
|
||||
NetworkBehaviour::inject_connected(&mut self.kademlia, peer_id, endpoint)
|
||||
}
|
||||
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) {
|
||||
NetworkBehaviour::<TTopology>::inject_disconnected(&mut self.kademlia, peer_id, endpoint)
|
||||
NetworkBehaviour::inject_disconnected(&mut self.kademlia, peer_id, endpoint)
|
||||
}
|
||||
|
||||
fn inject_replaced(&mut self, peer_id: PeerId, closed: ConnectedPoint, opened: ConnectedPoint) {
|
||||
NetworkBehaviour::inject_replaced(&mut self.kademlia, peer_id, closed, opened)
|
||||
}
|
||||
|
||||
fn inject_node_event(
|
||||
@@ -309,12 +353,12 @@ where
|
||||
peer_id: PeerId,
|
||||
event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
|
||||
) {
|
||||
NetworkBehaviour::<TTopology>::inject_node_event(&mut self.kademlia, peer_id, event)
|
||||
NetworkBehaviour::inject_node_event(&mut self.kademlia, peer_id, event)
|
||||
}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
params: &mut PollParameters<TTopology>,
|
||||
params: &mut PollParameters,
|
||||
) -> Async<
|
||||
NetworkBehaviourAction<
|
||||
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
|
||||
|
||||
@@ -15,19 +15,23 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::custom_proto::handler::{CustomProtosHandler, CustomProtosHandlerOut, CustomProtosHandlerIn};
|
||||
use crate::custom_proto::topology::NetTopology;
|
||||
use crate::custom_proto::upgrade::RegisteredProtocols;
|
||||
use crate::{NetworkConfiguration, NonReservedPeerMode, ProtocolId, topology::NetTopology};
|
||||
use crate::{NetworkConfiguration, NonReservedPeerMode, ProtocolId};
|
||||
use crate::parse_str_addr;
|
||||
use bytes::Bytes;
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use futures::prelude::*;
|
||||
use libp2p::core::swarm::{ConnectedPoint, NetworkBehaviour, NetworkBehaviourAction, PollParameters};
|
||||
use libp2p::core::{protocols_handler::ProtocolsHandler, PeerId};
|
||||
use libp2p::core::{protocols_handler::ProtocolsHandler, Multiaddr, PeerId};
|
||||
use log::{debug, trace, warn};
|
||||
use smallvec::SmallVec;
|
||||
use std::{io, marker::PhantomData, time::Duration, time::Instant};
|
||||
use std::{cmp, error, io, marker::PhantomData, path::Path, time::Duration, time::Instant};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_timer::Delay;
|
||||
|
||||
// File where the network topology is stored.
|
||||
const NODES_FILE: &str = "nodes.json";
|
||||
// Duration during which a peer is disabled.
|
||||
const PEER_DISABLE_DURATION: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
@@ -36,6 +40,9 @@ pub struct CustomProtos<TSubstream> {
|
||||
/// List of protocols to open with peers. Never modified.
|
||||
registered_protocols: RegisteredProtocols,
|
||||
|
||||
/// Topology of the network.
|
||||
topology: NetTopology,
|
||||
|
||||
/// List of custom protocols that we have open with remotes.
|
||||
open_protocols: Vec<(PeerId, ProtocolId)>,
|
||||
|
||||
@@ -56,6 +63,9 @@ pub struct CustomProtos<TSubstream> {
|
||||
/// If true, only reserved peers can connect.
|
||||
reserved_only: bool,
|
||||
|
||||
/// List of the IDs of the peers we are connected to.
|
||||
connected_peers: FnvHashSet<PeerId>,
|
||||
|
||||
/// List of the IDs of the reserved peers. We always try to maintain a connection these peers.
|
||||
reserved_peers: FnvHashSet<PeerId>,
|
||||
|
||||
@@ -122,7 +132,24 @@ pub enum CustomProtosOut {
|
||||
|
||||
impl<TSubstream> CustomProtos<TSubstream> {
|
||||
/// Creates a `CustomProtos`.
|
||||
pub fn new(config: &NetworkConfiguration, registered_protocols: RegisteredProtocols) -> Self {
|
||||
pub fn new(config: &NetworkConfiguration, local_peer_id: &PeerId, registered_protocols: RegisteredProtocols) -> Self {
|
||||
// Initialize the topology of the network.
|
||||
let mut topology = if let Some(ref path) = config.net_config_path {
|
||||
let path = Path::new(path).join(NODES_FILE);
|
||||
debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path);
|
||||
NetTopology::from_file(local_peer_id.clone(), path)
|
||||
} else {
|
||||
debug!(target: "sub-libp2p", "No peers file configured ; peers won't be saved");
|
||||
NetTopology::memory(local_peer_id.clone())
|
||||
};
|
||||
|
||||
// Add the bootstrap nodes to the topology.
|
||||
for bootnode in config.boot_nodes.iter() {
|
||||
if let Ok((peer_id, addr)) = parse_str_addr(bootnode) {
|
||||
topology.add_bootstrap_addr(&peer_id, addr.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let max_incoming_connections = config.in_peers as usize;
|
||||
let max_outgoing_connections = config.out_peers as usize;
|
||||
|
||||
@@ -136,9 +163,11 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
|
||||
CustomProtos {
|
||||
registered_protocols,
|
||||
topology,
|
||||
max_incoming_connections,
|
||||
max_outgoing_connections,
|
||||
reserved_only: config.non_reserved_mode == NonReservedPeerMode::Deny,
|
||||
connected_peers: Default::default(),
|
||||
reserved_peers: Default::default(),
|
||||
banned_peers: Vec::new(),
|
||||
open_protocols: Vec::with_capacity(open_protos_cap),
|
||||
@@ -150,7 +179,8 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
}
|
||||
|
||||
/// Adds a reserved peer.
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId) {
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
self.topology.add_bootstrap_addr(&peer_id, addr);
|
||||
self.reserved_peers.insert(peer_id);
|
||||
|
||||
// Trigger a `connect_to_nodes` round.
|
||||
@@ -240,11 +270,40 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Indicates to the topology that we have discovered new addresses for a given node.
|
||||
pub fn add_discovered_addrs<I>(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
addrs: I,
|
||||
) where I: Iterator<Item = (Multiaddr, bool)> {
|
||||
if self.topology.add_discovered_addrs(peer_id, addrs) {
|
||||
// Trigger a `connect_to_nodes` round.
|
||||
self.next_connect_to_nodes = Delay::new(Instant::now());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of peers in the topology.
|
||||
pub fn num_topology_peers(&self) -> usize {
|
||||
self.topology.num_peers()
|
||||
}
|
||||
|
||||
/// Flushes the topology to the disk.
|
||||
pub fn flush_topology(&mut self) -> Result<(), io::Error> {
|
||||
self.topology.flush_to_disk()
|
||||
}
|
||||
|
||||
/// Perform a cleanup pass, removing all obsolete addresses and peers.
|
||||
///
|
||||
/// This should be done from time to time.
|
||||
pub fn cleanup(&mut self) {
|
||||
self.topology.cleanup();
|
||||
}
|
||||
|
||||
/// Updates the attempted connections to nodes.
|
||||
///
|
||||
/// Also updates `next_connect_to_nodes` with the earliest known moment when we need to
|
||||
/// update connections again.
|
||||
fn connect_to_nodes(&mut self, params: &mut PollParameters<NetTopology>) {
|
||||
fn connect_to_nodes(&mut self, params: &mut PollParameters) {
|
||||
// Make sure we are connected or connecting to all the reserved nodes.
|
||||
for reserved in self.reserved_peers.iter() {
|
||||
// TODO: don't generate an event if we're already in a pending connection (https://github.com/libp2p/rust-libp2p/issues/697)
|
||||
@@ -272,7 +331,7 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
num_to_open);
|
||||
|
||||
let local_peer_id = params.local_peer_id().clone();
|
||||
let (to_try, will_change) = params.topology().addrs_to_attempt();
|
||||
let (to_try, will_change) = self.topology.addrs_to_attempt();
|
||||
for (peer_id, _) in to_try {
|
||||
if num_to_open == 0 {
|
||||
break
|
||||
@@ -282,6 +341,10 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
continue
|
||||
}
|
||||
|
||||
if self.connected_peers.contains(&peer_id) {
|
||||
continue
|
||||
}
|
||||
|
||||
if let Some((_, ban_end)) = self.banned_peers.iter().find(|(p, _)| p == peer_id) {
|
||||
if *ban_end > Instant::now() {
|
||||
continue
|
||||
@@ -293,11 +356,11 @@ impl<TSubstream> CustomProtos<TSubstream> {
|
||||
}
|
||||
|
||||
// Next round is when we expect the topology will change.
|
||||
self.next_connect_to_nodes.reset(will_change);
|
||||
self.next_connect_to_nodes.reset(cmp::min(will_change, Instant::now() + Duration::from_secs(60)));
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSubstream> NetworkBehaviour<NetTopology> for CustomProtos<TSubstream>
|
||||
impl<TSubstream> NetworkBehaviour for CustomProtos<TSubstream>
|
||||
where
|
||||
TSubstream: AsyncRead + AsyncWrite,
|
||||
{
|
||||
@@ -308,13 +371,23 @@ where
|
||||
CustomProtosHandler::new(self.registered_protocols.clone())
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr> {
|
||||
self.topology.addresses_of_peer(peer_id)
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) {
|
||||
// When a peer connects, its handler is initially in the disabled state. We make sure that
|
||||
// the peer is allowed, and if so we put it in the enabled state.
|
||||
|
||||
self.connected_peers.insert(peer_id.clone());
|
||||
|
||||
let is_reserved = self.reserved_peers.contains(&peer_id);
|
||||
if self.reserved_only && !is_reserved {
|
||||
debug!(target: "sub-libp2p", "Ignoring {:?} because we're in reserved mode", peer_id);
|
||||
self.events.push(NetworkBehaviourAction::SendEvent {
|
||||
peer_id: peer_id.clone(),
|
||||
event: CustomProtosHandlerIn::Disable,
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
@@ -323,6 +396,10 @@ where
|
||||
if let Some((_, expire)) = self.banned_peers.iter().find(|(p, _)| p == &peer_id) {
|
||||
if *expire >= Instant::now() {
|
||||
debug!(target: "sub-libp2p", "Ignoring banned peer {:?}", peer_id);
|
||||
self.events.push(NetworkBehaviourAction::SendEvent {
|
||||
peer_id: peer_id.clone(),
|
||||
event: CustomProtosHandlerIn::Disable,
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -338,6 +415,10 @@ where
|
||||
|
||||
debug_assert!(num_outgoing <= self.max_outgoing_connections);
|
||||
if num_outgoing == self.max_outgoing_connections {
|
||||
self.events.push(NetworkBehaviourAction::SendEvent {
|
||||
peer_id: peer_id.clone(),
|
||||
event: CustomProtosHandlerIn::Disable,
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -351,6 +432,10 @@ where
|
||||
if num_ingoing == self.max_incoming_connections {
|
||||
debug!(target: "sub-libp2p", "Ignoring incoming connection from {:?} because \
|
||||
we're full", peer_id);
|
||||
self.events.push(NetworkBehaviourAction::SendEvent {
|
||||
peer_id: peer_id.clone(),
|
||||
event: CustomProtosHandlerIn::Disable,
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -374,10 +459,16 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
self.topology.set_connected(&peer_id, &endpoint);
|
||||
self.enabled_peers.insert(peer_id, endpoint);
|
||||
}
|
||||
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId, _: ConnectedPoint) {
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) {
|
||||
let was_connected = self.connected_peers.remove(&peer_id);
|
||||
debug_assert!(was_connected);
|
||||
|
||||
self.topology.set_disconnected(peer_id, &endpoint);
|
||||
|
||||
while let Some(pos) = self.open_protocols.iter().position(|(p, _)| p == peer_id) {
|
||||
let (_, protocol_id) = self.open_protocols.remove(pos);
|
||||
|
||||
@@ -388,12 +479,24 @@ where
|
||||
};
|
||||
|
||||
self.events.push(NetworkBehaviourAction::GenerateEvent(event));
|
||||
}
|
||||
|
||||
// Trigger a `connect_to_nodes` round.
|
||||
self.next_connect_to_nodes = Delay::new(Instant::now());
|
||||
|
||||
self.enabled_peers.remove(peer_id);
|
||||
}
|
||||
|
||||
fn inject_dial_failure(&mut self, peer_id: Option<&PeerId>, addr: &Multiaddr, error: &dyn error::Error) {
|
||||
if let Some(peer_id) = peer_id.as_ref() {
|
||||
debug!(target: "sub-libp2p", "Failed to reach peer {:?} through {} => {:?}", peer_id, addr, error);
|
||||
if self.connected_peers.contains(peer_id) {
|
||||
self.topology.set_unreachable(addr);
|
||||
}
|
||||
|
||||
// Trigger a `connect_to_nodes` round.
|
||||
self.next_connect_to_nodes = Delay::new(Instant::now());
|
||||
}
|
||||
|
||||
self.enabled_peers.remove(peer_id);
|
||||
}
|
||||
|
||||
fn inject_node_event(
|
||||
@@ -461,7 +564,7 @@ where
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
params: &mut PollParameters<NetTopology>,
|
||||
params: &mut PollParameters,
|
||||
) -> Async<
|
||||
NetworkBehaviourAction<
|
||||
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
|
||||
|
||||
@@ -19,13 +19,14 @@ use crate::custom_proto::upgrade::{RegisteredProtocol, RegisteredProtocols, Regi
|
||||
use bytes::Bytes;
|
||||
use futures::prelude::*;
|
||||
use libp2p::core::{
|
||||
Endpoint, ProtocolsHandler, ProtocolsHandlerEvent,
|
||||
ProtocolsHandler, ProtocolsHandlerEvent,
|
||||
protocols_handler::KeepAlive,
|
||||
protocols_handler::ProtocolsHandlerUpgrErr,
|
||||
upgrade::{InboundUpgrade, OutboundUpgrade}
|
||||
};
|
||||
use log::{trace, warn};
|
||||
use smallvec::SmallVec;
|
||||
use std::{fmt, io};
|
||||
use std::{fmt, io, time::Duration, time::Instant};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use void::Void;
|
||||
|
||||
@@ -42,6 +43,9 @@ pub struct CustomProtosHandler<TSubstream> {
|
||||
/// See the documentation of `State`.
|
||||
state: State,
|
||||
|
||||
/// Value to be returned by `connection_keep_alive()`.
|
||||
keep_alive: KeepAlive,
|
||||
|
||||
/// The active substreams. There should always ever be only one substream per protocol.
|
||||
substreams: SmallVec<[RegisteredProtocolSubstream<TSubstream>; 6]>,
|
||||
|
||||
@@ -130,7 +134,9 @@ where
|
||||
pub fn new(protocols: RegisteredProtocols) -> Self {
|
||||
CustomProtosHandler {
|
||||
protocols,
|
||||
state: State::Disabled,
|
||||
// We keep the connection alive for at least 5 seconds, waiting for what happens.
|
||||
keep_alive: KeepAlive::Until(Instant::now() + Duration::from_secs(5)),
|
||||
state: State::Normal,
|
||||
substreams: SmallVec::new(),
|
||||
events_queue: SmallVec::new(),
|
||||
}
|
||||
@@ -140,9 +146,10 @@ where
|
||||
fn inject_fully_negotiated(
|
||||
&mut self,
|
||||
proto: RegisteredProtocolSubstream<TSubstream>,
|
||||
_: Endpoint,
|
||||
) {
|
||||
match self.state {
|
||||
// TODO: we should shut down refused substreams gracefully; this should be fixed
|
||||
// at the same time as https://github.com/paritytech/substrate/issues/1517
|
||||
State::Disabled | State::ShuttingDown => return,
|
||||
State::Normal => ()
|
||||
}
|
||||
@@ -183,7 +190,7 @@ where
|
||||
&mut self,
|
||||
proto: <Self::InboundProtocol as InboundUpgrade<TSubstream>>::Output
|
||||
) {
|
||||
self.inject_fully_negotiated(proto, Endpoint::Listener);
|
||||
self.inject_fully_negotiated(proto);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -192,7 +199,7 @@ where
|
||||
proto: <Self::OutboundProtocol as OutboundUpgrade<TSubstream>>::Output,
|
||||
_: Self::OutboundOpenInfo
|
||||
) {
|
||||
self.inject_fully_negotiated(proto, Endpoint::Dialer);
|
||||
self.inject_fully_negotiated(proto);
|
||||
}
|
||||
|
||||
fn inject_event(&mut self, message: CustomProtosHandlerIn) {
|
||||
@@ -203,6 +210,7 @@ where
|
||||
State::Disabled | State::ShuttingDown => (),
|
||||
}
|
||||
|
||||
self.keep_alive = KeepAlive::Now;
|
||||
for substream in self.substreams.iter_mut() {
|
||||
substream.shutdown();
|
||||
}
|
||||
@@ -213,6 +221,8 @@ where
|
||||
State::Normal | State::ShuttingDown => (),
|
||||
}
|
||||
|
||||
self.keep_alive = KeepAlive::Forever;
|
||||
|
||||
// Try open one substream for each registered protocol.
|
||||
if let CustomProtosHandlerIn::EnableActive = message {
|
||||
for protocol in self.protocols.0.iter() {
|
||||
@@ -253,14 +263,16 @@ where
|
||||
#[inline]
|
||||
fn inject_dial_upgrade_error(&mut self, _: Self::OutboundOpenInfo, err: ProtocolsHandlerUpgrErr<io::Error>) {
|
||||
warn!(target: "sub-libp2p", "Error while opening custom protocol: {:?}", err);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn connection_keep_alive(&self) -> bool {
|
||||
// Right now if the remote doesn't support one of the custom protocols, we shut down the
|
||||
// entire connection. This is a hack-ish solution to the problem where we connect to nodes
|
||||
// that support libp2p but not the testnet that we want.
|
||||
self.substreams.len() == self.protocols.len()
|
||||
self.shutdown();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn connection_keep_alive(&self) -> KeepAlive {
|
||||
self.keep_alive
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) {
|
||||
|
||||
@@ -19,4 +19,5 @@ pub use self::upgrade::{RegisteredProtocol, RegisteredProtocols};
|
||||
|
||||
mod behaviour;
|
||||
mod handler;
|
||||
mod topology;
|
||||
mod upgrade;
|
||||
|
||||
+42
-102
@@ -15,12 +15,10 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.?
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use libp2p::{Multiaddr, PeerId, identify::IdentifyTopology, multihash::Multihash};
|
||||
use libp2p::core::{PublicKey, swarm::ConnectedPoint, topology::DisconnectReason, topology::Topology};
|
||||
use libp2p::kad::{KBucketsPeerId, KadConnectionType, KademliaTopology};
|
||||
use libp2p::{core::swarm::ConnectedPoint, Multiaddr, PeerId};
|
||||
use log::{debug, info, trace, warn};
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use std::{cmp, fs, iter, vec};
|
||||
use std::{cmp, fs};
|
||||
use std::io::{Read, Cursor, Error as IoError, ErrorKind as IoErrorKind, Write, BufReader, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
@@ -58,8 +56,6 @@ const FAIL_BACKOFF_MULTIPLIER: u32 = 2;
|
||||
/// We need a maximum value for the backoff, overwise we risk an overflow.
|
||||
const MAX_BACKOFF: Duration = Duration::from_secs(30 * 60);
|
||||
|
||||
// TODO: should be merged with the Kademlia k-buckets
|
||||
|
||||
/// Stores information about the topology of the network.
|
||||
#[derive(Debug)]
|
||||
pub struct NetTopology {
|
||||
@@ -67,12 +63,8 @@ pub struct NetTopology {
|
||||
store: FnvHashMap<PeerId, PeerInfo>,
|
||||
/// Optional path to the file that caches the serialized version of `store`.
|
||||
cache_path: Option<PathBuf>,
|
||||
/// Public key of the local node.
|
||||
local_public_key: PublicKey,
|
||||
/// PeerId of the local node. Derived from `local_public_key`.
|
||||
/// PeerId of the local node.
|
||||
local_peer_id: PeerId,
|
||||
/// Known addresses for the local node to report to the network.
|
||||
external_addresses: Vec<Multiaddr>,
|
||||
}
|
||||
|
||||
impl NetTopology {
|
||||
@@ -80,14 +72,11 @@ impl NetTopology {
|
||||
///
|
||||
/// `flush_to_disk()` will be a no-op.
|
||||
#[inline]
|
||||
pub fn memory(local_public_key: PublicKey) -> NetTopology {
|
||||
let local_peer_id = local_public_key.clone().into_peer_id();
|
||||
pub fn memory(local_peer_id: PeerId) -> NetTopology {
|
||||
NetTopology {
|
||||
store: Default::default(),
|
||||
cache_path: None,
|
||||
local_peer_id,
|
||||
local_public_key,
|
||||
external_addresses: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,17 +86,14 @@ impl NetTopology {
|
||||
/// or contains garbage data, the execution still continues.
|
||||
///
|
||||
/// Calling `flush_to_disk()` in the future writes to the given path.
|
||||
pub fn from_file<P: AsRef<Path>>(local_public_key: PublicKey, path: P) -> NetTopology {
|
||||
pub fn from_file<P: AsRef<Path>>(local_peer_id: PeerId, path: P) -> NetTopology {
|
||||
let path = path.as_ref();
|
||||
let local_peer_id = local_public_key.clone().into_peer_id();
|
||||
debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path);
|
||||
let store = try_load(path, &local_peer_id);
|
||||
NetTopology {
|
||||
store,
|
||||
cache_path: Some(path.to_owned()),
|
||||
local_peer_id,
|
||||
local_public_key,
|
||||
external_addresses: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,12 +132,6 @@ impl NetTopology {
|
||||
});
|
||||
}
|
||||
|
||||
/// Add the external addresses that are known for the local node.
|
||||
pub fn add_external_addrs<TIter>(&mut self, addrs: TIter)
|
||||
where TIter: Iterator<Item = Multiaddr> {
|
||||
self.external_addresses.extend(addrs);
|
||||
}
|
||||
|
||||
/// Returns a list of all the known addresses of peers, ordered by the
|
||||
/// order in which we should attempt to connect to them.
|
||||
///
|
||||
@@ -200,6 +180,10 @@ impl NetTopology {
|
||||
///
|
||||
/// We assume that the address is valid, so its score starts very high.
|
||||
pub fn add_bootstrap_addr(&mut self, peer: &PeerId, addr: Multiaddr) {
|
||||
if *peer == self.local_peer_id {
|
||||
return
|
||||
}
|
||||
|
||||
let now_systime = SystemTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
@@ -235,16 +219,22 @@ impl NetTopology {
|
||||
}
|
||||
}
|
||||
|
||||
/// Inner implementaiton of the `add_*_discovered_addrs` methods.
|
||||
/// Indicates the topology that we have discovered new addresses for a given node.
|
||||
///
|
||||
/// Returns `true` if the topology has changed in some way. Returns `false` if calling this
|
||||
/// method was a no-op.
|
||||
fn add_discovered_addrs<I>(
|
||||
pub fn add_discovered_addrs<I>(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
addrs: I,
|
||||
) -> bool
|
||||
where I: Iterator<Item = (Multiaddr, bool)> {
|
||||
if *peer_id == self.local_peer_id {
|
||||
return false
|
||||
}
|
||||
|
||||
let mut addrs: Vec<_> = addrs.collect();
|
||||
|
||||
let now_systime = SystemTime::now();
|
||||
let now = Instant::now();
|
||||
|
||||
@@ -252,14 +242,14 @@ impl NetTopology {
|
||||
|
||||
let new_addrs = peer.addrs
|
||||
.drain(..)
|
||||
.filter_map(|a| {
|
||||
.filter(|a| {
|
||||
if a.expires < now_systime && !a.is_connected() {
|
||||
return None
|
||||
return false
|
||||
}
|
||||
if let Some(pos) = addrs.iter().position(|&(ref addr, _)| addr == &a.addr) {
|
||||
while let Some(pos) = addrs.iter().position(|&(ref addr, _)| addr == &a.addr) {
|
||||
addrs.remove(pos);
|
||||
}
|
||||
Some(a)
|
||||
true
|
||||
})
|
||||
.collect();
|
||||
peer.addrs = new_addrs;
|
||||
@@ -267,6 +257,7 @@ impl NetTopology {
|
||||
let mut anything_changed = false;
|
||||
|
||||
if !addrs.is_empty() {
|
||||
anything_changed = true;
|
||||
trace!(
|
||||
target: "sub-libp2p",
|
||||
"Peer store: adding addresses {:?} for {:?}",
|
||||
@@ -292,7 +283,11 @@ impl NetTopology {
|
||||
}
|
||||
}
|
||||
|
||||
anything_changed = true;
|
||||
// `addrs` can contain duplicates, therefore we would insert the same address twice.
|
||||
if peer.addrs.iter().any(|a| a.addr == addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
peer.addrs.push(Addr {
|
||||
addr,
|
||||
expires: now_systime + KADEMLIA_DISCOVERY_EXPIRATION,
|
||||
@@ -308,58 +303,10 @@ impl NetTopology {
|
||||
|
||||
anything_changed
|
||||
}
|
||||
}
|
||||
|
||||
impl KademliaTopology for NetTopology {
|
||||
type ClosestPeersIter = vec::IntoIter<PeerId>;
|
||||
type GetProvidersIter = iter::Empty<PeerId>;
|
||||
|
||||
fn add_kad_discovered_address(&mut self, peer: PeerId, addr: Multiaddr, ty: KadConnectionType) {
|
||||
self.add_discovered_addrs(&peer, iter::once((addr, ty == KadConnectionType::Connected)));
|
||||
}
|
||||
|
||||
fn closest_peers(&mut self, target: &Multihash, _max: usize) -> Self::ClosestPeersIter {
|
||||
// TODO: very inefficient
|
||||
let mut peers = self.store.keys().cloned().collect::<Vec<_>>();
|
||||
peers.push(self.local_peer_id.clone());
|
||||
peers.sort_by(|a, b| {
|
||||
b.as_ref().distance_with(target).cmp(&a.as_ref().distance_with(target))
|
||||
});
|
||||
peers.into_iter()
|
||||
}
|
||||
|
||||
fn add_provider(&mut self, _: Multihash, _: PeerId) {
|
||||
// We don't implement ADD_PROVIDER/GET_PROVIDERS
|
||||
}
|
||||
|
||||
fn get_providers(&mut self, _: &Multihash) -> Self::GetProvidersIter {
|
||||
// We don't implement ADD_PROVIDER/GET_PROVIDERS
|
||||
iter::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl IdentifyTopology for NetTopology {
|
||||
/// Returns the addresses stored for a specific peer.
|
||||
#[inline]
|
||||
fn add_identify_discovered_addrs<TIter>(&mut self, peer: &PeerId, addrs: TIter)
|
||||
where
|
||||
TIter: Iterator<Item = Multiaddr>
|
||||
{
|
||||
// These are addresses that peers indicate for themselves.
|
||||
// The typical use case is:
|
||||
// - A peer connects to one of our listening points.
|
||||
// - We send an identify request to it, and it answers with a list of addresses.
|
||||
// - If later it disconnects, we can try to dial it back through one of these addresses.
|
||||
self.add_discovered_addrs(peer, addrs.map(move |a| (a, true)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Topology for NetTopology {
|
||||
#[inline]
|
||||
fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec<Multiaddr> {
|
||||
if peer == &self.local_peer_id {
|
||||
return self.external_addresses.clone()
|
||||
}
|
||||
|
||||
pub fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec<Multiaddr> {
|
||||
let peer = if let Some(peer) = self.store.get_mut(peer) {
|
||||
peer
|
||||
} else {
|
||||
@@ -382,20 +329,12 @@ impl Topology for NetTopology {
|
||||
list.into_iter().map(|(_, addr)| addr.clone()).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn add_local_external_addrs<TIter>(&mut self, addrs: TIter)
|
||||
where TIter: Iterator<Item = Multiaddr> {
|
||||
self.add_external_addrs(addrs)
|
||||
}
|
||||
/// Marks the given peer as connected through the given endpoint.
|
||||
pub fn set_connected(&mut self, peer: &PeerId, endpoint: &ConnectedPoint) {
|
||||
if *peer == self.local_peer_id {
|
||||
return
|
||||
}
|
||||
|
||||
fn local_peer_id(&self) -> &PeerId {
|
||||
&self.local_peer_id
|
||||
}
|
||||
|
||||
fn local_public_key(&self) -> &PublicKey {
|
||||
&self.local_public_key
|
||||
}
|
||||
|
||||
fn set_connected(&mut self, peer: &PeerId, endpoint: &ConnectedPoint) {
|
||||
let addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address } => address,
|
||||
ConnectedPoint::Listener { .. } => return
|
||||
@@ -438,17 +377,16 @@ impl Topology for NetTopology {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_disconnected(&mut self, _: &PeerId, endpoint: &ConnectedPoint, reason: DisconnectReason) {
|
||||
/// Marks the given peer as disconnected. The endpoint is the one we were connected to.
|
||||
pub fn set_disconnected(&mut self, _: &PeerId, endpoint: &ConnectedPoint) {
|
||||
let addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address } => address,
|
||||
ConnectedPoint::Listener { .. } => return
|
||||
};
|
||||
|
||||
let score_diff = match reason {
|
||||
DisconnectReason::Replaced => -3,
|
||||
DisconnectReason::Graceful => -1,
|
||||
DisconnectReason::Error => -5,
|
||||
};
|
||||
// Note that we used to have different score values here in the past, but there really
|
||||
// isn't much point in doing so in practice.
|
||||
let score_diff = -3;
|
||||
|
||||
for info in self.store.values_mut() {
|
||||
for a in info.addrs.iter_mut() {
|
||||
@@ -466,13 +404,15 @@ impl Topology for NetTopology {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_unreachable(&mut self, addr: &Multiaddr) {
|
||||
/// Indicates to the topology that we failed to reach a node when dialing the given address.
|
||||
pub fn set_unreachable(&mut self, addr: &Multiaddr) {
|
||||
for info in self.store.values_mut() {
|
||||
for a in info.addrs.iter_mut() {
|
||||
if &a.addr != addr {
|
||||
continue
|
||||
}
|
||||
|
||||
debug_assert!(!a.is_connected());
|
||||
a.adjust_score(SCORE_DIFF_ON_FAILED_TO_CONNECT);
|
||||
trace!(target: "sub-libp2p", "Back off for {} = {:?}", addr, a.next_back_off);
|
||||
a.back_off_until = Instant::now() + a.next_back_off;
|
||||
@@ -21,7 +21,6 @@ mod custom_proto;
|
||||
mod error;
|
||||
mod secret;
|
||||
mod service_task;
|
||||
mod topology;
|
||||
mod traits;
|
||||
mod transport;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ use crate::{
|
||||
transport
|
||||
};
|
||||
use crate::custom_proto::{RegisteredProtocol, RegisteredProtocols};
|
||||
use crate::topology::NetTopology;
|
||||
use crate::{Error, NetworkConfiguration, NodeIndex, ProtocolId, parse_str_addr};
|
||||
use bytes::Bytes;
|
||||
use fnv::FnvHashMap;
|
||||
@@ -37,9 +36,6 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio_timer::Interval;
|
||||
|
||||
// File where the network topology is stored.
|
||||
const NODES_FILE: &str = "nodes.json";
|
||||
|
||||
/// Starts the substrate libp2p service.
|
||||
///
|
||||
/// Returns a stream that must be polled regularly in order for the networking to function.
|
||||
@@ -58,25 +54,12 @@ where TProtos: IntoIterator<Item = RegisteredProtocol> {
|
||||
let local_public_key = local_private_key.to_public_key();
|
||||
let local_peer_id = local_public_key.clone().into_peer_id();
|
||||
|
||||
// Initialize the topology of the network.
|
||||
let mut topology = if let Some(ref path) = config.net_config_path {
|
||||
let path = Path::new(path).join(NODES_FILE);
|
||||
debug!(target: "sub-libp2p", "Initializing peer store for JSON file {:?}", path);
|
||||
NetTopology::from_file(local_public_key, path)
|
||||
} else {
|
||||
debug!(target: "sub-libp2p", "No peers file configured ; peers won't be saved");
|
||||
NetTopology::memory(local_public_key)
|
||||
};
|
||||
|
||||
// Register the external addresses provided by the user as our own.
|
||||
topology.add_external_addrs(config.public_addresses.clone().into_iter());
|
||||
|
||||
// Build the swarm.
|
||||
let (mut swarm, bandwidth) = {
|
||||
let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect());
|
||||
let behaviour = Behaviour::new(&config, local_peer_id.clone(), registered_custom);
|
||||
let behaviour = Behaviour::new(&config, local_public_key.clone(), registered_custom);
|
||||
let (transport, bandwidth) = transport::build_transport(local_private_key);
|
||||
(Swarm::new(transport, behaviour, topology), bandwidth)
|
||||
(Swarm::new(transport, behaviour, local_peer_id.clone()), bandwidth)
|
||||
};
|
||||
|
||||
// Listen on multiaddresses.
|
||||
@@ -90,11 +73,15 @@ where TProtos: IntoIterator<Item = RegisteredProtocol> {
|
||||
}
|
||||
}
|
||||
|
||||
// Add the bootstrap nodes to the topology and connect to them.
|
||||
// Add external addresses.
|
||||
for addr in &config.public_addresses {
|
||||
Swarm::add_external_address(&mut swarm, addr.clone());
|
||||
}
|
||||
|
||||
// Connect to the bootnodes.
|
||||
for bootnode in config.boot_nodes.iter() {
|
||||
match parse_str_addr(bootnode) {
|
||||
Ok((peer_id, addr)) => {
|
||||
Swarm::topology_mut(&mut swarm).add_bootstrap_addr(&peer_id, addr.clone());
|
||||
Ok((peer_id, _)) => {
|
||||
Swarm::dial(&mut swarm, peer_id);
|
||||
},
|
||||
Err(_) => {
|
||||
@@ -121,8 +108,7 @@ where TProtos: IntoIterator<Item = RegisteredProtocol> {
|
||||
// Initialize the reserved peers.
|
||||
for reserved in config.reserved_nodes.iter() {
|
||||
if let Ok((peer_id, addr)) = parse_str_addr(reserved) {
|
||||
Swarm::topology_mut(&mut swarm).add_bootstrap_addr(&peer_id, addr);
|
||||
swarm.add_reserved_peer(peer_id.clone());
|
||||
swarm.add_reserved_peer(peer_id.clone(), addr);
|
||||
Swarm::dial(&mut swarm, peer_id);
|
||||
} else {
|
||||
warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved);
|
||||
@@ -130,7 +116,7 @@ where TProtos: IntoIterator<Item = RegisteredProtocol> {
|
||||
}
|
||||
|
||||
debug!(target: "sub-libp2p", "Topology started with {} entries",
|
||||
Swarm::topology_mut(&mut swarm).num_peers());
|
||||
swarm.num_topology_peers());
|
||||
|
||||
Ok(Service {
|
||||
swarm,
|
||||
@@ -204,7 +190,7 @@ pub enum ServiceEvent {
|
||||
/// Network service. Must be polled regularly in order for the networking to work.
|
||||
pub struct Service {
|
||||
/// Stream of events of the swarm.
|
||||
swarm: Swarm<Boxed<(PeerId, StreamMuxerBox), IoError>, Behaviour<Substream<StreamMuxerBox>>, NetTopology>,
|
||||
swarm: Swarm<Boxed<(PeerId, StreamMuxerBox), IoError>, Behaviour<Substream<StreamMuxerBox>>>,
|
||||
|
||||
/// Bandwidth logging system. Can be queried to know the average bandwidth consumed.
|
||||
bandwidth: Arc<transport::BandwidthSinks>,
|
||||
@@ -270,8 +256,7 @@ impl Service {
|
||||
|
||||
/// Try to add a reserved peer.
|
||||
pub fn add_reserved_peer(&mut self, peer_id: PeerId, addr: Multiaddr) {
|
||||
Swarm::topology_mut(&mut self.swarm).add_bootstrap_addr(&peer_id, addr);
|
||||
self.swarm.add_reserved_peer(peer_id);
|
||||
self.swarm.add_reserved_peer(peer_id, addr);
|
||||
}
|
||||
|
||||
/// Try to remove a reserved peer.
|
||||
@@ -452,13 +437,13 @@ impl Service {
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Ok(Async::Ready(Some(_))) => {
|
||||
debug!(target: "sub-libp2p", "Cleaning and flushing topology");
|
||||
Swarm::topology_mut(&mut self.swarm).cleanup();
|
||||
if let Err(err) = Swarm::topology_mut(&mut self.swarm).flush_to_disk() {
|
||||
self.swarm.cleanup();
|
||||
if let Err(err) = self.swarm.flush_topology() {
|
||||
warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err);
|
||||
}
|
||||
debug!(target: "sub-libp2p", "Topology now contains {} nodes",
|
||||
Swarm::topology_mut(&mut self.swarm).num_peers());
|
||||
},
|
||||
self.swarm.num_topology_peers());
|
||||
}
|
||||
Ok(Async::Ready(None)) => {
|
||||
warn!(target: "sub-libp2p", "Topology flush stream ended unexpectedly");
|
||||
return Ok(Async::Ready(None))
|
||||
@@ -474,7 +459,7 @@ impl Service {
|
||||
|
||||
impl Drop for Service {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = Swarm::topology_mut(&mut self.swarm).flush_to_disk() {
|
||||
if let Err(err) = self.swarm.flush_topology() {
|
||||
warn!(target: "sub-libp2p", "Failed to flush topology: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ fn two_nodes_transfer_lots_of_packets() {
|
||||
});
|
||||
|
||||
let combined = fut1.select(fut2).map_err(|(err, _)| err);
|
||||
tokio::runtime::Runtime::new().unwrap().block_on_all(combined).unwrap();
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(combined).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -148,10 +148,13 @@ fn many_nodes_connectivity() {
|
||||
return Ok(Async::Ready(Some(())))
|
||||
}
|
||||
}
|
||||
// TODO: we sometimes receive a closed connection event; maybe this is
|
||||
// benign, but it would be nice to figure out why
|
||||
// (https://github.com/libp2p/rust-libp2p/issues/844)
|
||||
Some(ServiceEvent::ClosedCustomProtocol { .. }) => {}
|
||||
Some(ServiceEvent::ClosedCustomProtocol { .. }) => {
|
||||
// Only remove 1 if we haven't returned success yet, otherwise we
|
||||
// will succeed the test multiple times.
|
||||
if num_connecs < NUM_NODES - 1 {
|
||||
num_connecs -= 1;
|
||||
}
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ impl-serde = { version = "0.1", optional = true }
|
||||
wasmi = { version = "0.4.3", optional = true }
|
||||
hash-db = { version = "0.11", default-features = false }
|
||||
hash256-std-hasher = { version = "0.11", default-features = false }
|
||||
ring = { version = "0.13", optional = true }
|
||||
ring = { version = "0.14", optional = true }
|
||||
untrusted = { version = "0.6", optional = true }
|
||||
hex-literal = { version = "0.1", optional = true }
|
||||
base58 = { version = "0.1", optional = true }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
use untrusted;
|
||||
use blake2_rfc;
|
||||
use ring::{rand, signature};
|
||||
use ring::{rand, signature, signature::KeyPair};
|
||||
use {hash::H512, Ed25519AuthorityId};
|
||||
use base58::{ToBase58, FromBase58};
|
||||
|
||||
@@ -199,9 +199,11 @@ impl Pair {
|
||||
pub fn generate_with_pkcs8() -> (Self, [u8; PKCS_LEN]) {
|
||||
let rng = rand::SystemRandom::new();
|
||||
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).expect("system randomness is available; qed");
|
||||
let pair = Self::from_pkcs8(&pkcs8_bytes).expect("just-generated pkcs#8 data is valid; qed");
|
||||
let pair = Self::from_pkcs8(&pkcs8_bytes.as_ref()).expect("just-generated pkcs#8 data is valid; qed");
|
||||
|
||||
(pair, pkcs8_bytes)
|
||||
let mut out = [0; PKCS_LEN];
|
||||
out.copy_from_slice(pkcs8_bytes.as_ref());
|
||||
(pair, out)
|
||||
}
|
||||
|
||||
/// Generate new secure (random) key pair.
|
||||
@@ -211,7 +213,7 @@ impl Pair {
|
||||
}
|
||||
|
||||
/// Generate from pkcs#8 bytes.
|
||||
pub fn from_pkcs8(pkcs8_bytes: &[u8]) -> Result<Self, ::ring::error::Unspecified> {
|
||||
pub fn from_pkcs8(pkcs8_bytes: &[u8]) -> Result<Self, ::ring::error::KeyRejected> {
|
||||
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).map(Pair)
|
||||
}
|
||||
|
||||
@@ -234,7 +236,7 @@ impl Pair {
|
||||
/// Get the public key.
|
||||
pub fn public(&self) -> Public {
|
||||
let mut r = [0u8; 32];
|
||||
let pk = self.0.public_key_bytes();
|
||||
let pk = self.0.public_key().as_ref();
|
||||
r.copy_from_slice(pk);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
+35
-28
@@ -20,7 +20,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -30,8 +30,8 @@ name = "backtrace-sys"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -83,7 +83,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -209,7 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -361,7 +361,7 @@ name = "iovec"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -405,7 +405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
version = "0.2.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -490,7 +490,7 @@ dependencies = [
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -515,7 +515,7 @@ version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -536,7 +536,7 @@ version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -563,7 +563,7 @@ name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -580,7 +580,7 @@ dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -589,8 +589,8 @@ name = "openssl-sys"
|
||||
version = "0.9.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -658,7 +658,7 @@ name = "parking_lot_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -670,7 +670,7 @@ name = "parking_lot_core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -763,7 +763,7 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -774,7 +774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -786,7 +786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -859,12 +859,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.13.5"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1000,6 +1001,11 @@ dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "sr-api-macros"
|
||||
version = "0.1.0"
|
||||
@@ -1260,7 +1266,7 @@ dependencies = [
|
||||
"parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1378,7 +1384,7 @@ name = "time"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1537,7 +1543,7 @@ dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1718,7 +1724,7 @@ dependencies = [
|
||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
@@ -1762,7 +1768,7 @@ dependencies = [
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
@@ -1814,7 +1820,7 @@ dependencies = [
|
||||
"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
|
||||
"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
|
||||
"checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
@@ -1833,6 +1839,7 @@ dependencies = [
|
||||
"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a"
|
||||
"checksum slog-scope 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "053344c94c0e2b22da6305efddb698d7c485809427cf40555dc936085f67a9df"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||
"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7"
|
||||
|
||||
Reference in New Issue
Block a user