mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 23:31:07 +00:00
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:
+194
-29
@@ -32,7 +32,8 @@ use service::{
|
||||
FactoryGenesis, PruningMode, ChainSpec,
|
||||
};
|
||||
use network::{
|
||||
Protocol, config::{NetworkConfiguration, NonReservedPeerMode, Secret},
|
||||
self, multiaddr::Protocol,
|
||||
config::{NetworkConfiguration, NonReservedPeerMode, NodeKeyConfig},
|
||||
build_multiaddr,
|
||||
};
|
||||
use primitives::H256;
|
||||
@@ -50,6 +51,7 @@ pub use structopt::clap::App;
|
||||
use params::{
|
||||
RunCmd, PurgeChainCmd, RevertCmd, ImportBlocksCmd, ExportBlocksCmd, BuildSpecCmd,
|
||||
NetworkConfigurationParams, SharedParams, MergeParameters, TransactionPoolParams,
|
||||
NodeKeyParams, NodeKeyType
|
||||
};
|
||||
pub use params::{NoCustom, CoreParams};
|
||||
pub use traits::{GetLogFilter, AugmentClap};
|
||||
@@ -61,7 +63,18 @@ use lazy_static::lazy_static;
|
||||
use futures::Future;
|
||||
use substrate_telemetry::TelemetryEndpoints;
|
||||
|
||||
const MAX_NODE_NAME_LENGTH: usize = 32;
|
||||
/// The maximum number of characters for a node name.
|
||||
const NODE_NAME_MAX_LENGTH: usize = 32;
|
||||
|
||||
/// The file name of the node's Secp256k1 secret key inside the chain-specific
|
||||
/// network config directory, if neither `--node-key` nor `--node-key-file`
|
||||
/// is specified in combination with `--node-key-type=secp256k1`.
|
||||
const NODE_KEY_SECP256K1_FILE: &str = "secret";
|
||||
|
||||
/// The file name of the node's Ed25519 secret key inside the chain-specific
|
||||
/// network config directory, if neither `--node-key` nor `--node-key-file`
|
||||
/// is specified in combination with `--node-key-type=ed25519`.
|
||||
const NODE_KEY_ED25519_FILE: &str = "secret_ed25519";
|
||||
|
||||
/// Executable version. Used to pass version information from the root crate.
|
||||
pub struct VersionInfo {
|
||||
@@ -101,7 +114,7 @@ fn generate_node_name() -> String {
|
||||
let node_name = Generator::with_naming(Name::Numbered).next().unwrap();
|
||||
let count = node_name.chars().count();
|
||||
|
||||
if count < MAX_NODE_NAME_LENGTH {
|
||||
if count < NODE_NAME_MAX_LENGTH {
|
||||
break node_name
|
||||
}
|
||||
};
|
||||
@@ -133,14 +146,14 @@ fn base_path(cli: &SharedParams, version: &VersionInfo) -> PathBuf {
|
||||
)
|
||||
}
|
||||
|
||||
fn create_input_err<T: Into<String>>(msg: T) -> error::Error {
|
||||
fn input_err<T: Into<String>>(msg: T) -> error::Error {
|
||||
error::ErrorKind::Input(msg.into()).into()
|
||||
}
|
||||
|
||||
/// Check whether a node name is considered as valid
|
||||
fn is_node_name_valid(_name: &str) -> Result<(), &str> {
|
||||
let name = _name.to_string();
|
||||
if name.chars().count() >= MAX_NODE_NAME_LENGTH {
|
||||
if name.chars().count() >= NODE_NAME_MAX_LENGTH {
|
||||
return Err("Node name too long");
|
||||
}
|
||||
|
||||
@@ -231,14 +244,60 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_node_key(key: Option<String>) -> error::Result<Option<Secret>> {
|
||||
match key.map(|k| H256::from_str(&k)) {
|
||||
Some(Ok(secret)) => Ok(Some(secret.into())),
|
||||
Some(Err(err)) => Err(create_input_err(format!("Error parsing node key: {}", err))),
|
||||
None => Ok(None),
|
||||
/// Create a `NodeKeyConfig` from the given `NodeKeyParams` in the context
|
||||
/// of an optional network config storage directory.
|
||||
fn node_key_config<P>(params: NodeKeyParams, net_config_dir: &Option<P>)
|
||||
-> error::Result<NodeKeyConfig>
|
||||
where
|
||||
P: AsRef<Path>
|
||||
{
|
||||
match params.node_key_type {
|
||||
NodeKeyType::Secp256k1 =>
|
||||
params.node_key.as_ref().map(parse_secp256k1_secret).unwrap_or_else(||
|
||||
Ok(params.node_key_file
|
||||
.or_else(|| net_config_file(net_config_dir, NODE_KEY_SECP256K1_FILE))
|
||||
.map(network::Secret::File)
|
||||
.unwrap_or(network::Secret::New)))
|
||||
.map(NodeKeyConfig::Secp256k1),
|
||||
|
||||
NodeKeyType::Ed25519 =>
|
||||
params.node_key.as_ref().map(parse_ed25519_secret).unwrap_or_else(||
|
||||
Ok(params.node_key_file
|
||||
.or_else(|| net_config_file(net_config_dir, NODE_KEY_ED25519_FILE))
|
||||
.map(network::Secret::File)
|
||||
.unwrap_or(network::Secret::New)))
|
||||
.map(NodeKeyConfig::Ed25519)
|
||||
}
|
||||
}
|
||||
|
||||
fn net_config_file<P>(net_config_dir: &Option<P>, name: &str) -> Option<PathBuf>
|
||||
where
|
||||
P: AsRef<Path>
|
||||
{
|
||||
net_config_dir.as_ref().map(|d| d.as_ref().join(name))
|
||||
}
|
||||
|
||||
/// Create an error caused by an invalid node key argument.
|
||||
fn invalid_node_key(e: impl std::fmt::Display) -> error::Error {
|
||||
input_err(format!("Invalid node key: {}", e))
|
||||
}
|
||||
|
||||
/// Parse a Secp256k1 secret key from a hex string into a `network::Secret`.
|
||||
fn parse_secp256k1_secret(hex: &String) -> error::Result<network::Secp256k1Secret> {
|
||||
H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes|
|
||||
network::identity::secp256k1::SecretKey::from_bytes(bytes)
|
||||
.map(network::Secret::Input)
|
||||
.map_err(invalid_node_key))
|
||||
}
|
||||
|
||||
/// Parse a Ed25519 secret key from a hex string into a `network::Secret`.
|
||||
fn parse_ed25519_secret(hex: &String) -> error::Result<network::Ed25519Secret> {
|
||||
H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes|
|
||||
network::identity::ed25519::SecretKey::from_bytes(bytes)
|
||||
.map(network::Secret::Input)
|
||||
.map_err(invalid_node_key))
|
||||
}
|
||||
|
||||
/// Fill the given `PoolConfiguration` by looking at the cli parameters.
|
||||
fn fill_transaction_pool_configuration<F: ServiceFactory>(
|
||||
options: &mut FactoryFullConfiguration<F>,
|
||||
@@ -295,7 +354,7 @@ fn fill_network_configuration(
|
||||
config.public_addresses = Vec::new();
|
||||
|
||||
config.client_version = client_id;
|
||||
config.use_secret = parse_node_key(cli.node_key)?;
|
||||
config.node_key = node_key_config(cli.node_key_params, &config.net_config_path)?;
|
||||
|
||||
config.in_peers = cli.in_peers;
|
||||
config.out_peers = cli.out_peers;
|
||||
@@ -324,7 +383,7 @@ where
|
||||
match is_node_name_valid(&config.name) {
|
||||
Ok(_) => (),
|
||||
Err(msg) => bail!(
|
||||
create_input_err(
|
||||
input_err(
|
||||
format!("Invalid node name '{}'. Reason: {}. If unsure, use none.",
|
||||
config.name,
|
||||
msg
|
||||
@@ -347,7 +406,7 @@ where
|
||||
Some(ref s) if s == "archive" => PruningMode::ArchiveAll,
|
||||
None => PruningMode::default(),
|
||||
Some(s) => PruningMode::keep_blocks(
|
||||
s.parse().map_err(|_| create_input_err("Invalid pruning mode specified"))?
|
||||
s.parse().map_err(|_| input_err("Invalid pruning mode specified"))?
|
||||
),
|
||||
};
|
||||
|
||||
@@ -443,23 +502,19 @@ where
|
||||
// 9926-9949 Unassigned
|
||||
|
||||
fn with_default_boot_node<F>(
|
||||
mut spec: ChainSpec<FactoryGenesis<F>>,
|
||||
cli: &BuildSpecCmd,
|
||||
spec: &mut ChainSpec<FactoryGenesis<F>>,
|
||||
cli: BuildSpecCmd,
|
||||
version: &VersionInfo,
|
||||
) -> error::Result<ChainSpec<FactoryGenesis<F>>>
|
||||
) -> error::Result<()>
|
||||
where
|
||||
F: ServiceFactory
|
||||
{
|
||||
if spec.boot_nodes().is_empty() {
|
||||
let network_path =
|
||||
Some(network_path(&base_path(&cli.shared_params, version), spec.id()).to_string_lossy().into());
|
||||
let network_key = parse_node_key(cli.node_key.clone())?;
|
||||
|
||||
let network_keys =
|
||||
network::obtain_private_key(&network_key, &network_path)
|
||||
.map_err(|err| format!("Error obtaining network key: {}", err))?;
|
||||
|
||||
let peer_id = network_keys.to_peer_id();
|
||||
let base_path = base_path(&cli.shared_params, version);
|
||||
let storage_path = network_path(&base_path, spec.id());
|
||||
let node_key = node_key_config(cli.node_key_params, &Some(storage_path))?;
|
||||
let keys = node_key.into_keypair()?;
|
||||
let peer_id = keys.public().into_peer_id();
|
||||
let addr = build_multiaddr![
|
||||
Ip4([127, 0, 0, 1]),
|
||||
Tcp(30333u16),
|
||||
@@ -467,7 +522,7 @@ where
|
||||
];
|
||||
spec.add_boot_node(addr)
|
||||
}
|
||||
Ok(spec)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_spec<F, S>(
|
||||
@@ -480,9 +535,10 @@ where
|
||||
S: FnOnce(&str) -> Result<Option<ChainSpec<FactoryGenesis<F>>>, String>,
|
||||
{
|
||||
info!("Building chain spec");
|
||||
let spec = load_spec(&cli.shared_params, spec_factory)?;
|
||||
let spec = with_default_boot_node::<F>(spec, &cli, version)?;
|
||||
let json = service::chain_ops::build_spec::<FactoryGenesis<F>>(spec, cli.raw)?;
|
||||
let raw_output = cli.raw;
|
||||
let mut spec = load_spec(&cli.shared_params, spec_factory)?;
|
||||
with_default_boot_node::<F>(&mut spec, cli, version)?;
|
||||
let json = service::chain_ops::build_spec::<FactoryGenesis<F>>(spec, raw_output)?;
|
||||
|
||||
print!("{}", json);
|
||||
|
||||
@@ -707,6 +763,8 @@ fn kill_color(s: &str) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempdir::TempDir;
|
||||
use network::identity::{secp256k1, ed25519};
|
||||
|
||||
#[test]
|
||||
fn tests_node_name_good() {
|
||||
@@ -722,4 +780,111 @@ mod tests {
|
||||
assert!(is_node_name_valid("www.visit.me").is_err());
|
||||
assert!(is_node_name_valid("email@domain").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_key_config_input() {
|
||||
fn secret_input(net_config_dir: Option<String>) -> error::Result<()> {
|
||||
NodeKeyType::variants().into_iter().try_for_each(|t| {
|
||||
let node_key_type = NodeKeyType::from_str(t).unwrap();
|
||||
let sk = match node_key_type {
|
||||
NodeKeyType::Secp256k1 => secp256k1::SecretKey::generate().as_ref().to_vec(),
|
||||
NodeKeyType::Ed25519 => ed25519::SecretKey::generate().as_ref().to_vec()
|
||||
};
|
||||
let params = NodeKeyParams {
|
||||
node_key_type,
|
||||
node_key: Some(format!("{:x}", H256::from_slice(sk.as_ref()))),
|
||||
node_key_file: None
|
||||
};
|
||||
node_key_config(params, &net_config_dir).and_then(|c| match c {
|
||||
NodeKeyConfig::Secp256k1(network::Secret::Input(ref ski))
|
||||
if node_key_type == NodeKeyType::Secp256k1 &&
|
||||
&sk[..] == ski.as_ref() => Ok(()),
|
||||
NodeKeyConfig::Ed25519(network::Secret::Input(ref ski))
|
||||
if node_key_type == NodeKeyType::Ed25519 &&
|
||||
&sk[..] == ski.as_ref() => Ok(()),
|
||||
_ => Err(input_err("Unexpected node key config"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
assert!(secret_input(None).is_ok());
|
||||
assert!(secret_input(Some("x".to_string())).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_key_config_file() {
|
||||
fn secret_file(net_config_dir: Option<String>) -> error::Result<()> {
|
||||
NodeKeyType::variants().into_iter().try_for_each(|t| {
|
||||
let node_key_type = NodeKeyType::from_str(t).unwrap();
|
||||
let tmp = TempDir::new("alice")?;
|
||||
let file = tmp.path().join(format!("{}_mysecret", t)).to_path_buf();
|
||||
let params = NodeKeyParams {
|
||||
node_key_type,
|
||||
node_key: None,
|
||||
node_key_file: Some(file.clone())
|
||||
};
|
||||
node_key_config(params, &net_config_dir).and_then(|c| match c {
|
||||
NodeKeyConfig::Secp256k1(network::Secret::File(ref f))
|
||||
if node_key_type == NodeKeyType::Secp256k1 && f == &file => Ok(()),
|
||||
NodeKeyConfig::Ed25519(network::Secret::File(ref f))
|
||||
if node_key_type == NodeKeyType::Ed25519 && f == &file => Ok(()),
|
||||
_ => Err(input_err("Unexpected node key config"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
assert!(secret_file(None).is_ok());
|
||||
assert!(secret_file(Some("x".to_string())).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_node_key_config_default() {
|
||||
fn with_def_params<F>(f: F) -> error::Result<()>
|
||||
where
|
||||
F: Fn(NodeKeyParams) -> error::Result<()>
|
||||
{
|
||||
NodeKeyType::variants().into_iter().try_for_each(|t| {
|
||||
let node_key_type = NodeKeyType::from_str(t).unwrap();
|
||||
f(NodeKeyParams {
|
||||
node_key_type,
|
||||
node_key: None,
|
||||
node_key_file: None
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn no_config_dir() -> error::Result<()> {
|
||||
with_def_params(|params| {
|
||||
let typ = params.node_key_type;
|
||||
node_key_config::<String>(params, &None)
|
||||
.and_then(|c| match c {
|
||||
NodeKeyConfig::Secp256k1(network::Secret::New)
|
||||
if typ == NodeKeyType::Secp256k1 => Ok(()),
|
||||
NodeKeyConfig::Ed25519(network::Secret::New)
|
||||
if typ == NodeKeyType::Ed25519 => Ok(()),
|
||||
_ => Err(input_err("Unexpected node key config"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn some_config_dir(net_config_dir: String) -> error::Result<()> {
|
||||
with_def_params(|params| {
|
||||
let dir = PathBuf::from(net_config_dir.clone());
|
||||
let typ = params.node_key_type;
|
||||
node_key_config(params, &Some(net_config_dir.clone()))
|
||||
.and_then(move |c| match c {
|
||||
NodeKeyConfig::Secp256k1(network::Secret::File(ref f))
|
||||
if typ == NodeKeyType::Secp256k1 &&
|
||||
f == &dir.join(NODE_KEY_SECP256K1_FILE) => Ok(()),
|
||||
NodeKeyConfig::Ed25519(network::Secret::File(ref f))
|
||||
if typ == NodeKeyType::Ed25519 &&
|
||||
f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()),
|
||||
_ => Err(input_err("Unexpected node key config"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
assert!(no_config_dir().is_ok());
|
||||
assert!(some_config_dir("x".to_string()).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ pub struct SharedParams {
|
||||
#[structopt(long = "base-path", short = "d", value_name = "PATH", parse(from_os_str))]
|
||||
pub base_path: Option<PathBuf>,
|
||||
|
||||
///Sets a custom logging filter
|
||||
/// Sets a custom logging filter
|
||||
#[structopt(short = "l", long = "log", value_name = "LOG_PATTERN")]
|
||||
pub log: Option<String>,
|
||||
}
|
||||
@@ -98,10 +98,6 @@ pub struct NetworkConfigurationParams {
|
||||
#[structopt(long = "port", value_name = "PORT")]
|
||||
pub port: Option<u16>,
|
||||
|
||||
/// Specify node secret key (64-character hex string)
|
||||
#[structopt(long = "node-key", value_name = "KEY")]
|
||||
pub node_key: Option<String>,
|
||||
|
||||
/// Specify the number of outgoing connections we're trying to maintain
|
||||
#[structopt(long = "out-peers", value_name = "OUT_PEERS", default_value = "25")]
|
||||
pub out_peers: u32,
|
||||
@@ -109,6 +105,93 @@ pub struct NetworkConfigurationParams {
|
||||
/// Specify the maximum number of incoming connections we're accepting
|
||||
#[structopt(long = "in-peers", value_name = "IN_PEERS", default_value = "25")]
|
||||
pub in_peers: u32,
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[structopt(flatten)]
|
||||
pub node_key_params: NodeKeyParams
|
||||
}
|
||||
|
||||
arg_enum! {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum NodeKeyType {
|
||||
Secp256k1,
|
||||
Ed25519
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters used to create the `NodeKeyConfig`, which determines the keypair
|
||||
/// used for libp2p networking.
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
pub struct NodeKeyParams {
|
||||
/// The secret key to use for libp2p networking.
|
||||
///
|
||||
/// The value is a string that is parsed according to the choice of
|
||||
/// `--node-key-type` as follows:
|
||||
///
|
||||
/// `secp256k1`:
|
||||
/// The value is parsed as a hex-encoded Secp256k1 32 bytes secret key,
|
||||
/// i.e. 64 hex characters.
|
||||
///
|
||||
/// `ed25519`:
|
||||
/// The value is parsed as a hex-encoded Ed25519 32 bytes secret key,
|
||||
/// i.e. 64 hex characters.
|
||||
///
|
||||
/// The value of this option takes precedence over `--node-key-file`.
|
||||
///
|
||||
/// WARNING: Secrets provided as command-line arguments are easily exposed.
|
||||
/// Use of this option should be limited to development and testing. To use
|
||||
/// an externally managed secret key, use `--node-key-file` instead.
|
||||
#[structopt(long = "node-key", value_name = "KEY")]
|
||||
pub node_key: Option<String>,
|
||||
|
||||
/// The type of secret key to use for libp2p networking.
|
||||
///
|
||||
/// The secret key of the node is obtained as follows:
|
||||
///
|
||||
/// * If the `--node-key` option is given, the value is parsed as a secret key
|
||||
/// according to the type. See the documentation for `--node-key`.
|
||||
///
|
||||
/// * If the `--node-key-file` option is given, the secret key is read from the
|
||||
/// specified file. See the documentation for `--node-key-file`.
|
||||
///
|
||||
/// * Otherwise, the secret key is read from a file with a predetermined,
|
||||
/// type-specific name from the chain-specific network config directory
|
||||
/// inside the base directory specified by `--base-dir`. If this file does
|
||||
/// not exist, it is created with a newly generated secret key of the
|
||||
/// chosen type.
|
||||
///
|
||||
/// The node's secret key determines the corresponding public key and hence the
|
||||
/// node's peer ID in the context of libp2p.
|
||||
///
|
||||
/// NOTE: The current default key type is `secp256k1` for a transition period only
|
||||
/// but will eventually change to `ed25519` in a future release. To continue using
|
||||
/// `secp256k1` keys, use `--node-key-type=secp256k1`.
|
||||
#[structopt(
|
||||
long = "node-key-type",
|
||||
value_name = "TYPE",
|
||||
raw(
|
||||
possible_values = "&NodeKeyType::variants()",
|
||||
case_insensitive = "true",
|
||||
default_value = r#""Secp256k1""#
|
||||
)
|
||||
)]
|
||||
pub node_key_type: NodeKeyType,
|
||||
|
||||
/// The file from which to read the node's secret key to use for libp2p networking.
|
||||
///
|
||||
/// The contents of the file are parsed according to the choice of `--node-key-type`
|
||||
/// as follows:
|
||||
///
|
||||
/// `secp256k1`:
|
||||
/// The file must contain an unencoded 32 bytes Secp256k1 secret key.
|
||||
///
|
||||
/// `ed25519`:
|
||||
/// The file must contain an unencoded 32 bytes Ed25519 secret key.
|
||||
///
|
||||
/// If the file does not exist, it is created with a newly generated secret key of
|
||||
/// the chosen type.
|
||||
#[structopt(long = "node-key-file", value_name = "FILE")]
|
||||
pub node_key_file: Option<PathBuf>
|
||||
}
|
||||
|
||||
/// Parameters used to create the pool configuration.
|
||||
@@ -169,7 +252,7 @@ pub struct RunCmd {
|
||||
#[structopt(long = "name", value_name = "NAME")]
|
||||
pub name: Option<String>,
|
||||
|
||||
/// Should not connect to the Substrate telemetry server (telemetry is on by default on global chains)
|
||||
/// Disable connecting to the Substrate telemetry server (telemetry is on by default on global chains).
|
||||
#[structopt(long = "no-telemetry")]
|
||||
pub no_telemetry: bool,
|
||||
|
||||
@@ -343,9 +426,9 @@ pub struct BuildSpecCmd {
|
||||
#[structopt(flatten)]
|
||||
pub shared_params: SharedParams,
|
||||
|
||||
/// Specify node secret key (64-character hex string)
|
||||
#[structopt(long = "node-key", value_name = "KEY")]
|
||||
pub node_key: Option<String>,
|
||||
#[allow(missing_docs)]
|
||||
#[structopt(flatten)]
|
||||
pub node_key_params: NodeKeyParams,
|
||||
}
|
||||
|
||||
impl_get_log_filter!(BuildSpecCmd);
|
||||
|
||||
Reference in New Issue
Block a user