From d95c901782e0ff48394562afe4e3425cd7538442 Mon Sep 17 00:00:00 2001 From: librelois <c@elo.tf> Date: Sat, 22 Jan 2022 01:53:32 +0100 Subject: [PATCH] feat(cli): add subcommand generate-session-keys --- Cargo.lock | 2 + Cargo.toml | 2 + node/src/cli.rs | 6 ++- node/src/cli/key.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 node/src/cli/key.rs diff --git a/Cargo.lock b/Cargo.lock index 15e89cff4..03e3e8186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1235,6 +1235,7 @@ dependencies = [ "g1-runtime", "gdev-runtime", "gtest-runtime", + "hex", "jsonrpc-core", "log", "maplit", @@ -1268,6 +1269,7 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-keyring", + "sp-keystore", "sp-membership", "sp-offchain", "sp-runtime", diff --git a/Cargo.toml b/Cargo.toml index caeb104c2..6d9f96550 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ sp-membership = { path = 'primitives/membership' } # crates.io dependencies async-io = "1.3" futures = { version = "0.3.1", features = ["compat"] } +hex = "0.4.3" jsonrpc-core = '18.0.0' log = "0.4" maplit = '1.0.2' @@ -85,6 +86,7 @@ sp-core = { git = "https://github.com/librelois/substrate.git", branch = "dunite sp-finality-grandpa = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } sp-offchain = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } sp-keyring = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } +sp-keystore = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } sp-runtime = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } sp-session = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } sp-storage = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-01" } diff --git a/node/src/cli.rs b/node/src/cli.rs index 534ad8b38..ed59dbc65 100644 --- a/node/src/cli.rs +++ b/node/src/cli.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>. +pub mod key; + use sc_cli::RunCmd; use std::str::FromStr; use structopt::StructOpt; @@ -26,7 +28,7 @@ pub struct Cli { #[structopt(flatten)] pub run: RunCmd, - /// When blocks should be sealed in the dev service. + /// How blocks should be sealed /// /// Options are "production", "instant", "manual", or timer interval in milliseconds #[structopt(long, default_value = "production")] @@ -36,7 +38,7 @@ pub struct Cli { #[derive(Debug, StructOpt)] pub enum Subcommand { /// Key management cli utilities - Key(sc_cli::KeySubcommand), + Key(key::KeySubcommand), /// Build a chain specification. BuildSpec(sc_cli::BuildSpecCmd), diff --git a/node/src/cli/key.rs b/node/src/cli/key.rs new file mode 100644 index 000000000..0ed9d0a6e --- /dev/null +++ b/node/src/cli/key.rs @@ -0,0 +1,111 @@ +// Copyright 2021 Axiom-Team +// +// This file is part of Substrate-Libre-Currency. +// +// Substrate-Libre-Currency is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Substrate-Libre-Currency 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>. + +use sc_cli::{ + utils, with_crypto_scheme, CryptoScheme, Error, KeystoreParams, SharedParams, SubstrateCli, +}; +use sc_keystore::LocalKeystore; +use sc_service::config::{BasePath, KeystoreConfig}; +use sp_core::crypto::{KeyTypeId, SecretString}; +use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use std::sync::Arc; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +pub enum KeySubcommand { + /// Generate session keys and store them in the keystore + GenerateSessionKeys(GenSessionKeysCmd), + + #[allow(missing_docs)] + #[structopt(flatten)] + Key(sc_cli::KeySubcommand), +} + +impl KeySubcommand { + /// Run the command + pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> { + match self { + Self::GenerateSessionKeys(cmd) => cmd.run(cli), + Self::Key(cmd) => cmd.run(cli), + } + } +} + +#[derive(Debug, StructOpt)] +pub struct GenSessionKeysCmd { + /// The secret key URI. + /// If the value is a file, the file content is used as URI. + /// If not given, you will be prompted for the URI. + #[structopt(long)] + suri: Option<String>, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub keystore_params: KeystoreParams, +} + +const KEY_TYPES: [(KeyTypeId, CryptoScheme); 4] = [ + (KeyTypeId(*b"gran"), CryptoScheme::Ed25519), + (KeyTypeId(*b"babe"), CryptoScheme::Sr25519), + (KeyTypeId(*b"imon"), CryptoScheme::Sr25519), + (KeyTypeId(*b"audi"), CryptoScheme::Sr25519), +]; + +impl GenSessionKeysCmd { + /// Run the command + pub fn run<C: SubstrateCli>(&self, cli: &C) -> Result<(), Error> { + let suri = utils::read_uri(self.suri.as_ref())?; + let base_path = self + .shared_params + .base_path() + .unwrap_or_else(|| BasePath::from_project("", "", &C::executable_name())); + let chain_id = self.shared_params.chain_id(self.shared_params.is_dev()); + let chain_spec = cli.load_spec(&chain_id)?; + let config_dir = base_path.config_dir(chain_spec.id()); + + let mut public_keys = Vec::with_capacity(128); + for (key_type_id, crypto_scheme) in KEY_TYPES { + let (keystore, public) = match self.keystore_params.keystore_config(&config_dir)? { + (_, KeystoreConfig::Path { path, password }) => { + let public = + with_crypto_scheme!(crypto_scheme, to_vec(&suri, password.clone()))?; + let keystore: SyncCryptoStorePtr = + Arc::new(LocalKeystore::open(path, password)?); + (keystore, public) + } + _ => unreachable!("keystore_config always returns path and password; qed"), + }; + + SyncCryptoStore::insert_unknown(&*keystore, key_type_id, &suri, &public[..]) + .map_err(|_| Error::KeyStoreOperation)?; + + public_keys.extend_from_slice(&public[..]); + } + + println!("Session Keys: 0x{}", hex::encode(public_keys)); + + Ok(()) + } +} + +fn to_vec<P: sp_core::Pair>(uri: &str, pass: Option<SecretString>) -> Result<Vec<u8>, Error> { + let p = utils::pair_from_suri::<P>(uri, pass)?; + Ok(p.public().as_ref().to_vec()) +} -- GitLab