diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 5e763195a4..bcadbe2e74 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -2339,7 +2339,7 @@ name = "node-primitives" version = "2.0.0" dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -2858,15 +2858,6 @@ name = "ppv-lite86" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pretty_assertions" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pretty_assertions" version = "0.6.1" @@ -4837,6 +4828,7 @@ dependencies = [ "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", + "substrate-session 2.0.0", "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", @@ -5040,6 +5032,7 @@ dependencies = [ "substrate-keyring 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", + "substrate-session 2.0.0", "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-trie 2.0.0", @@ -6364,7 +6357,6 @@ dependencies = [ "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum primitive-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e44400d651ca5276415dc8e00541c5c9d03844f1f0a87ad28f0a8fadcb2300bc" "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" diff --git a/substrate/core/primitives/src/crypto.rs b/substrate/core/primitives/src/crypto.rs index 56a8528369..0adf50e160 100644 --- a/substrate/core/primitives/src/crypto.rs +++ b/substrate/core/primitives/src/crypto.rs @@ -18,7 +18,9 @@ //! Cryptographic utilities. // end::description[] -use rstd::convert::{TryFrom, TryInto}; +#[cfg(feature = "std")] +use rstd::convert::TryInto; +use rstd::convert::TryFrom; #[cfg(feature = "std")] use parking_lot::Mutex; #[cfg(feature = "std")] diff --git a/substrate/core/rpc/Cargo.toml b/substrate/core/rpc/Cargo.toml index 3072ba4783..ab05eb4e24 100644 --- a/substrate/core/rpc/Cargo.toml +++ b/substrate/core/rpc/Cargo.toml @@ -21,6 +21,7 @@ client = { package = "substrate-client", path = "../client" } substrate-executor = { path = "../executor" } network = { package = "substrate-network", path = "../network" } primitives = { package = "substrate-primitives", path = "../primitives" } +session = { package = "substrate-session", path = "../session" } state_machine = { package = "substrate-state-machine", path = "../state-machine" } transaction_pool = { package = "substrate-transaction-pool", path = "../transaction-pool" } sr-primitives = { path = "../sr-primitives" } @@ -33,4 +34,4 @@ futures = "0.1.17" sr-io = { path = "../sr-io" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" } rustc-hex = "2.0" -tokio = "0.1.17" +tokio = "0.1.17" \ No newline at end of file diff --git a/substrate/core/rpc/src/author/mod.rs b/substrate/core/rpc/src/author/mod.rs index 47f481f00f..d797e87da5 100644 --- a/substrate/core/rpc/src/author/mod.rs +++ b/substrate/core/rpc/src/author/mod.rs @@ -33,9 +33,9 @@ use log::warn; use codec::{Encode, Decode}; use primitives::{ Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Pair, Public, key_types}, - traits::BareCryptoStorePtr + traits::BareCryptoStorePtr, }; -use sr_primitives::{generic, traits}; +use sr_primitives::{generic, traits::{self, ProvideRuntimeApi}}; use self::error::{Error, Result}; use transaction_pool::{ txpool::{ @@ -47,6 +47,7 @@ use transaction_pool::{ watcher::Status, }, }; +use session::SessionKeys; pub use self::gen_client::Client as AuthorClient; @@ -68,6 +69,10 @@ pub trait AuthorApi { maybe_public: Option ) -> Result; + /// Generate new session keys and returns the corresponding public keys. + #[rpc(name = "author_rotateKeys")] + fn rotate_keys(&self) -> Result; + /// Returns all pending extrinsics, potentially grouped by sender. #[rpc(name = "author_pendingExtrinsics")] fn pending_extrinsics(&self) -> Result>; @@ -138,6 +143,8 @@ impl AuthorApi, BlockHash

> for Author whe P::Block: traits::Block, P::Error: 'static, RA: Send + Sync + 'static, + Client: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: SessionKeys, { type Metadata = crate::metadata::Metadata; @@ -170,6 +177,14 @@ impl AuthorApi, BlockHash

> for Author whe Ok(public.into()) } + fn rotate_keys(&self) -> Result { + let best_block_hash = self.client.info().chain.best_hash; + self.client.runtime_api().generate_session_keys( + &generic::BlockId::Hash(best_block_hash), + None, + ).map(Into::into).map_err(Into::into) + } + fn submit_extrinsic(&self, ext: Bytes) -> Result> { let xt = Decode::decode(&mut &ext[..])?; let best_block_hash = self.client.info().chain.best_hash; diff --git a/substrate/core/rpc/src/author/tests.rs b/substrate/core/rpc/src/author/tests.rs index 18a2e41739..0fdff9989b 100644 --- a/substrate/core/rpc/src/author/tests.rs +++ b/substrate/core/rpc/src/author/tests.rs @@ -27,7 +27,10 @@ use primitives::{ H256, blake2_256, hexdisplay::HexDisplay, traits::BareCryptoStore, testing::KeyStore, ed25519, crypto::key_types, }; -use test_client::{self, AccountKeyring, runtime::{Extrinsic, Transfer}}; +use test_client::{ + self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys}, DefaultTestClientBuilderExt, + TestClientBuilderExt, +}; use tokio::runtime; fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { @@ -203,4 +206,35 @@ fn should_insert_key() { .ed25519_key_pair(key_types::ED25519, &key_pair.public()).expect("Key exists in store"); assert_eq!(key_pair.public(), store_key_pair.public()); +} + +#[test] +fn should_rotate_keys() { + let runtime = runtime::Runtime::new().unwrap(); + let keystore = KeyStore::new(); + let client = Arc::new(test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build()); + let p = Author { + client: client.clone(), + pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client))), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), + }; + + let new_public_keys = p.rotate_keys().expect("Rotates the keys"); + + let session_keys = SessionKeys::decode(&mut &new_public_keys[..]) + .expect("SessionKeys decode successfully"); + + let ed25519_key_pair = keystore.read().ed25519_key_pair( + key_types::ED25519, + &session_keys.ed25519.clone().into(), + ).expect("ed25519 key exists in store"); + + let sr25519_key_pair = keystore.read().sr25519_key_pair( + key_types::SR25519, + &session_keys.sr25519.clone().into(), + ).expect("sr25519 key exists in store"); + + assert_eq!(session_keys.ed25519, ed25519_key_pair.public().into()); + assert_eq!(session_keys.sr25519, sr25519_key_pair.public().into()); } \ No newline at end of file diff --git a/substrate/core/rpc/src/state/tests.rs b/substrate/core/rpc/src/state/tests.rs index 6a8eefa10b..6b4ddc9b92 100644 --- a/substrate/core/rpc/src/state/tests.rs +++ b/substrate/core/rpc/src/state/tests.rs @@ -260,7 +260,8 @@ fn should_return_runtime_version() { \"specVersion\":1,\"implVersion\":1,\"apis\":[[\"0xdf6acb689907609b\",2],\ [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",1],[\"0x40fe3ad401f8959a\",3],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",1],\ - [\"0xf78b278be53f454c\",1]]}"; + [\"0xf78b278be53f454c\",1],[\"0xab3c0572291feb8b\",1]]}"; + assert_eq!( serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(), result, diff --git a/substrate/core/service/Cargo.toml b/substrate/core/service/Cargo.toml index 2bcb180570..c2a17371da 100644 --- a/substrate/core/service/Cargo.toml +++ b/substrate/core/service/Cargo.toml @@ -23,8 +23,8 @@ keystore = { package = "substrate-keystore", path = "../../core/keystore" } sr-io = { path = "../../core/sr-io" } sr-primitives = { path = "../../core/sr-primitives" } primitives = { package = "substrate-primitives", path = "../primitives" } +session = { package = "substrate-session", path = "../session" } app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" } -substrate-session = { path = "../session" } consensus_common = { package = "substrate-consensus-common", path = "../../core/consensus/common" } network = { package = "substrate-network", path = "../../core/network" } client = { package = "substrate-client", path = "../../core/client" } diff --git a/substrate/core/service/src/components.rs b/substrate/core/service/src/components.rs index d2b6131ed0..2ca99e0b31 100644 --- a/substrate/core/service/src/components.rs +++ b/substrate/core/service/src/components.rs @@ -156,13 +156,13 @@ pub trait InitialSessionKeys { impl InitialSessionKeys for C where ComponentClient: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: substrate_session::SessionKeys>, + as ProvideRuntimeApi>::Api: session::SessionKeys>, { fn generate_intial_session_keys( client: Arc>, seeds: Vec, ) -> error::Result<()> { - substrate_session::generate_initial_session_keys(client, seeds).map_err(Into::into) + session::generate_initial_session_keys(client, seeds).map_err(Into::into) } } @@ -180,7 +180,8 @@ pub trait StartRPC { impl StartRPC for C where ComponentClient: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: runtime_api::Metadata>, + as ProvideRuntimeApi>::Api: + runtime_api::Metadata> + session::SessionKeys>, { fn start_rpc( client: Arc>, @@ -193,7 +194,12 @@ impl StartRPC for C where let subscriptions = rpc::apis::Subscriptions::new(task_executor.clone()); let chain = rpc::apis::chain::Chain::new(client.clone(), subscriptions.clone()); let state = rpc::apis::state::State::new(client.clone(), subscriptions.clone()); - let author = rpc::apis::author::Author::new(client, transaction_pool, subscriptions, keystore); + let author = rpc::apis::author::Author::new( + client, + transaction_pool, + subscriptions, + keystore, + ); let system = rpc::apis::system::System::new(rpc_system_info, system_send_back); rpc::rpc_handler::, ComponentExHash, _, _, _, _>( state, diff --git a/substrate/core/test-runtime/Cargo.toml b/substrate/core/test-runtime/Cargo.toml index 98d110a574..13186056ce 100644 --- a/substrate/core/test-runtime/Cargo.toml +++ b/substrate/core/test-runtime/Cargo.toml @@ -19,6 +19,7 @@ babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../ rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } sr-primitives = { path = "../sr-primitives", default-features = false } +session = { package = "substrate-session", path = "../session", default-features = false } runtime_version = { package = "sr-version", path = "../sr-version", default-features = false } runtime_support = { package = "srml-support", path = "../../srml/support", default-features = false } substrate-trie = { path = "../trie", default-features = false } @@ -69,4 +70,5 @@ std = [ "srml-timestamp/std", "srml-system/std", "app-crypto/std", + "session/std", ] diff --git a/substrate/core/test-runtime/src/lib.rs b/substrate/core/test-runtime/src/lib.rs index e2c7c27876..54c922c216 100644 --- a/substrate/core/test-runtime/src/lib.rs +++ b/substrate/core/test-runtime/src/lib.rs @@ -37,15 +37,15 @@ use substrate_client::{ impl_runtime_apis, }; use sr_primitives::{ - ApplyResult, create_runtime_str, Perbill, + ApplyResult, create_runtime_str, Perbill, impl_opaque_keys, transaction_validity::{TransactionValidity, ValidTransaction}, traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, - GetNodeBlockType, GetRuntimeBlockType, Verify, IdentityLookup + GetNodeBlockType, GetRuntimeBlockType, Verify, IdentityLookup, }, }; use runtime_version::RuntimeVersion; -pub use primitives::hash::H256; +pub use primitives::{hash::H256, crypto::key_types}; #[cfg(any(feature = "std", test))] use runtime_version::NativeVersion; use runtime_support::{impl_outer_origin, parameter_types}; @@ -434,6 +434,15 @@ fn code_using_trie() -> u64 { } else { 103 } } +impl_opaque_keys! { + pub struct SessionKeys { + #[id(key_types::ED25519)] + pub ed25519: ed25519::AppPublic, + #[id(key_types::SR25519)] + pub sr25519: sr25519::AppPublic, + } +} + #[cfg(not(feature = "std"))] /// Mutable static variables should be always observed to have /// the initialized value at the start of a runtime call. @@ -612,6 +621,12 @@ cfg_if! { runtime_io::submit_transaction(&ex).unwrap(); } } + + impl session::SessionKeys for Runtime { + fn generate_session_keys(_: Option>) -> Vec { + SessionKeys::generate(None) + } + } } } else { impl_runtime_apis! { @@ -816,6 +831,12 @@ cfg_if! { runtime_io::submit_transaction(&ex).unwrap() } } + + impl session::SessionKeys for Runtime { + fn generate_session_keys(_: Option>) -> Vec { + SessionKeys::generate(None) + } + } } } } diff --git a/substrate/node/primitives/Cargo.toml b/substrate/node/primitives/Cargo.toml index 05fb231205..654347273f 100644 --- a/substrate/node/primitives/Cargo.toml +++ b/substrate/node/primitives/Cargo.toml @@ -13,7 +13,7 @@ sr-primitives = { path = "../../core/sr-primitives", default-features = false } [dev-dependencies] substrate-serializer = { path = "../../core/serializer" } -pretty_assertions = "0.5" +pretty_assertions = "0.6.1" [features] default = ["std"]