From 65e78b81294808f3c5738b88388f65cdb2aed254 Mon Sep 17 00:00:00 2001
From: Nikolay Volf <nikvolf@gmail.com>
Date: Thu, 2 Jan 2020 14:46:45 +0300
Subject: [PATCH] Insert key via node RPC for subkey (#4514)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Insert key via node RPC.

* somewhat address the reivew

* Update bin/utils/subkey/src/rpc.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update bin/utils/subkey/src/rpc.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update bin/utils/subkey/src/main.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
---
 substrate/Cargo.lock                   |  4 +++
 substrate/bin/utils/subkey/Cargo.toml  |  4 +++
 substrate/bin/utils/subkey/src/main.rs | 28 +++++++++++++++
 substrate/bin/utils/subkey/src/rpc.rs  | 49 ++++++++++++++++++++++++++
 4 files changed, 85 insertions(+)
 create mode 100644 substrate/bin/utils/subkey/src/rpc.rs

diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index a426e58fcfa..e53a3e440e1 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -6725,9 +6725,12 @@ dependencies = [
  "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "frame-system 2.0.0",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core-client 14.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "node-primitives 2.0.0",
  "node-runtime 2.0.0",
  "pallet-balances 2.0.0",
@@ -6736,6 +6739,7 @@ dependencies = [
  "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rpassword 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sc-rpc 2.0.0",
  "sp-core 2.0.0",
  "sp-runtime 2.0.0",
  "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml
index c042b76f4a8..b4398d9f8b2 100644
--- a/substrate/bin/utils/subkey/Cargo.toml
+++ b/substrate/bin/utils/subkey/Cargo.toml
@@ -5,6 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 
 [dependencies]
+futures = "0.1.29"
 sp-core = { version = "*", path = "../../../primitives/core" }
 node-runtime = { version = "*", path = "../../node/runtime" }
 node-primitives = { version = "*", path = "../../node/primitives" }
@@ -23,6 +24,9 @@ pallet-transaction-payment = { version = "2.0.0", path = "../../../frame/transac
 rpassword = "4.0.1"
 itertools = "0.8.2"
 derive_more = { version = "0.99.2" }
+sc-rpc = { version = "2.0.0", path = "../../../client/rpc" }
+jsonrpc-core-client = { version = "14.0.3", features = ["http"] }
+hyper = "0.12.35"
 
 [features]
 bench = []
diff --git a/substrate/bin/utils/subkey/src/main.rs b/substrate/bin/utils/subkey/src/main.rs
index d586fac6f90..616b1692899 100644
--- a/substrate/bin/utils/subkey/src/main.rs
+++ b/substrate/bin/utils/subkey/src/main.rs
@@ -34,6 +34,7 @@ use std::{
 	convert::{TryInto, TryFrom}, io::{stdin, Read}, str::FromStr, path::PathBuf, fs, fmt,
 };
 
+mod rpc;
 mod vanity;
 
 trait Crypto: Sized {
@@ -231,6 +232,15 @@ fn get_app<'a, 'b>(usage: &'a str) -> App<'a, 'b> {
 						If the value is a file, the file content is used as URI. \
 						If not given, you will be prompted for the URI.'
 				"),
+			SubCommand::with_name("insert")
+				.about("Insert a key to the keystore of a node")
+				.args_from_usage("
+					<suri> '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.'
+					<key-type> 'Key type, examples: \"gran\", or \"imon\" '
+					[node-url] 'Node JSON-RPC endpoint, default \"http:://localhost:9933\"'
+				"),
 		])
 }
 
@@ -384,6 +394,24 @@ where
 
 			print_extrinsic(extrinsic);
 		}
+		("insert", Some(matches)) => {
+			let suri = get_uri("suri", &matches)?;
+			let pair = read_pair::<C>(Some(&suri), password)?;
+			let node_url = matches.value_of("node-url").unwrap_or("http://localhost:9933");
+			let key_type = matches.value_of("key-type").ok_or(Error::Static("Key type id is required"))?;
+
+			// Just checking
+			let _key_type_id = sp_core::crypto::KeyTypeId::try_from(key_type)
+				.map_err(|_| Error::Static("Cannot convert argument to keytype: argument should be 4-character string"))?;
+
+			let rpc = rpc::RpcClient::new(node_url.to_string());
+
+			rpc.insert_key(
+				key_type.to_string(),
+				suri,
+				sp_core::Bytes(pair.public().as_ref().to_vec()),
+			);
+		}
 		_ => print_usage(&matches),
 	}
 
diff --git a/substrate/bin/utils/subkey/src/rpc.rs b/substrate/bin/utils/subkey/src/rpc.rs
new file mode 100644
index 00000000000..1b8e46315c2
--- /dev/null
+++ b/substrate/bin/utils/subkey/src/rpc.rs
@@ -0,0 +1,49 @@
+// Copyright 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/>.
+
+//! Helper to run commands against current node RPC
+
+use futures::Future;
+use hyper::rt;
+use node_primitives::Hash;
+use sc_rpc::author::AuthorClient;
+use jsonrpc_core_client::transports::http;
+use sp_core::Bytes;
+
+pub struct RpcClient { url: String }
+
+impl RpcClient {
+	pub fn new(url: String) -> Self { Self { url } }
+
+	pub fn insert_key(
+		&self,
+		key_type: String,
+		suri: String,
+		public: Bytes,
+	) {
+		let url = self.url.clone();
+
+		rt::run(
+			http::connect(&url)
+				.and_then(|client: AuthorClient<Hash, Hash>| {
+					client.insert_key(key_type, suri, public).map(|_| ())
+				})
+				.map_err(|e| {
+					println!("Error inserting key: {:?}", e);
+				})
+		);
+	}
+}
-- 
GitLab