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