libp2p-0.5.0 (#1971)

* Update libp2p. Add support for ed25519 node (network) keys.

  * Update networking to the changes from https://github.com/libp2p/rust-libp2p/pull/972.
  * Add support for using ed25519 keys for libp2p networking.
  * Add support for reading libp2p secret keys from (external) files.

* Adapt to changes from https://github.com/libp2p/rust-libp2p/pull/992

* More tests.

* Cosmetics

* Deduplicate tests.

* Remove quickcheck from tests that don't use extra random inputs.

* Remove quickcheck.

* Swap new/default impls for NetworkConfiguration.

* Use libp2p-0.5.0 from crates.io.

* Post-rebase update.

* Remove unnecessary wildcard pattern.

* Combine two overlapping tests.
This commit is contained in:
Roman Borschel
2019-03-19 11:16:25 +01:00
committed by GitHub
parent 648b11e118
commit 57387ef585
19 changed files with 757 additions and 528 deletions
+24 -1
View File
@@ -25,7 +25,7 @@ use libp2p::identify::{Identify, IdentifyEvent, protocol::IdentifyInfo};
use libp2p::kad::{Kademlia, KademliaOut, KadConnectionType};
use libp2p::ping::{Ping, PingEvent};
use log::{debug, trace, warn};
use std::{cmp, io, time::Duration, time::Instant};
use std::{cmp, io, fmt, time::Duration, time::Instant};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_timer::Delay;
use void;
@@ -445,3 +445,26 @@ where
}
}
/// The severity of misbehaviour of a peer that is reported.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Severity {
/// Peer is timing out. Could be bad connectivity of overload of work on either of our sides.
Timeout,
/// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider
/// it could answer.
Useless(String),
/// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer
/// must have taken concrete action in order to behave in such a way which is wantanly invalid.
Bad(String),
}
impl fmt::Display for Severity {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Severity::Timeout => write!(fmt, "Timeout"),
Severity::Useless(r) => write!(fmt, "Useless ({})", r),
Severity::Bad(r) => write!(fmt, "Bad ({})", r),
}
}
}
+286
View File
@@ -0,0 +1,286 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Libp2p network configuration.
use libp2p::identity::{Keypair, secp256k1, ed25519};
use libp2p::{Multiaddr, multiaddr::Protocol};
use std::error::Error;
use std::{io::{self, Write}, iter, fs, net::Ipv4Addr, path::{Path, PathBuf}};
/// Network service configuration.
#[derive(Clone)]
pub struct NetworkConfiguration {
/// Directory path to store general network configuration. None means nothing will be saved.
pub config_path: Option<String>,
/// Directory path to store network-specific configuration. None means nothing will be saved.
pub net_config_path: Option<String>,
/// Multiaddresses to listen for incoming connections.
pub listen_addresses: Vec<Multiaddr>,
/// Multiaddresses to advertise. Detected automatically if empty.
pub public_addresses: Vec<Multiaddr>,
/// List of initial node addresses
pub boot_nodes: Vec<String>,
/// The node key configuration, which determines the node's network identity keypair.
pub node_key: NodeKeyConfig,
/// Maximum allowed number of incoming connections.
pub in_peers: u32,
/// Number of outgoing connections we're trying to maintain.
pub out_peers: u32,
/// List of reserved node addresses.
pub reserved_nodes: Vec<String>,
/// The non-reserved peer mode.
pub non_reserved_mode: NonReservedPeerMode,
/// Client identifier. Sent over the wire for debugging purposes.
pub client_version: String,
/// Name of the node. Sent over the wire for debugging purposes.
pub node_name: String,
}
impl Default for NetworkConfiguration {
fn default() -> Self {
NetworkConfiguration {
config_path: None,
net_config_path: None,
listen_addresses: Vec::new(),
public_addresses: Vec::new(),
boot_nodes: Vec::new(),
node_key: NodeKeyConfig::Secp256k1(Secret::New),
in_peers: 25,
out_peers: 75,
reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Accept,
client_version: "unknown".into(),
node_name: "unknown".into(),
}
}
}
impl NetworkConfiguration {
/// Create a new instance of default settings.
pub fn new() -> Self {
Self::default()
}
/// Create new default configuration for localhost-only connection with random port (useful for testing)
pub fn new_local() -> NetworkConfiguration {
let mut config = NetworkConfiguration::new();
config.listen_addresses = vec![
iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)))
.chain(iter::once(Protocol::Tcp(0)))
.collect()
];
config
}
}
/// The policy for connections to non-reserved peers.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NonReservedPeerMode {
/// Accept them. This is the default.
Accept,
/// Deny them.
Deny,
}
impl NonReservedPeerMode {
/// Attempt to parse the peer mode from a string.
pub fn parse(s: &str) -> Option<Self> {
match s {
"accept" => Some(NonReservedPeerMode::Accept),
"deny" => Some(NonReservedPeerMode::Deny),
_ => None,
}
}
}
/// The configuration of a node's secret key, describing the type of key
/// and how it is obtained. A node's identity keypair is the result of
/// the evaluation of the node key configuration.
#[derive(Clone)]
pub enum NodeKeyConfig {
/// A Secp256k1 secret key configuration.
Secp256k1(Secret<secp256k1::SecretKey>),
/// A Ed25519 secret key configuration.
Ed25519(Secret<ed25519::SecretKey>)
}
/// The options for obtaining a Secp256k1 secret key.
pub type Secp256k1Secret = Secret<secp256k1::SecretKey>;
/// The options for obtaining a Ed25519 secret key.
pub type Ed25519Secret = Secret<ed25519::SecretKey>;
/// The configuration options for obtaining a secret key `K`.
#[derive(Clone)]
pub enum Secret<K> {
/// Use the given secret key `K`.
Input(K),
/// Read the secret key from a file. If the file does not exist,
/// it is created with a newly generated secret key `K`. The format
/// of the file is determined by `K`:
///
/// * `secp256k1::SecretKey`: An unencoded 32 bytes Secp256k1 secret key.
/// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key.
File(PathBuf),
/// Always generate a new secret key `K`.
New
}
impl NodeKeyConfig {
/// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`:
///
/// * If the secret is configured as input, the corresponding keypair is returned.
///
/// * If the secret is configured as a file, it is read from that file, if it exists.
/// Otherwise a new secret is generated and stored. In either case, the
/// keypair obtained from the secret is returned.
///
/// * If the secret is configured to be new, it is generated and the corresponding
/// keypair is returned.
pub fn into_keypair(self) -> io::Result<Keypair> {
use NodeKeyConfig::*;
match self {
Secp256k1(Secret::New) =>
Ok(Keypair::generate_secp256k1()),
Secp256k1(Secret::Input(k)) =>
Ok(Keypair::Secp256k1(k.into())),
Secp256k1(Secret::File(f)) =>
get_secret(f,
|mut b| secp256k1::SecretKey::from_bytes(&mut b),
secp256k1::SecretKey::generate)
.map(secp256k1::Keypair::from)
.map(Keypair::Secp256k1),
Ed25519(Secret::New) =>
Ok(Keypair::generate_ed25519()),
Ed25519(Secret::Input(k)) =>
Ok(Keypair::Ed25519(k.into())),
Ed25519(Secret::File(f)) =>
get_secret(f,
|mut b| ed25519::SecretKey::from_bytes(&mut b),
ed25519::SecretKey::generate)
.map(ed25519::Keypair::from)
.map(Keypair::Ed25519),
}
}
}
/// Load a secret key from a file, if it exists, or generate a
/// new secret key and write it to that file. In either case,
/// the secret key is returned.
fn get_secret<P, F, G, E, K>(file: P, parse: F, generate: G) -> io::Result<K>
where
P: AsRef<Path>,
F: for<'r> FnOnce(&'r mut [u8]) -> Result<K, E>,
G: FnOnce() -> K,
E: Error + Send + Sync + 'static,
K: AsRef<[u8]>
{
std::fs::read(&file)
.and_then(|mut sk_bytes|
parse(&mut sk_bytes)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)))
.or_else(|e| {
if e.kind() == io::ErrorKind::NotFound {
file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?;
let sk = generate();
write_secret_file(file, sk.as_ref())?;
Ok(sk)
} else {
Err(e)
}
})
}
/// Write secret bytes to a file.
fn write_secret_file<P>(path: P, sk_bytes: &[u8]) -> io::Result<()>
where
P: AsRef<Path>
{
let mut file = open_secret_file(&path)?;
file.write_all(sk_bytes)
}
/// Opens a file containing a secret key in write mode.
#[cfg(unix)]
fn open_secret_file<P>(path: P) -> io::Result<fs::File>
where
P: AsRef<Path>
{
use std::os::unix::fs::OpenOptionsExt;
fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode(0o600)
.open(path)
}
/// Opens a file containing a secret key in write mode.
#[cfg(not(unix))]
fn open_secret_file<P>(path: P) -> Result<fs::File, io::Error>
where
P: AsRef<Path>
{
fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
}
#[cfg(test)]
mod tests {
use super::*;
use tempdir::TempDir;
fn secret_bytes(kp: &Keypair) -> Vec<u8> {
match kp {
Keypair::Ed25519(p) => p.secret().as_ref().iter().cloned().collect(),
Keypair::Secp256k1(p) => p.secret().as_ref().iter().cloned().collect(),
_ => panic!("Unexpected keypair.")
}
}
#[test]
fn test_secret_file() {
let tmp = TempDir::new("x").unwrap();
std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated
let file = tmp.path().join("x").to_path_buf();
let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap();
let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap();
assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2))
}
#[test]
fn test_secret_input() {
let sk = secp256k1::SecretKey::generate();
let kp1 = NodeKeyConfig::Secp256k1(Secret::Input(sk.clone())).into_keypair().unwrap();
let kp2 = NodeKeyConfig::Secp256k1(Secret::Input(sk)).into_keypair().unwrap();
assert!(secret_bytes(&kp1) == secret_bytes(&kp2));
}
#[test]
fn test_secret_new() {
let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap();
let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap();
assert!(secret_bytes(&kp1) != secret_bytes(&kp2));
}
}
@@ -71,7 +71,7 @@ pub struct CustomProtos<TMessage, TSubstream> {
/// List of the IDs of peers that are forbidden, and the moment their ban expires.
banned_peers: Vec<(PeerId, Instant)>,
/// When this delay expires, we need to synchronize our active connectons with the
/// When this delay expires, we need to synchronize our active connections with the
/// network topology.
next_connect_to_nodes: Delay,
@@ -132,11 +132,6 @@ enum PerProtocolState<TMessage, TSubstream> {
reenable: bool,
},
/// We are trying to shut down the connection and thus should refuse any incoming connection.
/// Contains substreams that are being closed. Once all the substreams are closed, we close
/// the connection.
ShuttingDown(SmallVec<[RegisteredProtocolSubstream<TMessage, TSubstream>; 6]>),
/// We sometimes temporarily switch to this state during processing. If we are in this state
/// at the beginning of a method, that means something bad happend in the source code.
Poisoned,
@@ -232,10 +227,6 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite {
return_value = None;
PerProtocolState::Disabled { shutdown, reenable: true }
}
PerProtocolState::ShuttingDown(list) => {
return_value = None;
PerProtocolState::ShuttingDown(list)
}
};
return_value
@@ -289,61 +280,11 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite {
PerProtocolState::Disabled { shutdown, .. } =>
PerProtocolState::Disabled { shutdown, reenable: false },
PerProtocolState::ShuttingDown(list) =>
PerProtocolState::ShuttingDown(list),
};
return_value
}
/// Shuts down all the substream. Returns `true` if the protocol was closed, `false` if it was
/// already closed or not open yet.
fn shutdown(&mut self) -> bool {
let mut return_value = false;
self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) {
PerProtocolState::Poisoned => {
error!(target: "sub-libp2p", "Handler is in poisoned state");
PerProtocolState::Poisoned
}
PerProtocolState::Init { substreams: mut list, .. } => {
for s in &mut list { s.shutdown(); }
PerProtocolState::ShuttingDown(list)
}
PerProtocolState::Opening { .. } => {
PerProtocolState::ShuttingDown(SmallVec::new())
}
PerProtocolState::BackCompat { mut substream, mut shutdown } => {
substream.shutdown();
shutdown.push(substream);
return_value = true;
PerProtocolState::ShuttingDown(shutdown.into_iter().collect())
}
PerProtocolState::Normal(state) => {
let mut out: SmallVec<[_; 6]> = SmallVec::new();
out.extend(state.outgoing_substream.into_iter());
out.extend(state.incoming_substreams.into_iter());
out.extend(state.pending_response.into_iter().map(|(_, s)| s));
out.extend(state.pending_send_back.into_iter().map(|(_, s)| s));
for s in &mut out {
s.shutdown();
}
out.extend(state.shutdown.into_iter());
return_value = true;
PerProtocolState::ShuttingDown(out)
}
PerProtocolState::Disabled { shutdown, .. } =>
PerProtocolState::ShuttingDown(shutdown),
PerProtocolState::ShuttingDown(list) =>
PerProtocolState::ShuttingDown(list),
};
return_value
}
/// Polls the state for events. Optionally returns an event to produce.
#[must_use]
fn poll(&mut self)
@@ -353,7 +294,7 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite {
self.state = match mem::replace(&mut self.state, PerProtocolState::Poisoned) {
PerProtocolState::Poisoned => {
error!(target: "sub-libp2p", "Handler is in poisoned state; shutting down");
return_value = Some(ProtocolsHandlerEvent::Shutdown);
return_value = None;
PerProtocolState::Poisoned
}
@@ -468,12 +409,6 @@ where TMessage: CustomMessage, TSubstream: AsyncRead + AsyncWrite {
PerProtocolState::Disabled { shutdown, reenable }
}
}
PerProtocolState::ShuttingDown(mut list) => {
shutdown_list(&mut list);
return_value = None;
PerProtocolState::ShuttingDown(list)
}
};
return_value
@@ -793,12 +728,6 @@ where
shutdown.push(substream);
PerProtocolState::Disabled { shutdown, reenable: false }
}
PerProtocolState::ShuttingDown(mut list) => {
substream.shutdown();
list.push(substream);
PerProtocolState::ShuttingDown(list)
}
};
}
@@ -909,9 +838,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage {
}
}
#[inline]
fn inject_inbound_closed(&mut self) {}
#[inline]
fn inject_dial_upgrade_error(&mut self, protocol_id: Self::OutboundOpenInfo, err: ProtocolsHandlerUpgrErr<io::Error>) {
let is_severe = match err {
@@ -942,7 +868,7 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage {
PerProtocolState::Init { .. } | PerProtocolState::Opening { .. } => {}
PerProtocolState::BackCompat { .. } | PerProtocolState::Normal { .. } =>
keep_forever = true,
PerProtocolState::Disabled { .. } | PerProtocolState::ShuttingDown(_) |
PerProtocolState::Disabled { .. } |
PerProtocolState::Poisoned => return KeepAlive::Now,
}
}
@@ -954,18 +880,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage {
}
}
fn shutdown(&mut self) {
for protocol in &mut self.protocols {
if protocol.shutdown() {
let event = CustomProtosHandlerOut::CustomProtocolClosed {
protocol_id: protocol.protocol.id(),
result: Ok(())
};
self.events_queue.push(ProtocolsHandlerEvent::Custom(event));
}
}
}
fn poll(
&mut self,
) -> Poll<
@@ -985,16 +899,6 @@ where TSubstream: AsyncRead + AsyncWrite, TMessage: CustomMessage {
}
}
// Shut down the node if everything is closed.
let can_shut_down = self.protocols.iter().all(|p|
match p.state {
PerProtocolState::ShuttingDown(ref list) if list.is_empty() => true,
_ => false
});
if can_shut_down {
return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown))
}
Ok(Async::NotReady)
}
}
+19 -10
View File
@@ -17,29 +17,38 @@
//! Networking layer of Substrate.
mod behaviour;
mod config;
mod custom_proto;
mod secret;
mod service_task;
mod traits;
mod transport;
pub use crate::behaviour::Severity;
pub use crate::config::*;
pub use crate::custom_proto::{CustomMessage, CustomMessageId, RegisteredProtocol};
pub use crate::secret::obtain_private_key;
pub use crate::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPeerMode};
pub use crate::service_task::{start_service, Service, ServiceEvent};
pub use crate::traits::{NetworkConfiguration, NodeIndex, NodeId, NonReservedPeerMode};
pub use crate::traits::{ProtocolId, Secret, Severity};
pub use libp2p::{Multiaddr, multiaddr::Error as MultiaddrError, multiaddr::Protocol, build_multiaddr, PeerId, core::PublicKey};
pub use libp2p::{Multiaddr, multiaddr, build_multiaddr};
pub use libp2p::{identity, PeerId, core::PublicKey};
use libp2p::core::nodes::ConnectedPoint;
use serde_derive::Serialize;
use std::{collections::{HashMap, HashSet}, error, fmt, time::Duration};
/// Protocol / handler id
pub type ProtocolId = [u8; 3];
/// Node public key
pub type NodeId = PeerId;
/// Local (temporary) peer session ID.
pub type NodeIndex = usize;
/// Parses a string address and returns the component, if valid.
pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> {
let mut addr: Multiaddr = addr_str.parse()?;
let who = match addr.pop() {
Some(Protocol::P2p(key)) => PeerId::from_multihash(key)
Some(multiaddr::Protocol::P2p(key)) => PeerId::from_multihash(key)
.map_err(|_| ParseErr::InvalidPeerId)?,
_ => return Err(ParseErr::PeerIdMissing),
};
@@ -51,7 +60,7 @@ pub fn parse_str_addr(addr_str: &str) -> Result<(PeerId, Multiaddr), ParseErr> {
#[derive(Debug)]
pub enum ParseErr {
/// Error while parsing the multiaddress.
MultiaddrParse(MultiaddrError),
MultiaddrParse(multiaddr::Error),
/// Multihash of the peer ID is invalid.
InvalidPeerId,
/// The peer ID is missing from the address.
@@ -78,8 +87,8 @@ impl error::Error for ParseErr {
}
}
impl From<MultiaddrError> for ParseErr {
fn from(err: MultiaddrError) -> ParseErr {
impl From<multiaddr::Error> for ParseErr {
fn from(err: multiaddr::Error) -> ParseErr {
ParseErr::MultiaddrParse(err)
}
}
-138
View File
@@ -1,138 +0,0 @@
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::NetworkConfiguration;
use libp2p::secio;
use log::{trace, warn};
use rand::Rng;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write};
use std::{fs, path::Path};
// File where the private key is stored.
const SECRET_FILE: &str = "secret";
/// Obtains or generates the local private key using the configuration.
pub fn obtain_private_key_from_config(
config: &NetworkConfiguration
) -> Result<secio::SecioKeyPair, IoError> {
obtain_private_key(&config.use_secret, &config.net_config_path)
}
/// Obtains or generates the local private key using the configuration.
pub fn obtain_private_key(
secret: &Option<[u8; 32]>,
net_config_path: &Option<String>,
) -> Result<secio::SecioKeyPair, IoError> {
if let Some(ref secret) = secret {
// Key was specified in the configuration.
secio::SecioKeyPair::secp256k1_raw_key(&secret[..])
.map_err(|err| IoError::new(IoErrorKind::InvalidData, err))
} else {
if let Some(ref path) = net_config_path {
fs::create_dir_all(Path::new(path))?;
// Try fetch the key from a the file containing the secret.
let secret_path = Path::new(path).join(SECRET_FILE);
match load_private_key_from_file(&secret_path) {
Ok(s) => Ok(s),
Err(err) => {
// Failed to fetch existing file ; generate a new key
trace!(target: "sub-libp2p",
"Failed to load existing secret key file {:?}, generating new key ; err = {:?}",
secret_path,
err
);
Ok(gen_key_and_try_write_to_file(&secret_path))
}
}
} else {
// No path in the configuration, nothing we can do except generate
// a new key.
let mut key: [u8; 32] = [0; 32];
rand::rngs::EntropyRng::new().fill(&mut key);
Ok(secio::SecioKeyPair::secp256k1_raw_key(&key)
.expect("randomly-generated key with correct len should always be valid"))
}
}
}
/// Tries to load a private key from a file located at the given path.
fn load_private_key_from_file<P>(path: P)
-> Result<secio::SecioKeyPair, IoError>
where P: AsRef<Path> {
fs::File::open(path)
.and_then(|mut file| {
// We are in 2018 and there is still no method on `std::io::Read`
// that directly returns a `Vec`.
let mut buf = Vec::new();
file.read_to_end(&mut buf).map(|_| buf)
})
.and_then(|content|
secio::SecioKeyPair::secp256k1_raw_key(&content)
.map_err(|err| IoError::new(IoErrorKind::InvalidData, err))
)
}
/// Generates a new secret key and tries to write it to the given file.
/// Doesn't error if we couldn't open or write to the file.
fn gen_key_and_try_write_to_file<P>(path: P) -> secio::SecioKeyPair
where P: AsRef<Path> {
let raw_key: [u8; 32] = rand::rngs::EntropyRng::new().gen();
let secio_key = secio::SecioKeyPair::secp256k1_raw_key(&raw_key)
.expect("randomly-generated key with correct len should always be valid");
// And store the newly-generated key in the file if possible.
// Errors that happen while doing so are ignored.
match open_priv_key_file(&path) {
Ok(mut file) =>
match file.write_all(&raw_key) {
Ok(()) => (),
Err(err) => warn!(target: "sub-libp2p",
"Failed to write secret key in file {:?} ; err = {:?}",
path.as_ref(),
err
),
},
Err(err) => warn!(target: "sub-libp2p",
"Failed to store secret key in file {:?} ; err = {:?}",
path.as_ref(),
err
),
}
secio_key
}
/// Opens a file containing a private key in write mode.
#[cfg(unix)]
fn open_priv_key_file<P>(path: P) -> Result<fs::File, IoError>
where P: AsRef<Path> {
use std::os::unix::fs::OpenOptionsExt;
fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode(256 | 128) // 0o600 in decimal
.open(path)
}
/// Opens a file containing a private key in write mode.
#[cfg(not(unix))]
fn open_priv_key_file<P>(path: P) -> Result<fs::File, IoError>
where P: AsRef<Path> {
fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
}
@@ -15,7 +15,7 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::{
behaviour::Behaviour, behaviour::BehaviourOut, secret::obtain_private_key_from_config,
behaviour::Behaviour, behaviour::BehaviourOut,
transport, NetworkState, NetworkStatePeer, NetworkStateNotConnectedPeer
};
use crate::custom_proto::{CustomMessage, RegisteredProtocol, RegisteredProtocols};
@@ -49,15 +49,15 @@ where TProtos: IntoIterator<Item = RegisteredProtocol<TMessage>>,
}
// Private and public keys configuration.
let local_private_key = obtain_private_key_from_config(&config)?;
let local_public_key = local_private_key.to_public_key();
let local_peer_id = local_public_key.clone().into_peer_id();
let local_identity = config.node_key.clone().into_keypair()?;
let local_public = local_identity.public();
let local_peer_id = local_public.clone().into_peer_id();
// Build the swarm.
let (mut swarm, bandwidth) = {
let registered_custom = RegisteredProtocols(registered_custom.into_iter().collect());
let behaviour = Behaviour::new(&config, local_public_key.clone(), registered_custom);
let (transport, bandwidth) = transport::build_transport(local_private_key);
let behaviour = Behaviour::new(&config, local_public, registered_custom);
let (transport, bandwidth) = transport::build_transport(local_identity);
(Swarm::new(transport, behaviour, local_peer_id.clone()), bandwidth)
};
-139
View File
@@ -1,139 +0,0 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::{fmt, iter, net::Ipv4Addr, str};
use libp2p::{multiaddr::Protocol, Multiaddr, PeerId};
/// Protocol / handler id
pub type ProtocolId = [u8; 3];
/// Node public key
pub type NodeId = PeerId;
/// Local (temporary) peer session ID.
pub type NodeIndex = usize;
/// secio secret key;
pub type Secret = [u8; 32];
/// Network service configuration
#[derive(Debug, PartialEq, Clone)]
pub struct NetworkConfiguration {
/// Directory path to store general network configuration. None means nothing will be saved
pub config_path: Option<String>,
/// Directory path to store network-specific configuration. None means nothing will be saved
pub net_config_path: Option<String>,
/// Multiaddresses to listen for incoming connections.
pub listen_addresses: Vec<Multiaddr>,
/// Multiaddresses to advertise. Detected automatically if empty.
pub public_addresses: Vec<Multiaddr>,
/// List of initial node addresses
pub boot_nodes: Vec<String>,
/// Use provided node key instead of default
pub use_secret: Option<Secret>,
/// Maximum allowed number of incoming connections
pub in_peers: u32,
/// Number of outgoing connections we're trying to maintain
pub out_peers: u32,
/// List of reserved node addresses.
pub reserved_nodes: Vec<String>,
/// The non-reserved peer mode.
pub non_reserved_mode: NonReservedPeerMode,
/// Client identifier. Sent over the wire for debugging purposes.
pub client_version: String,
/// Name of the node. Sent over the wire for debugging purposes.
pub node_name: String,
}
impl Default for NetworkConfiguration {
fn default() -> Self {
NetworkConfiguration::new()
}
}
impl NetworkConfiguration {
/// Create a new instance of default settings.
pub fn new() -> Self {
NetworkConfiguration {
config_path: None,
net_config_path: None,
listen_addresses: Vec::new(),
public_addresses: Vec::new(),
boot_nodes: Vec::new(),
use_secret: None,
in_peers: 25,
out_peers: 75,
reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Accept,
client_version: "unknown".into(),
node_name: "unknown".into(),
}
}
/// Create new default configuration for localhost-only connection with random port (useful for testing)
pub fn new_local() -> NetworkConfiguration {
let mut config = NetworkConfiguration::new();
config.listen_addresses = vec![
iter::once(Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)))
.chain(iter::once(Protocol::Tcp(0)))
.collect()
];
config
}
}
/// The severity of misbehaviour of a peer that is reported.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Severity {
/// Peer is timing out. Could be bad connectivity of overload of work on either of our sides.
Timeout,
/// Peer has been notably useless. E.g. unable to answer a request that we might reasonably consider
/// it could answer.
Useless(String),
/// Peer has behaved in an invalid manner. This doesn't necessarily need to be Byzantine, but peer
/// must have taken concrete action in order to behave in such a way which is wantanly invalid.
Bad(String),
}
impl fmt::Display for Severity {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Severity::Timeout => write!(fmt, "Timeout"),
Severity::Useless(r) => write!(fmt, "Useless ({})", r),
Severity::Bad(r) => write!(fmt, "Bad ({})", r),
}
}
}
/// Non-reserved peer modes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NonReservedPeerMode {
/// Accept them. This is the default.
Accept,
/// Deny them.
Deny,
}
impl NonReservedPeerMode {
/// Attempt to parse the peer mode from a string.
pub fn parse(s: &str) -> Option<Self> {
match s {
"accept" => Some(NonReservedPeerMode::Accept),
"deny" => Some(NonReservedPeerMode::Deny),
_ => None,
}
}
}
@@ -17,7 +17,7 @@
use futures::prelude::*;
use libp2p::{
InboundUpgradeExt, OutboundUpgradeExt, PeerId, Transport,
mplex, secio, yamux, tcp, dns, websocket, bandwidth
mplex, identity, secio, yamux, tcp, dns, websocket, bandwidth
};
use libp2p::core::{self, transport::boxed::Boxed, muxing::StreamMuxerBox};
use std::{io, sync::Arc, time::Duration, usize};
@@ -29,7 +29,7 @@ pub use self::bandwidth::BandwidthSinks;
/// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all
/// the connections spawned with this transport.
pub fn build_transport(
local_private_key: secio::SecioKeyPair
keypair: identity::Keypair
) -> (Boxed<(PeerId, StreamMuxerBox), io::Error>, Arc<bandwidth::BandwidthSinks>) {
let mut mplex_config = mplex::MplexConfig::new();
mplex_config.max_buffer_len_behaviour(mplex::MaxBufferBehaviour::Block);
@@ -42,7 +42,7 @@ pub fn build_transport(
// TODO: rework the transport creation (https://github.com/libp2p/rust-libp2p/issues/783)
let transport = transport
.with_upgrade(secio::SecioConfig::new(local_private_key))
.with_upgrade(secio::SecioConfig::new(keypair))
.and_then(move |out, endpoint| {
let peer_id = out.remote_key.into_peer_id();
let peer_id2 = peer_id.clone();