Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sudo/sessionKeys: Implement sudo_sessionKeys_unstable_generate #1682

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions substrate/client/rpc-spec-v2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ sp-core = { path = "../../primitives/core" }
sp-runtime = { path = "../../primitives/runtime" }
sp-api = { path = "../../primitives/api" }
sp-blockchain = { path = "../../primitives/blockchain" }
sp-keystore = { path = "../../primitives/keystore" }
sp-session = { path = "../../primitives/session" }
sp-version = { path = "../../primitives/version" }
sc-client-api = { path = "../api" }
sc-utils = { path = "../utils" }
Expand Down
1 change: 1 addition & 0 deletions substrate/client/rpc-spec-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
pub mod archive;
pub mod chain_head;
pub mod chain_spec;
pub mod sudo_session_keys;
pub mod transaction;

/// Task executor that is being used by RPC subscriptions.
Expand Down
37 changes: 37 additions & 0 deletions substrate/client/rpc-spec-v2/src/sudo_session_keys/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! API trait of the `sudo_sessionKeys` method.

use jsonrpsee::{core::RpcResult, proc_macros::rpc};

use super::MethodResult;

#[rpc(client, server)]
pub trait SudoSessionKeys {
/// This RPC method calls into `SessionKeys_generate_session_keys` runtime function.
///
/// The `SessionKeys_generate_session_keys` runtime function generates a series of keys,
/// inserts those keys into the keystore, and returns all the public keys concatenated.
///
/// # Unstable
///
/// This method is unstable and subject to change in the future.
#[method(name = "sudo_sessionKeys_unstable_generate")]
fn sudo_session_keys_unstable_generate(&self, seed: Option<String>) -> RpcResult<MethodResult>;
}
53 changes: 53 additions & 0 deletions substrate/client/rpc-spec-v2/src/sudo_session_keys/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! Substrate sudo sessions key API.

use serde::{Deserialize, Serialize};

#[cfg(test)]
mod tests;

pub mod api;
pub mod sudo_session_keys;

/// The result of an RPC method.
#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum MethodResult {
lexnv marked this conversation as resolved.
Show resolved Hide resolved
/// Method generated a result.
Ok(MethodResultOk),
/// Method ecountered an error.
Err(MethodResultErr),
lexnv marked this conversation as resolved.
Show resolved Hide resolved
}

/// The succesful result of an RPC method.
lexnv marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MethodResultOk {
/// The result of the method.
pub result: String,
}

/// The error result of an RPC method.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MethodResultErr {
/// The error of the method.
pub error: String,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! API implementation for `sudo_session_keys`.

use jsonrpsee::core::{async_trait, RpcResult};
use sp_blockchain::HeaderBackend;
use sp_keystore::{KeystoreExt, KeystorePtr};
use sp_runtime::traits::Block as BlockT;
use std::{marker::PhantomData, sync::Arc};

use crate::{chain_head::hex_string, sudo_session_keys::api::SudoSessionKeysServer};

use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_session::SessionKeys;

use super::{MethodResult, MethodResultErr, MethodResultOk};

/// An API for `SudoSessionKeys` RPC calls.
pub struct SudoSessionKeys<Client, Block: BlockT> {
/// Substrate client.
client: Arc<Client>,
/// The key store.
keystore: KeystorePtr,
/// Phantom data to hold the block type.
_phantom: PhantomData<Block>,
}

impl<Client, Block: BlockT> SudoSessionKeys<Client, Block> {
/// Create a new [`SudoSessionKeys`].
pub fn new(client: Arc<Client>, keystore: KeystorePtr) -> Self {
Self { client, keystore, _phantom: PhantomData }
}
}

#[async_trait]
impl<Client, Block> SudoSessionKeysServer for SudoSessionKeys<Client, Block>
where
Block: BlockT + 'static,
Client: HeaderBackend<Block> + ProvideRuntimeApi<Block> + Send + Sync + 'static,
Client::Api: SessionKeys<Block>,
{
fn sudo_session_keys_unstable_generate(&self, seed: Option<String>) -> RpcResult<MethodResult> {
// Call into the runtime of the best block hash.
let best_block_hash = self.client.info().best_hash;
let mut runtime_api = self.client.runtime_api();

runtime_api.register_extension(KeystoreExt::from(self.keystore.clone()));

let response = runtime_api
.generate_session_keys(best_block_hash, seed.map(|seed| seed.into_bytes()))
.map(|bytes| MethodResult::Ok(MethodResultOk { result: hex_string(&bytes.as_slice()) }))
.unwrap_or_else(|api_err| {
MethodResult::Err(MethodResultErr { error: api_err.to_string() })
});

Ok(response)
}
}
66 changes: 66 additions & 0 deletions substrate/client/rpc-spec-v2/src/sudo_session_keys/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use super::{sudo_session_keys::SudoSessionKeys, MethodResult};
use codec::Decode;
use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule};

use crate::sudo_session_keys::api::SudoSessionKeysServer;
use sp_core::{
crypto::ByteArray,
testing::{ED25519, SR25519},
};
use sp_keystore::{testing::MemoryKeystore, Keystore};
use std::sync::Arc;
use substrate_test_runtime_client::{
self,
runtime::{Block, SessionKeys},
Backend, Client, DefaultTestClientBuilderExt, TestClientBuilderExt,
};

fn setup_api() -> (Arc<MemoryKeystore>, RpcModule<SudoSessionKeys<Client<Backend>, Block>>) {
let keystore = Arc::new(MemoryKeystore::new());
let client = Arc::new(substrate_test_runtime_client::TestClientBuilder::new().build());
let api = SudoSessionKeys::new(client, keystore.clone()).into_rpc();

(keystore, api)
}

#[tokio::test]
async fn sudo_session_keys_unstable_generate() {
lexnv marked this conversation as resolved.
Show resolved Hide resolved
let (keystore, api) = setup_api();

let response: MethodResult = api
.call("sudo_sessionKeys_unstable_generate", EmptyParams::new())
.await
.unwrap();

let bytes = match response {
MethodResult::Ok(ok) => hex::decode(ok.result.strip_prefix("0x").unwrap()).unwrap(),
_ => panic!("Unexpected response"),
};

let session_keys =
SessionKeys::decode(&mut &bytes[..]).expect("SessionKeys decode successfully");

let ed25519_pubkeys = keystore.keys(ED25519).unwrap();
let sr25519_pubkeys = keystore.keys(SR25519).unwrap();

assert!(ed25519_pubkeys.contains(&session_keys.ed25519.to_raw_vec()));
assert!(sr25519_pubkeys.contains(&session_keys.sr25519.to_raw_vec()));
}