diff --git a/Cargo.lock b/Cargo.lock index 7f8f7bd555f2d..3537571009c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3459,6 +3459,7 @@ dependencies = [ "srml-session 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-timestamp 2.0.0", "substrate-finality-grandpa-primitives 2.0.0", "substrate-primitives 2.0.0", ] diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 18c65d011e657..4b7b2ac83300e 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -22,7 +22,6 @@ use crate::codec::{Codec, Encode, Decode}; use crate::traits::{self, Checkable, Applyable, BlakeTwo256, Convert}; use crate::generic::DigestItem as GenDigestItem; pub use substrate_primitives::H256; -use substrate_primitives::U256; use substrate_primitives::sr25519::{Public as AuthorityId, Signature as AuthoritySignature}; /// Authority Id @@ -31,7 +30,7 @@ use substrate_primitives::sr25519::{Public as AuthorityId, Signature as Authorit pub struct UintAuthorityId(pub u64); impl Into for UintAuthorityId { fn into(self) -> AuthorityId { - let bytes: [u8; 32] = U256::from(self.0).into(); + let bytes: [u8; 32] = H256::from_low_u64_be(self.0).into(); AuthorityId(bytes) } } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 336636fef884b..ae4812126907a 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -81,7 +81,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { GenesisConfig { consensus: Some(ConsensusConfig { code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), // FIXME change once we have #1252 - authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), + authorities: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect(), }), system: None, balances: Some(BalancesConfig { @@ -104,7 +104,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { session: Some(SessionConfig { validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), session_length: 5 * MINUTES, - keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::>(), + keys: initial_authorities.iter().map(|x| (x.1.clone(), (x.1.clone(), x.2.clone()))).collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -270,7 +270,7 @@ pub fn testnet_genesis( GenesisConfig { consensus: Some(ConsensusConfig { code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), - authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), + authorities: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect(), }), system: None, indices: Some(IndicesConfig { @@ -288,7 +288,7 @@ pub fn testnet_genesis( session: Some(SessionConfig { validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), session_length: 10, - keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::>(), + keys: initial_authorities.iter().map(|x| (x.1.clone(), (x.1.clone(), x.2.clone()))).collect::>(), }), staking: Some(StakingConfig { current_era: 0, diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d243357fc2e30..93a1ed80df4b9 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -86,6 +86,8 @@ impl Convert for CurrencyToVoteHandler { fn convert(x: u128) -> u128 { x * Self::factor() } } +pub type SessionKey = (AccountId, AuthorityId); + impl system::Trait for Runtime { type Origin = Origin; type Index = Index; @@ -123,13 +125,20 @@ impl balances::Trait for Runtime { impl consensus::Trait for Runtime { type Log = Log; - type SessionKey = AuthorityId; + type SessionKey = SessionKey; // The Aura module handles offline-reports internally // rather than using an explicit report system. type InherentOfflineReport = (); } +pub struct ConvertSessionKeyToAuthorityId; +impl Convert for ConvertSessionKeyToAuthorityId { + fn convert(session_key: SessionKey) -> AuthorityId { + session_key.1 + } +} + impl timestamp::Trait for Runtime { type Moment = u64; type OnTimestampSet = Aura; @@ -198,7 +207,8 @@ impl sudo::Trait for Runtime { } impl grandpa::Trait for Runtime { - type SessionKey = AuthorityId; + type LocalSessionKey = AuthorityId; + type ConvertLocalSessionKey = ConvertSessionKeyToAuthorityId; type Log = Log; type Event = Event; } @@ -208,7 +218,7 @@ impl finality_tracker::Trait for Runtime { } construct_runtime!( - pub enum Runtime with Log(InternalLog: DigestItem) where + pub enum Runtime with Log(InternalLog: DigestItem) where Block = Block, NodeBlock = node_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index 7855019af8a4d..0fd7ecf53911e 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -19,6 +19,7 @@ finality-tracker = { package = "srml-finality-tracker", path = "../finality-trac [dev-dependencies] runtime_io = { package = "sr-io", path = "../../core/sr-io" } +timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } [features] default = ["std"] diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index 5425ace8bb89e..0ea511bc4c2c1 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -43,7 +43,7 @@ use srml_support::storage::unhashed::StorageVec; use primitives::traits::CurrentHeight; use substrate_primitives::ed25519; use system::ensure_signed; -use primitives::traits::MaybeSerializeDebug; +use primitives::traits::{Convert, MaybeSerializeDebug}; use ed25519::Public as AuthorityId; mod mock; @@ -58,7 +58,7 @@ impl StorageVec for AuthorityStorageVec { /// The log type of this crate, projected from module trait type. pub type Log = RawLog< ::BlockNumber, - ::SessionKey, + ::LocalSessionKey, >; /// Logs which can be scanned by GRANDPA for authorities change events. @@ -72,19 +72,19 @@ pub trait GrandpaChangeSignal { /// A logs in this module. #[cfg_attr(feature = "std", derive(Serialize, Debug))] #[derive(Encode, Decode, PartialEq, Eq, Clone)] -pub enum RawLog { +pub enum RawLog { /// Authorities set change has been signaled. Contains the new set of authorities /// and the delay in blocks _to finalize_ before applying. - AuthoritiesChangeSignal(N, Vec<(SessionKey, u64)>), + AuthoritiesChangeSignal(N, Vec<(LocalSessionKey, u64)>), /// A forced authorities set change. Contains in this order: the median last /// finalized block when the change was signaled, the delay in blocks _to import_ /// before applying and the new set of authorities. - ForcedAuthoritiesChangeSignal(N, N, Vec<(SessionKey, u64)>), + ForcedAuthoritiesChangeSignal(N, N, Vec<(LocalSessionKey, u64)>), } -impl RawLog { +impl RawLog { /// Try to cast the log entry as a contained signal. - pub fn as_signal(&self) -> Option<(N, &[(SessionKey, u64)])> { + pub fn as_signal(&self) -> Option<(N, &[(LocalSessionKey, u64)])> { match *self { RawLog::AuthoritiesChangeSignal(ref delay, ref signal) => Some((delay.clone(), signal)), RawLog::ForcedAuthoritiesChangeSignal(_, _, _) => None, @@ -92,7 +92,7 @@ impl RawLog { } /// Try to cast the log entry as a contained forced signal. - pub fn as_forced_signal(&self) -> Option<(N, N, &[(SessionKey, u64)])> { + pub fn as_forced_signal(&self) -> Option<(N, N, &[(LocalSessionKey, u64)])> { match *self { RawLog::ForcedAuthoritiesChangeSignal(ref median, ref delay, ref signal) => Some((median.clone(), delay.clone(), signal)), RawLog::AuthoritiesChangeSignal(_, _) => None, @@ -100,8 +100,8 @@ impl RawLog { } } -impl GrandpaChangeSignal for RawLog - where N: Clone, SessionKey: Clone + Into, +impl GrandpaChangeSignal for RawLog + where N: Clone, LocalSessionKey: Clone + Into, { fn as_signal(&self) -> Option> { RawLog::as_signal(self).map(|(delay, next_authorities)| ScheduledChange { @@ -124,12 +124,15 @@ impl GrandpaChangeSignal for RawLog } } -pub trait Trait: system::Trait { +pub trait Trait: session::Trait + system::Trait { /// Type for all log entries of this module. type Log: From> + Into>; /// The session key type used by authorities. - type SessionKey: Parameter + Default + MaybeSerializeDebug; + type LocalSessionKey: Parameter + Default + MaybeSerializeDebug; + + // Convert to LocalSessionKey. + type ConvertLocalSessionKey: Convert; /// The event type of this module. type Event: From> + Into<::Event>; @@ -139,30 +142,30 @@ pub trait Trait: system::Trait { // TODO: remove shim // https://github.com/paritytech/substrate/issues/1614 #[derive(Encode, Decode)] -pub struct OldStoredPendingChange { +pub struct OldStoredPendingChange { /// The block number this was scheduled at. pub scheduled_at: N, /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: Vec<(SessionKey, u64)>, + pub next_authorities: Vec<(LocalSessionKey, u64)>, } /// A stored pending change. #[derive(Encode)] -pub struct StoredPendingChange { +pub struct StoredPendingChange { /// The block number this was scheduled at. pub scheduled_at: N, /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: Vec<(SessionKey, u64)>, + pub next_authorities: Vec<(LocalSessionKey, u64)>, /// If defined it means the change was forced and the given block number /// indicates the median last finalized block when the change was signaled. pub forced: Option, } -impl Decode for StoredPendingChange { +impl Decode for StoredPendingChange { fn decode(value: &mut I) -> Option { let old = OldStoredPendingChange::decode(value)?; let forced = >::decode(value).unwrap_or(None); @@ -177,21 +180,21 @@ impl Decode for StoredPendingChange where ::SessionKey { + pub enum Event where ::LocalSessionKey { /// New authority set has been applied. - NewAuthorities(Vec<(SessionKey, u64)>), + NewAuthorities(Vec<(LocalSessionKey, u64)>), } ); decl_storage! { trait Store for Module as GrandpaFinality { // Pending change: (signaled at, scheduled change). - PendingChange get(pending_change): Option>; + PendingChange get(pending_change): Option>; // next block number where we can force a change. NextForced get(next_forced): Option; } add_extra_genesis { - config(authorities): Vec<(T::SessionKey, u64)>; + config(authorities): Vec<(T::LocalSessionKey, u64)>; build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { use codec::{Encode, KeyedVec}; @@ -242,7 +245,7 @@ decl_module! { Self::deposit_event( RawEvent::NewAuthorities(pending_change.next_authorities.clone()) ); - >::set_items(pending_change.next_authorities); + >::set_items(pending_change.next_authorities); >::kill(); } } @@ -252,8 +255,8 @@ decl_module! { impl Module { /// Get the current set of authorities, along with their respective weights. - pub fn grandpa_authorities() -> Vec<(T::SessionKey, u64)> { - >::items() + pub fn grandpa_authorities() -> Vec<(T::LocalSessionKey, u64)> { + >::items() } /// Schedule a change in the authorities. @@ -271,7 +274,7 @@ impl Module { /// No change should be signaled while any change is pending. Returns /// an error if a change is already pending. pub fn schedule_change( - next_authorities: Vec<(T::SessionKey, u64)>, + next_authorities: Vec<(T::LocalSessionKey, u64)>, in_blocks: T::BlockNumber, forced: Option, ) -> Result { @@ -307,7 +310,7 @@ impl Module { } } -impl Module where AuthorityId: core::convert::From<::SessionKey> { +impl Module where AuthorityId: core::convert::From<::LocalSessionKey> { /// See if the digest contains any standard scheduled change. pub fn scrape_digest_change(log: &Log) -> Option> @@ -337,17 +340,15 @@ impl Default for SyncedAuthorities { } } -impl session::OnSessionChange for SyncedAuthorities where - T: Trait + consensus::Trait::SessionKey>, - ::Log: From::SessionKey>> +impl session::OnSessionChange for SyncedAuthorities where { fn on_session_change(_: X, _: bool) { use primitives::traits::Zero; let next_authorities = >::authorities() .into_iter() - .map(|key| (key, 1)) // evenly-weighted. - .collect::::SessionKey, u64)>>(); + .map(|key| (T::ConvertLocalSessionKey::convert(key), 1)) // evenly-weighted. + .collect::::LocalSessionKey, u64)>>(); // instant changes let last_authorities = >::grandpa_authorities(); @@ -357,9 +358,7 @@ impl session::OnSessionChange for SyncedAuthorities where } } -impl finality_tracker::OnFinalizationStalled for SyncedAuthorities where - T: Trait + consensus::Trait::SessionKey>, - ::Log: From::SessionKey>>, +impl finality_tracker::OnFinalizationStalled for SyncedAuthorities where T: finality_tracker::Trait, { fn on_stalled(further_wait: T::BlockNumber) { @@ -369,8 +368,8 @@ impl finality_tracker::OnFinalizationStalled for SyncedAuthor let next_authorities = >::authorities() .into_iter() - .map(|key| (key, 1)) // evenly-weighted. - .collect::::SessionKey, u64)>>(); + .map(|key| (T::ConvertLocalSessionKey::convert(key), 1)) // evenly-weighted. + .collect::::LocalSessionKey, u64)>>(); let median = >::median(); diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 4405604ab19c0..e6b93aa05c467 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -39,9 +39,26 @@ impl From> for DigestItem { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug, Decode, Encode)] pub struct Test; +impl timestamp::Trait for Test { + type Moment = u64; + type OnTimestampSet = (); +} +impl consensus::Trait for Test { + type Log = DigestItem; + type SessionKey = substrate_primitives::sr25519::Public; + type InherentOfflineReport = (); +} +impl session::Trait for Test { + type ConvertAccountIdToSessionKey = (); + type OnSessionChange = (); + type OnDisable = (); + type CheckRotateSession = session::AuraCheckRotateSession; + type Event = TestEvent; +} impl Trait for Test { type Log = DigestItem; - type SessionKey = u64; + type LocalSessionKey = u64; + type ConvertLocalSessionKey = (); type Event = TestEvent; } impl system::Trait for Test { @@ -65,6 +82,7 @@ mod grandpa { impl_outer_event!{ pub enum TestEvent for Test { grandpa, + session, } } diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index d13795e4bb09c..1f5f965ba4056 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -329,13 +329,15 @@ impl OnFreeBalanceZero for Module { #[cfg(test)] mod tests { use super::*; + use serde::{Deserialize, Serialize}; use std::cell::RefCell; use srml_support::{impl_outer_origin, assert_ok}; use runtime_io::with_externalities; - use substrate_primitives::{H256, Blake2Hasher}; + use substrate_primitives::{H256, U256, Blake2Hasher, ed25519, sr25519}; + use parity_codec::{Decode, Encode}; use primitives::BuildStorage; use primitives::traits::{BlakeTwo256, IdentityLookup}; - use primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, ConvertUintAuthorityId}; + use primitives::testing::{Digest, DigestItem, Header}; impl_outer_origin!{ pub enum Origin for Test {} @@ -356,9 +358,40 @@ mod tests { pub struct Test; impl consensus::Trait for Test { type Log = DigestItem; - type SessionKey = UintAuthorityId; + type SessionKey = TestSessionKey; type InherentOfflineReport = (); } + + #[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode, Serialize, Deserialize)] + pub struct TestSessionKey(u64, u64); + + impl From for sr25519::Public { + fn from(key: TestSessionKey) -> Self { + let bytes: [u8; 32] = H256::from_low_u64_be(key.0).into(); + Self(bytes) + } + } + + impl From for ed25519::Public { + fn from(key: TestSessionKey) -> Self { + let bytes: [u8; 32] = H256::from_low_u64_be(key.1).into(); + Self(bytes) + } + } + + pub struct ConvertU64ToTestSessionKey; + impl Convert> for ConvertU64ToTestSessionKey { + fn convert(a: u64) -> Option { + Some(TestSessionKey::from(a)) + } + } + + impl From for TestSessionKey { + fn from(id: u64) -> Self { + Self(id, id + 100) + } + } + impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -377,7 +410,7 @@ mod tests { type OnTimestampSet = (); } impl Trait for Test { - type ConvertAccountIdToSessionKey = ConvertUintAuthorityId; + type ConvertAccountIdToSessionKey = ConvertU64ToTestSessionKey; type OnSessionChange = TestOnSessionChange; type Event = (); } @@ -390,7 +423,7 @@ mod tests { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; t.extend(consensus::GenesisConfig::{ code: vec![], - authorities: NEXT_VALIDATORS.with(|l| l.borrow().iter().cloned().map(UintAuthorityId).collect()), + authorities: NEXT_VALIDATORS.with(|l| l.borrow().iter().cloned().map(TestSessionKey::from).collect()), }.build_storage().unwrap().0); t.extend(timestamp::GenesisConfig::{ minimum_period: 5, @@ -403,10 +436,14 @@ mod tests { runtime_io::TestExternalities::new(t) } + fn account_ids_to_session_keys(account_ids: Vec) -> Vec { + account_ids.into_iter().map(TestSessionKey::from).collect() + } + #[test] fn simple_setup_should_work() { with_externalities(&mut new_test_ext(), || { - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); assert_eq!(Session::length(), 2); assert_eq!(Session::validators(), vec![1, 2, 3]); }); @@ -419,19 +456,19 @@ mod tests { assert_ok!(Session::force_new_session(false)); Session::check_rotate_session(1); assert_eq!(Session::validators(), vec![1, 2]); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2])); NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 4]); assert_ok!(Session::force_new_session(false)); Session::check_rotate_session(2); assert_eq!(Session::validators(), vec![1, 2, 4]); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(4)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 4])); NEXT_VALIDATORS.with(|v| *v.borrow_mut() = vec![1, 2, 3]); assert_ok!(Session::force_new_session(false)); Session::check_rotate_session(3); assert_eq!(Session::validators(), vec![1, 2, 3]); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); }); } @@ -525,25 +562,25 @@ mod tests { // Block 1: No change System::set_block_number(1); Session::check_rotate_session(1); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); // Block 2: Session rollover, but no change. System::set_block_number(2); Session::check_rotate_session(2); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); // Block 3: Set new key for validator 2; no visible change. System::set_block_number(3); - assert_ok!(Session::set_key(Origin::signed(2), UintAuthorityId(5))); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_ok!(Session::set_key(Origin::signed(2), TestSessionKey::from(5))); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); Session::check_rotate_session(3); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 2, 3])); // Block 4: Session rollover, authority 2 changes. System::set_block_number(4); Session::check_rotate_session(4); - assert_eq!(Consensus::authorities(), vec![UintAuthorityId(1), UintAuthorityId(5), UintAuthorityId(3)]); + assert_eq!(Consensus::authorities(), account_ids_to_session_keys(vec![1, 5, 3])); }); } }