From aadeb9ca35ae324641fe711db33775533905134e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Jul 2019 10:29:28 +0800 Subject: [PATCH 01/80] Add Call type to extensible transactions. Cleanup some naming --- .../src/generic/checked_extrinsic.rs | 11 +++-- .../src/generic/unchecked_extrinsic.rs | 1 + core/sr-primitives/src/testing.rs | 6 +-- core/sr-primitives/src/traits.rs | 42 ++++++++++++++----- node/runtime/src/lib.rs | 1 + srml/balances/src/lib.rs | 3 ++ srml/contracts/src/exec.rs | 2 +- srml/contracts/src/lib.rs | 6 +-- srml/executive/src/lib.rs | 3 ++ srml/im-online/src/lib.rs | 2 +- srml/session/src/historical.rs | 6 +-- srml/session/src/lib.rs | 11 +++-- srml/support/src/storage/hashed/generator.rs | 17 ++++++++ srml/support/src/storage/mod.rs | 7 ++++ srml/system/src/lib.rs | 11 +++++ 15 files changed, 97 insertions(+), 32 deletions(-) diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 04ccd1162c6c6..44a0758267468 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -45,11 +45,10 @@ for where AccountId: Member + MaybeDisplay, Call: Member + Dispatchable, - Extra: SignedExtension, + Extra: SignedExtension, Origin: From>, { type AccountId = AccountId; - type Call = Call; fn sender(&self) -> Option<&Self::AccountId> { @@ -61,9 +60,9 @@ where len: usize, ) -> TransactionValidity { if let Some((ref id, ref extra)) = self.signed { - Extra::validate(extra, id, info, len).into() + Extra::validate(extra, id, &self.function, info, len).into() } else { - match Extra::validate_unsigned(info, len) { + match Extra::validate_unsigned(&self.function, info, len) { Ok(extra) => match U::validate_unsigned(&self.function) { TransactionValidity::Valid(v) => TransactionValidity::Valid(v.combine_with(extra)), @@ -79,10 +78,10 @@ where len: usize, ) -> Result { let maybe_who = if let Some((id, extra)) = self.signed { - Extra::pre_dispatch(extra, &id, info, len)?; + Extra::pre_dispatch(extra, &id, &self.function, info, len)?; Some(id) } else { - Extra::pre_dispatch_unsigned(info, len)?; + Extra::pre_dispatch_unsigned(&self.function, info, len)?; None }; Ok(self.function.dispatch(Origin::from(maybe_who))) diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 092af6e6f3cdd..6fd152d05ce54 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -243,6 +243,7 @@ mod tests { struct TestExtra; impl SignedExtension for TestExtra { type AccountId = u64; + type Call = (); type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 6ef7844fc9b3b..b12c7258c2638 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -245,7 +245,7 @@ impl traits::Extrinsic for TestXt impl Applyable for TestXt where Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, - Extra: SignedExtension, + Extra: SignedExtension, Origin: From> { type AccountId = u64; @@ -268,10 +268,10 @@ impl Applyable for TestXt where len: usize, ) -> Result { let maybe_who = if let Some((who, extra)) = self.0 { - Extra::pre_dispatch(extra, &who, info, len)?; + Extra::pre_dispatch(extra, &who, &self.1, info, len)?; Some(who) } else { - Extra::pre_dispatch_unsigned(info, len)?; + Extra::pre_dispatch_unsigned(&self.1, info, len)?; None }; Ok(self.1.dispatch(maybe_who.into())) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 670f8d181d1b5..06a7a98ab121a 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -788,8 +788,8 @@ pub enum DispatchError { /// General error to do with the transaction's proofs (e.g. signature). BadProof, -/* /// General error to do with actually executing the dispatched logic. - User(&'static str),*/ + /// General error to do with a limit being reached that may be reset on the next block. + BlockExhausted, } impl From for i8 { @@ -802,6 +802,7 @@ impl From for i8 { DispatchError::Stale => -68, DispatchError::Future => -69, DispatchError::BadProof => -70, + DispatchError::BlockExhausted => -71, } } } @@ -830,6 +831,8 @@ pub trait SignedExtension: { /// The type which encodes the sender identity. type AccountId; + /// The type which encodes the call to be dispatched. + type Call; /// Any additional data that will go into the signed payload. This may be created dynamically /// from the transaction using the `additional_signed` function. @@ -839,35 +842,45 @@ pub trait SignedExtension: /// also perform any pre-signature-verification checks and return an error if needed. fn additional_signed(&self) -> Result; - /// Validate a signed transaction for the transaction queue. + /// Validate a signed transaction for the transaction queue. fn validate( &self, _who: &Self::AccountId, + _call: &Self::Call, _info: DispatchInfo, _len: usize, - ) -> Result { Ok(Default::default()) } + ) -> Result { + Ok(Default::default()) + } /// Do any pre-flight stuff for a signed transaction. fn pre_dispatch( self, who: &Self::AccountId, + call: &Self::Call, info: DispatchInfo, len: usize, - ) -> Result<(), DispatchError> { self.validate(who, info, len).map(|_| ()) } + ) -> Result<(), DispatchError> { + self.validate(who, call, info, len).map(|_| ()) + } /// Validate an unsigned transaction for the transaction queue. Normally the default /// implementation is fine since `ValidateUnsigned` is a better way of recognising and /// validating unsigned transactions. fn validate_unsigned( + _call: &Self::Call, _info: DispatchInfo, _len: usize, ) -> Result { Ok(Default::default()) } /// Do any pre-flight stuff for a unsigned transaction. fn pre_dispatch_unsigned( + call: &Self::Call, info: DispatchInfo, len: usize, - ) -> Result<(), DispatchError> { Self::validate_unsigned(info, len).map(|_| ()) } + ) -> Result<(), DispatchError> { + Self::validate_unsigned(call, info, len).map(|_| ()) + } } macro_rules! tuple_impl_indexed { @@ -877,9 +890,11 @@ macro_rules! tuple_impl_indexed { ([$($direct:ident)+] ; [$($index:tt,)+]) => { impl< AccountId, - $($direct: SignedExtension),+ + Call, + $($direct: SignedExtension),+ > SignedExtension for ($($direct),+,) { type AccountId = AccountId; + type Call = Call; type AdditionalSigned = ($($direct::AdditionalSigned,)+); fn additional_signed(&self) -> Result { Ok(( $(self.$index.additional_signed()?,)+ )) @@ -887,33 +902,37 @@ macro_rules! tuple_impl_indexed { fn validate( &self, who: &Self::AccountId, + call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result { - let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, info, len)?),+]; + let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, call, info, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch( self, who: &Self::AccountId, + call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result<(), DispatchError> { - $(self.$index.pre_dispatch(who, info, len)?;)+ + $(self.$index.pre_dispatch(who, call, info, len)?;)+ Ok(()) } fn validate_unsigned( + call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result { - let aggregator = vec![$($direct::validate_unsigned(info, len)?),+]; + let aggregator = vec![$($direct::validate_unsigned(call, info, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch_unsigned( + call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result<(), DispatchError> { - $($direct::pre_dispatch_unsigned(info, len)?;)+ + $($direct::pre_dispatch_unsigned(call, info, len)?;)+ Ok(()) } } @@ -941,6 +960,7 @@ tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 impl SignedExtension for () { type AccountId = u64; type AdditionalSigned = (); + type Call = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 02d2a91851fa1..bb86d9721dbee 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -111,6 +111,7 @@ parameter_types! { impl system::Trait for Runtime { type Origin = Origin; + type Call = Call; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index cde3fa2d16cfb..573480123e9e0 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -763,6 +763,7 @@ impl, I: Instance> PartialEq for ElevatedTrait { impl, I: Instance> Eq for ElevatedTrait {} impl, I: Instance> system::Trait for ElevatedTrait { type Origin = T::Origin; + type Call = T::Call; type Index = T::Index; type BlockNumber = T::BlockNumber; type Hash = T::Hash; @@ -1213,12 +1214,14 @@ impl, I: Instance> rstd::fmt::Debug for TakeFees { impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } fn validate( &self, who: &Self::AccountId, + _call: &Self::Call, info: DispatchInfo, len: usize, ) -> rstd::result::Result { diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 4a83e606ac86b..d923c72e64eb9 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -260,7 +260,7 @@ pub struct ExecutionContext<'a, T: Trait + 'a, V, L> { pub overlay: OverlayAccountDb<'a, T>, pub depth: usize, pub events: Vec>, - pub calls: Vec<(T::AccountId, T::Call)>, + pub calls: Vec<(T::AccountId, ::Call)>, pub config: &'a Config, pub vm: &'a V, pub loader: &'a L, diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index f38010a3557a9..129ac693cc83e 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -332,7 +332,7 @@ pub trait Trait: timestamp::Trait { /// /// It is recommended (though not required) for this function to return a fee that would be taken /// by the Executive module for regular dispatch. - type ComputeDispatchFee: ComputeDispatchFee>; + type ComputeDispatchFee: ComputeDispatchFee<::Call, BalanceOf>; /// trie id generator type TrieIdGenerator: TrieIdGenerator; @@ -426,8 +426,8 @@ where /// The default dispatch fee computor computes the fee in the same way that /// the implementation of `MakePayment` for the Balances module does. pub struct DefaultDispatchFeeComputor(PhantomData); -impl ComputeDispatchFee> for DefaultDispatchFeeComputor { - fn compute_dispatch_fee(call: &T::Call) -> BalanceOf { +impl ComputeDispatchFee<::Call, BalanceOf> for DefaultDispatchFeeComputor { + fn compute_dispatch_fee(call: &::Call) -> BalanceOf { let encoded_len = call.using_encoded(|encoded| encoded.len() as u32); let base_fee = T::TransactionBaseFee::get(); let byte_fee = T::TransactionByteFee::get(); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 9ae794d698b55..572ba4e2600be 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -114,6 +114,9 @@ mod internal { DispatchError::Stale => ApplyError::Stale, DispatchError::Future => ApplyError::Future, DispatchError::BadProof => ApplyError::BadSignature(""), + DispatchError::BlockExhausted => ApplyError::Future, + // ^^^ TODO: consider a better way of expressing this. does ::Future attempt to + // reschedule at the beginning of the next block? } } } diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 7898fea8eb733..b57024ac1068d 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -148,7 +148,7 @@ pub trait Trait: system::Trait + session::Trait { /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. - type UncheckedExtrinsic: ExtrinsicT + Encode + Decode; + type UncheckedExtrinsic: ExtrinsicT::Call> + Encode + Decode; /// The identifier type for an authority. type AuthorityId: Member + Parameter + Default + TypedKey + Decode + Encode + AsRef<[u8]>; diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index c6755c3ba3592..0f5d5884985ab 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -100,9 +100,9 @@ impl Module { /// Specialization of the crate-level `OnSessionEnding` which returns the old /// set of full identification when changing the validator set. pub trait OnSessionEnding: crate::OnSessionEnding { - /// Returns the set of new validators, if any, along with the old validators - /// and their full identifications. - fn on_session_ending(ending: SessionIndex, applied_at: SessionIndex) + /// If there was a validator set change, its returns the set of new validators along with the + /// old validators and their full identifications. + fn on_session_ending(ending: SessionIndex, will_apply_at: SessionIndex) -> Option<(Vec, Vec<(ValidatorId, FullIdentification)>)>; } diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 8589f92006d88..7bdc1f96a0fa2 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -172,10 +172,13 @@ pub trait OnSessionEnding { /// Handle the fact that the session is ending, and optionally provide the new validator set. /// /// `ending_index` is the index of the currently ending session. - /// The returned validator set, if any, will not be applied until `next_index`. - /// `next_index` is guaranteed to be at least `ending_index + 1`, since session indices don't - /// repeat. - fn on_session_ending(ending_index: SessionIndex, next_index: SessionIndex) -> Option>; + /// The returned validator set, if any, will not be applied until `will_apply_at`. + /// `will_apply_at` is guaranteed to be at least `ending_index + 1`, since session indices don't + /// repeat, but it could be some time after in case we are staging authority set changes. + fn on_session_ending( + ending_index: SessionIndex, + will_apply_at: SessionIndex + ) -> Option>; } impl OnSessionEnding for () { diff --git a/srml/support/src/storage/hashed/generator.rs b/srml/support/src/storage/hashed/generator.rs index 4d367fb2a870a..6b4f5829a3f74 100644 --- a/srml/support/src/storage/hashed/generator.rs +++ b/srml/support/src/storage/hashed/generator.rs @@ -238,6 +238,23 @@ pub trait StorageMap { /// Take the value under a key. fn take>(key: &K, storage: &mut S) -> Self::Query; + /// Swap the values of two keys. + fn swap>(key1: &K, key2: &K, storage: &mut S) { + let k1 = Self::key_for(key1); + let k2 = Self::key_for(key2); + let v1 = storage.get_raw(&k1[..]); + if let Some(val) = storage.get_raw(&k2[..]) { + storage.put_raw(&k1[..], &val[..]); + } else { + storage.kill(&k1[..]) + } + if let Some(val) = v1 { + storage.put_raw(&k2[..], &val[..]); + } else { + storage.kill(&k2[..]) + } + } + /// Store a value to be associated with the given key from the map. fn insert>(key: &K, val: &V, storage: &mut S) { storage.put(&Self::key_for(key)[..], val); diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 446855b55c187..33ad689a8c028 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -220,6 +220,9 @@ pub trait StorageMap { /// Load the value associated with the given key from the map. fn get>(key: KeyArg) -> Self::Query; + /// Swap the values of two keys. + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2); + /// Store a value to be associated with the given key from the map. fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg); @@ -256,6 +259,10 @@ impl StorageMap for U where U: hashed::generator::S U::get(key.borrow(), &RuntimeStorage) } + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2) { + U::swap(key1.borrow(), key2.borrow(), &mut RuntimeStorage) + } + fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg) { U::insert(key.borrow(), val.borrow(), &mut RuntimeStorage) } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index e98c53bf1d533..16dbb3a6bf5a2 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -151,6 +151,9 @@ pub trait Trait: 'static + Eq + Clone { /// The aggregated `Origin` type used by dispatchable calls. type Origin: Into, Self::Origin>> + From>; + /// The aggregated `Call` type. + type Call; + /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender /// account. type Index: @@ -869,6 +872,7 @@ impl CheckWeight { impl SignedExtension for CheckWeight { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } @@ -876,6 +880,7 @@ impl SignedExtension for CheckWeight { fn pre_dispatch( self, _who: &Self::AccountId, + _call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result<(), DispatchError> { @@ -889,6 +894,7 @@ impl SignedExtension for CheckWeight { fn validate( &self, _who: &Self::AccountId, + _call: &Self::Call, info: DispatchInfo, len: usize, ) -> Result { @@ -929,6 +935,7 @@ impl rstd::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } @@ -936,6 +943,7 @@ impl SignedExtension for CheckNonce { fn pre_dispatch( self, who: &Self::AccountId, + _call: &Self::Call, _info: DispatchInfo, _len: usize, ) -> Result<(), DispatchError> { @@ -952,6 +960,7 @@ impl SignedExtension for CheckNonce { fn validate( &self, who: &Self::AccountId, + _call: &Self::Call, info: DispatchInfo, _len: usize, ) -> Result { @@ -999,6 +1008,7 @@ impl rstd::fmt::Debug for CheckEra { impl SignedExtension for CheckEra { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = T::Hash; fn additional_signed(&self) -> Result { let current_u64 = >::block_number().saturated_into::(); @@ -1062,6 +1072,7 @@ mod tests { impl Trait for Test { type Origin = Origin; + type Call = (); type Index = u64; type BlockNumber = u64; type Hash = H256; From ad9af9e8cdc7c0a26afa4aae07b251f325a9f0ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Jul 2019 10:54:44 +0800 Subject: [PATCH 02/80] Merge Resource and BlockExhausted into just Exhausted --- core/sr-primitives/src/traits.rs | 6 +----- node/runtime/src/lib.rs | 2 +- srml/executive/src/lib.rs | 2 +- srml/system/src/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 06a7a98ab121a..c5721f5815ccc 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -787,22 +787,18 @@ pub enum DispatchError { /// General error to do with the transaction's proofs (e.g. signature). BadProof, - - /// General error to do with a limit being reached that may be reset on the next block. - BlockExhausted, } impl From for i8 { fn from(e: DispatchError) -> i8 { match e { DispatchError::Payment => -64, - DispatchError::Resource => -65, + DispatchError::Exhausted => -65, DispatchError::NoPermission => -66, DispatchError::BadState => -67, DispatchError::Stale => -68, DispatchError::Future => -69, DispatchError::BadProof => -70, - DispatchError::BlockExhausted => -71, } } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index bb86d9721dbee..8d644af47df4e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -187,7 +187,7 @@ impl authorship::Trait for Runtime { type EventHandler = (); } -type SessionHandlers = (Grandpa, Babe, ImOnline); +type SessionHandlers = (Grandpa, Babe); impl_opaque_keys! { pub struct SessionKeys { diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 572ba4e2600be..083d820ebf7e0 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -108,7 +108,7 @@ mod internal { fn from(d: DispatchError) -> Self { match d { DispatchError::Payment => ApplyError::CantPay, - DispatchError::Resource => ApplyError::FullBlock, + DispatchError::Exhausted => ApplyError::FullBlock, DispatchError::NoPermission => ApplyError::CantPay, DispatchError::BadState => ApplyError::CantPay, DispatchError::Stale => ApplyError::Stale, diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 16dbb3a6bf5a2..1a69916f3a96a 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -835,7 +835,7 @@ impl CheckWeight { let added_weight = info.weight.min(limit); let next_weight = current_weight.saturating_add(added_weight); if next_weight > limit { - return Err(DispatchError::Resource) + return Err(DispatchError::Exhausted) } Ok(next_weight) } @@ -850,7 +850,7 @@ impl CheckWeight { let added_len = len as u32; let next_len = current_len.saturating_add(added_len); if next_len > limit { - return Err(DispatchError::Resource) + return Err(DispatchError::Exhausted) } Ok(next_len) } From 38a488f7c0a49fab3f5380152a74b87d57d6522b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Jul 2019 11:08:07 +0800 Subject: [PATCH 03/80] Fix --- srml/executive/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 083d820ebf7e0..6bf2a19f1d888 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -114,9 +114,6 @@ mod internal { DispatchError::Stale => ApplyError::Stale, DispatchError::Future => ApplyError::Future, DispatchError::BadProof => ApplyError::BadSignature(""), - DispatchError::BlockExhausted => ApplyError::Future, - // ^^^ TODO: consider a better way of expressing this. does ::Future attempt to - // reschedule at the beginning of the next block? } } } From 8206086df1a8b05085b44eb1d5f62efa3a09347d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Jul 2019 11:10:28 +0800 Subject: [PATCH 04/80] Another fix --- core/sr-primitives/src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index c5721f5815ccc..7b7d6a5a27e67 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -771,7 +771,7 @@ pub enum DispatchError { Payment, /// General error to do with the exhaustion of block resources. - Resource, + Exhausted, /// General error to do with the permissions of the sender. NoPermission, From 10a9447ed1c75533e1858e61a565dfbb9ad18e28 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Jul 2019 11:24:42 +0800 Subject: [PATCH 05/80] Call --- srml/generic-asset/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 8a4e47180c3f1..07ce86a431799 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -1048,6 +1048,7 @@ impl PartialEq for ElevatedTrait { impl Eq for ElevatedTrait {} impl system::Trait for ElevatedTrait { type Origin = T::Origin; + type Call = T::Call; type Index = T::Index; type BlockNumber = T::BlockNumber; type Hash = T::Hash; From e3cc2fe251d656e4ae5d3c7c7696942b46ac5c50 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Jul 2019 11:32:36 +0800 Subject: [PATCH 06/80] Some fixes --- core/test-runtime/src/lib.rs | 7 ++++--- node-template/runtime/src/lib.rs | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index d4c1620863b46..ea5ecfc9ff440 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -138,7 +138,7 @@ impl BlindCheckable for Extrinsic { } impl ExtrinsicT for Extrinsic { - type Call = (); + type Call = Extrinsic; fn is_signed(&self) -> Option { if let Extrinsic::IncludeData(_) = *self { @@ -148,8 +148,8 @@ impl ExtrinsicT for Extrinsic { } } - fn new_unsigned(_call: Self::Call) -> Option { - None + fn new_unsigned(call: Self::Call) -> Option { + Some(call) } } @@ -338,6 +338,7 @@ parameter_types! { impl srml_system::Trait for Runtime { type Origin = Origin; + type Call = Extrinsic; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 7b2201c8efe99..aa9a017add62b 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -104,6 +104,8 @@ parameter_types! { impl system::Trait for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type Call = Call; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. type Lookup = Indices; /// The index type for storing how many extrinsics an account has signed. From 19c1840d9c1647f4bb421d509e3dcdfbe0a28437 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 28 Jul 2019 09:37:16 +0200 Subject: [PATCH 07/80] Fix srml tests. --- core/sr-primitives/src/testing.rs | 2 +- core/sr-primitives/src/traits.rs | 3 ++- srml/balances/src/mock.rs | 4 ++++ srml/balances/src/tests.rs | 11 ++++++---- srml/executive/src/lib.rs | 4 ++-- srml/system/src/lib.rs | 34 ++++++++++++++++--------------- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index b12c7258c2638..19e779a1de7b3 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -251,7 +251,7 @@ impl Applyable for TestXt where type AccountId = u64; type Call = Call; - fn sender(&self) -> Option<&u64> { self.0.as_ref().map(|x| &x.0) } + fn sender(&self) -> Option<&Self::AccountId> { self.0.as_ref().map(|x| &x.0) } /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 7b7d6a5a27e67..67c36738216f9 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -827,6 +827,7 @@ pub trait SignedExtension: { /// The type which encodes the sender identity. type AccountId; + /// The type which encodes the call to be dispatched. type Call; @@ -951,7 +952,7 @@ macro_rules! tuple_impl_indexed { #[allow(non_snake_case)] tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,); -/// Only for base bone testing when you don't care about signed extensions at all.\ +/// Only for bare bone testing when you don't care about signed extensions at all. #[cfg(feature = "std")] impl SignedExtension for () { type AccountId = u64; diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 116515c368f53..ad1feec8080bc 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -86,6 +86,7 @@ impl system::Trait for Runtime { type Index = u64; type BlockNumber = u64; type Hash = H256; + type Call = (); type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; @@ -208,6 +209,9 @@ impl ExtBuilder { pub type System = system::Module; pub type Balances = Module; + +pub const CALL: &::Call = &(); + /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { DispatchInfo { weight: w, ..Default::default() } diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 595be0e1ca603..5543ca31bddab 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight}; +use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight, CALL}; use runtime_io::with_externalities; use srml_support::{ assert_noop, assert_ok, assert_err, @@ -127,6 +127,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, + CALL, info_from_weight(1), 0, ).is_ok()); @@ -140,6 +141,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, + CALL, info_from_weight(1), 0, ).is_ok()); @@ -150,6 +152,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, + CALL, info_from_weight(1), 0, ).is_err()); @@ -757,9 +760,9 @@ fn signed_extension_take_fees_work() { .build(), || { let len = 10; - assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(5), len).is_ok()); + assert!(TakeFees::::from(0).pre_dispatch(&1, CALL, info_from_weight(5), len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); - assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, info_from_weight(3), len).is_ok()); + assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, CALL, info_from_weight(3), len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15); } ); @@ -777,7 +780,7 @@ fn signed_extension_take_fees_is_bounded() { use primitives::weights::Weight; // maximum weight possible - assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(Weight::max_value()), 10).is_ok()); + assert!(TakeFees::::from(0).pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10).is_ok()); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 6bf2a19f1d888..e937c6c24ae55 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -368,8 +368,7 @@ mod tests { use hex_literal::hex; impl_outer_origin! { - pub enum Origin for Runtime { - } + pub enum Origin for Runtime { } } impl_outer_event!{ @@ -390,6 +389,7 @@ mod tests { impl system::Trait for Runtime { type Origin = Origin; type Index = u64; + type Call = Call; type BlockNumber = u64; type Hash = substrate_primitives::H256; type Hashing = BlakeTwo256; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 1a69916f3a96a..54f23aa13eb18 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -1099,6 +1099,8 @@ mod tests { type System = Module; + const CALL: &::Call = &(); + fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::default().build_storage::().unwrap().0.into() } @@ -1252,14 +1254,14 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // stale - assert!(CheckNonce::(0).validate(&1, info, len).is_err()); - assert!(CheckNonce::(0).pre_dispatch(&1, info, len).is_err()); + assert!(CheckNonce::(0).validate(&1, CALL, info, len).is_err()); + assert!(CheckNonce::(0).pre_dispatch(&1, CALL, info, len).is_err()); // correct - assert!(CheckNonce::(1).validate(&1, info, len).is_ok()); - assert!(CheckNonce::(1).pre_dispatch(&1, info, len).is_ok()); + assert!(CheckNonce::(1).validate(&1, CALL, info, len).is_ok()); + assert!(CheckNonce::(1).pre_dispatch(&1, CALL, info, len).is_ok()); // future - assert!(CheckNonce::(5).validate(&1, info, len).is_ok()); - assert!(CheckNonce::(5).pre_dispatch(&1, info, len).is_err()); + assert!(CheckNonce::(5).validate(&1, CALL, info, len).is_ok()); + assert!(CheckNonce::(5).pre_dispatch(&1, CALL, info, len).is_err()); }) } @@ -1280,7 +1282,7 @@ mod tests { let reset_check_weight = |i, f, s| { AllExtrinsicsWeight::put(s); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, i, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, i, len); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; @@ -1297,7 +1299,7 @@ mod tests { let len = 0_usize; assert_eq!(System::all_extrinsics_weight(), 0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, free, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, free, len); assert!(r.is_ok()); assert_eq!(System::all_extrinsics_weight(), 0); }) @@ -1311,7 +1313,7 @@ mod tests { let normal_limit = normal_weight_limit(); assert_eq!(System::all_extrinsics_weight(), 0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, max, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, max, len); assert!(r.is_ok()); assert_eq!(System::all_extrinsics_weight(), normal_limit); }) @@ -1328,15 +1330,15 @@ mod tests { // given almost full block AllExtrinsicsWeight::put(normal_limit); // will not fit. - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, normal, len).is_err()); // will fit. - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, op, len).is_ok()); // likewise for length limit. let len = 100_usize; AllExtrinsicsLen::put(normal_length_limit()); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, normal, len).is_err()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, op, len).is_ok()); }) } @@ -1348,11 +1350,11 @@ mod tests { let len = 0_usize; assert_eq!( - CheckWeight::(PhantomData).validate(&1, normal, len).unwrap().priority, + CheckWeight::(PhantomData).validate(&1, CALL, normal, len).unwrap().priority, 100, ); assert_eq!( - CheckWeight::(PhantomData).validate(&1, op, len).unwrap().priority, + CheckWeight::(PhantomData).validate(&1, CALL, op, len).unwrap().priority, Bounded::max_value(), ); }) @@ -1365,7 +1367,7 @@ mod tests { let normal_limit = normal_weight_limit() as usize; let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::put(0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, tx, s); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, tx, s); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; From 539e481407647f9a8b1d70bca9807cc4447b0571 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 28 Jul 2019 09:53:05 +0200 Subject: [PATCH 08/80] Fix all tests. --- node-template/runtime/src/template.rs | 1 + srml/assets/src/lib.rs | 1 + srml/aura/src/mock.rs | 1 + srml/authorship/src/lib.rs | 1 + srml/balances/src/mock.rs | 2 +- srml/collective/src/lib.rs | 1 + srml/contracts/src/tests.rs | 1 + srml/council/src/lib.rs | 1 + srml/democracy/src/lib.rs | 1 + srml/elections/src/lib.rs | 1 + srml/example/src/lib.rs | 1 + srml/finality-tracker/src/lib.rs | 1 + srml/generic-asset/src/mock.rs | 1 + srml/grandpa/src/mock.rs | 1 + srml/indices/src/mock.rs | 1 + srml/session/src/mock.rs | 1 + srml/staking/src/mock.rs | 1 + srml/system/benches/bench.rs | 1 + srml/timestamp/src/lib.rs | 1 + srml/treasury/src/lib.rs | 1 + 20 files changed, 20 insertions(+), 1 deletion(-) diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index d0c51443904d9..baf157a4fe8ae 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -93,6 +93,7 @@ mod tests { } impl system::Trait for Test { type Origin = Origin; + type Call = (); type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 6dc5f321e41a4..40c1ad5048ef0 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -264,6 +264,7 @@ mod tests { impl system::Trait for Test { type Origin = Origin; type Index = u64; + type Call = (); type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 42f06b564f526..1268a7c0e1132 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -47,6 +47,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 39a3e8000a463..dd55f0393e9d0 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -349,6 +349,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index ad1feec8080bc..097f6ad9f3a04 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -85,8 +85,8 @@ impl system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Hash = H256; type Call = (); + type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index b05b69db77c83..56572c8106ab3 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -413,6 +413,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index db196ef7fe779..81a63582a55e0 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -107,6 +107,7 @@ impl system::Trait for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; + type Call = (); type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 3fc9926942e70..520f68dbd2f53 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -107,6 +107,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 1736d8a97e58c..6a98fc58259c3 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1025,6 +1025,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 8a681fa1458cc..0c119de8de1fc 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1132,6 +1132,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 68b52425ed007..18bfffe9078df 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -533,6 +533,7 @@ mod tests { type Index = u64; type BlockNumber = u64; type Hash = H256; + type Call = (); type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index d59183a166fae..d459c718636aa 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -308,6 +308,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index 9437b06d203cf..1d719613930fa 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -45,6 +45,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 9abb12b15ba23..11e6bb1c50391 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -51,6 +51,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index d1ce8dbe2a087..afd8b8290f2bd 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -75,6 +75,7 @@ impl system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 5c2711e971ac1..b06f763752c00 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -123,6 +123,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 426ba680a9e1e..a8912aff0e461 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -110,6 +110,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = BlockNumber; + type Call = (); type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = AccountId; diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index 071446ea355f7..a3ca9a3467b32 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -63,6 +63,7 @@ impl system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 46ffb6ed22e11..91e9561d6b4c9 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -358,6 +358,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index f86a8271a24ba..7b422d8966e94 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -382,6 +382,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; From 7c09750dd068f175427d0189831edff766fa6ddc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 28 Jul 2019 18:15:08 +0800 Subject: [PATCH 09/80] Refactor crypto so each application of it has its own type. --- core/consensus/babe/primitives/src/digest.rs | 10 +- core/consensus/babe/primitives/src/lib.rs | 13 +- core/consensus/babe/src/lib.rs | 16 +- core/finality-grandpa/primitives/src/lib.rs | 11 +- .../src/communication/gossip.rs | 2 +- .../finality-grandpa/src/communication/mod.rs | 15 +- core/finality-grandpa/src/environment.rs | 4 +- core/finality-grandpa/src/lib.rs | 8 +- core/keystore/src/lib.rs | 75 ++- core/offchain/src/api.rs | 2 + core/primitives/src/crypto.rs | 507 +++++++++++++++++- core/primitives/src/ed25519.rs | 56 +- core/primitives/src/lib.rs | 4 +- core/primitives/src/offchain.rs | 32 +- core/primitives/src/sr25519.rs | 54 +- core/service/src/components.rs | 6 +- core/service/src/lib.rs | 42 +- core/sr-primitives/src/lib.rs | 2 +- core/sr-primitives/src/testing.rs | 25 +- core/sr-primitives/src/traits.rs | 1 - node/cli/src/chain_spec.rs | 39 +- node/cli/src/service.rs | 13 +- node/runtime/src/lib.rs | 8 +- srml/im-online/src/lib.rs | 10 +- srml/session/src/lib.rs | 10 +- 25 files changed, 726 insertions(+), 239 deletions(-) diff --git a/core/consensus/babe/primitives/src/digest.rs b/core/consensus/babe/primitives/src/digest.rs index f39cc962878d5..b1253c7a9b218 100644 --- a/core/consensus/babe/primitives/src/digest.rs +++ b/core/consensus/babe/primitives/src/digest.rs @@ -17,7 +17,7 @@ //! Private implementation details of BABE digests. #[cfg(feature = "std")] -use substrate_primitives::sr25519::Signature; +use super::AuthoritySignature; #[cfg(feature = "std")] use super::{BABE_ENGINE_ID, Epoch}; #[cfg(not(feature = "std"))] @@ -103,10 +103,10 @@ pub trait CompatibleDigestItem: Sized { fn as_babe_pre_digest(&self) -> Option; /// Construct a digest item which contains a BABE seal. - fn babe_seal(signature: Signature) -> Self; + fn babe_seal(signature: AuthoritySignature) -> Self; /// If this item is a BABE signature, return the signature. - fn as_babe_seal(&self) -> Option; + fn as_babe_seal(&self) -> Option; /// If this item is a BABE epoch, return it. fn as_babe_epoch(&self) -> Option; @@ -124,11 +124,11 @@ impl CompatibleDigestItem for DigestItem where self.try_to(OpaqueDigestItemId::PreRuntime(&BABE_ENGINE_ID)) } - fn babe_seal(signature: Signature) -> Self { + fn babe_seal(signature: AuthoritySignature) -> Self { DigestItem::Seal(BABE_ENGINE_ID, signature.encode()) } - fn as_babe_seal(&self) -> Option { + fn as_babe_seal(&self) -> Option { self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID)) } diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index b6e964d27feda..1650437683964 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -24,21 +24,28 @@ mod digest; use parity_codec::{Encode, Decode}; use rstd::vec::Vec; use runtime_primitives::ConsensusEngineId; -use substrate_primitives::sr25519; use substrate_client::decl_runtime_apis; #[cfg(feature = "std")] pub use digest::{BabePreDigest, CompatibleDigestItem}; pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest}; +mod app { + use substrate_primitives::{app_crypto, crypto::key_types::BABE, sr25519}; + app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, BABE); +} + /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. #[cfg(feature = "std")] -pub type AuthorityPair = sr25519::Pair; +pub type AuthorityPair = app::Pair; + +/// A Babe authority signature. +pub type AuthoritySignature = app::Signature; /// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. -pub type AuthorityId = sr25519::Public; +pub type AuthorityId = app::Public; /// The `ConsensusEngineId` of BABE. pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE"; diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 38b6257c8a239..c131bf2e95692 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -22,6 +22,7 @@ #![cfg_attr(not(test), forbid(dead_code))] pub use babe_primitives::*; pub use consensus_common::SyncOracle; +use babe_primitives; use consensus_common::ImportResult; use consensus_common::import_queue::{ BoxJustificationImport, BoxFinalityProofImport, @@ -36,7 +37,7 @@ use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; use parking_lot::{Mutex, MutexGuard}; -use primitives::{Blake2Hasher, H256, Pair, Public, sr25519}; +use primitives::{Blake2Hasher, H256, Pair, Public}; use merlin::Transcript; use inherents::{InherentDataProviders, InherentData}; use substrate_telemetry::{ @@ -142,7 +143,7 @@ pub struct BabeParams { pub config: Config, /// The key of the node we are running on. - pub local_key: Arc, + pub local_key: Arc, /// The client to use pub client: Arc, @@ -221,7 +222,7 @@ struct BabeWorker { client: Arc, block_import: Arc>, env: Arc, - local_key: Arc, + local_key: Arc, sync_oracle: SO, force_authoring: bool, c: (u64, u64), @@ -498,7 +499,7 @@ fn check_header( } else { let (pre_hash, author) = (header.hash(), &authorities[authority_index as usize].0); - if sr25519::Pair::verify(&sig, pre_hash, author.clone()) { + if AuthorityPair::verify(&sig, pre_hash, author.clone()) { let (inout, _batchable_proof) = { let transcript = make_transcript( &randomness, @@ -775,8 +776,9 @@ fn register_babe_inherent_data_provider( } } -fn get_keypair(q: &sr25519::Pair) -> &Keypair { - q.as_ref() +fn get_keypair(q: &AuthorityPair) -> &Keypair { + use primitives::crypto::IsWrappedBy; + primitives::sr25519::Pair::from_ref(q).as_ref() } #[allow(deprecated)] @@ -829,7 +831,7 @@ fn calculate_threshold( fn claim_slot( slot_number: u64, Epoch { ref authorities, ref randomness, epoch_index, .. }: Epoch, - key: &sr25519::Pair, + key: &AuthorityPair, c: (u64, u64), ) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> { let public = &key.public(); diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 7752782025183..59109035ba94d 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -28,15 +28,20 @@ use sr_primitives::{ConsensusEngineId, traits::{DigestFor, NumberFor}}; use client::decl_runtime_apis; use rstd::vec::Vec; +mod app { + use substrate_primitives::{app_crypto, crypto::key_types::GRANDPA, ed25519}; + app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, GRANDPA); +} + /// The grandpa crypto scheme defined via the keypair type. #[cfg(feature = "std")] -pub type AuthorityPair = substrate_primitives::ed25519::Pair; +pub type AuthorityPair = app::Pair; /// Identity of a Grandpa authority. -pub type AuthorityId = substrate_primitives::ed25519::Public; +pub type AuthorityId = app::Public; /// Signature for a Grandpa authority. -pub type AuthoritySignature = substrate_primitives::ed25519::Signature; +pub type AuthoritySignature = app::Signature; /// The `ConsensusEngineId` of GRANDPA. pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index dfaa96628f2dc..191b7196f20dc 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -86,7 +86,7 @@ use runtime_primitives::traits::{NumberFor, Block as BlockT, Zero}; use network::consensus_gossip::{self as network_gossip, MessageIntent, ValidatorContext}; use network::{config::Roles, PeerId}; use parity_codec::{Encode, Decode}; -use crate::ed25519::Public as AuthorityId; +use fg_primitives::AuthorityId; use substrate_telemetry::{telemetry, CONSENSUS_DEBUG}; use log::{trace, debug, warn}; diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 4707dede78d65..b6a5d556c8835 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -36,7 +36,7 @@ use futures::sync::{oneshot, mpsc}; use log::{debug, trace}; use tokio_executor::Executor; use parity_codec::{Encode, Decode}; -use substrate_primitives::{ed25519, Pair}; +use substrate_primitives::Pair; use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO}; use runtime_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; use network::{consensus_gossip as network_gossip, NetworkService}; @@ -50,7 +50,7 @@ use crate::environment::HasVoted; use gossip::{ GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator }; -use substrate_primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; +use fg_primitives::{AuthorityPair, AuthorityId, AuthoritySignature}; pub mod gossip; mod periodic; @@ -341,7 +341,7 @@ impl> NetworkBridge { round: Round, set_id: SetId, voters: Arc>, - local_key: Option>, + local_key: Option>, has_voted: HasVoted, ) -> ( impl Stream,Error=Error>, @@ -354,8 +354,7 @@ impl> NetworkBridge { ); let locals = local_key.and_then(|pair| { - let public = pair.public(); - let id = AuthorityId(public.0); + let id = pair.public(); if voters.contains_key(&id) { Some((pair, id)) } else { @@ -633,9 +632,9 @@ pub(crate) fn check_message_sig( round: u64, set_id: u64, ) -> Result<(), ()> { - let as_public = AuthorityId::from_raw(id.0); + let as_public = id.clone(); let encoded_raw = localized_payload(round, set_id, message); - if ed25519::Pair::verify(signature, &encoded_raw, as_public) { + if AuthorityPair::verify(signature, &encoded_raw, as_public) { Ok(()) } else { debug!(target: "afg", "Bad signature on message from {:?}", id); @@ -653,7 +652,7 @@ pub(crate) fn check_message_sig( struct OutgoingMessages> { round: u64, set_id: u64, - locals: Option<(Arc, AuthorityId)>, + locals: Option<(Arc, AuthorityId)>, sender: mpsc::UnboundedSender>, network: N, has_voted: HasVoted, diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index e3189ecd92c95..bc892a8a98cfc 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -37,7 +37,7 @@ use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, NumberFor, One, Zero, BlockNumberToHash, }; -use substrate_primitives::{Blake2Hasher, ed25519, H256, Pair}; +use substrate_primitives::{Blake2Hasher, H256, Pair}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use crate::{ @@ -476,7 +476,7 @@ where { type Timer = Box + Send>; type Id = AuthorityId; - type Signature = ed25519::Signature; + type Signature = AuthoritySignature; // regular round message streams type In = Box>, + pub local_key: Option>, /// Some local identifier of the voter. pub name: Option, } @@ -396,7 +396,7 @@ where } fn global_communication, B, E, N, RA>( - local_key: Option<&Arc>, + local_key: Option<&Arc>, set_id: u64, voters: &Arc>, client: &Arc>, diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 77106059f82bd..b32497e1e6eab 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -23,7 +23,7 @@ use std::path::PathBuf; use std::fs::{self, File}; use std::io::{self, Write}; -use substrate_primitives::crypto::{KeyTypeId, Pair, Public}; +use substrate_primitives::crypto::{KeyTypeId, AppPublic, AppPair, Pair, Public, IsWrappedBy}; /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] @@ -69,8 +69,8 @@ impl Store { Ok(Store { path, additional: HashMap::new() }) } - fn get_pair(&self, public: &TPair::Public) -> Result> { - let key = (TPair::KEY_TYPE, public.to_raw_vec()); + fn get_pair(&self, public: &TPair::Public, key_type: KeyTypeId) -> Result> { + let key = (key_type, public.to_raw_vec()); if let Some(bytes) = self.additional.get(&key) { let pair = TPair::from_seed_slice(bytes) .map_err(|_| Error::InvalidSeed)?; @@ -79,35 +79,55 @@ impl Store { Ok(None) } - fn insert_pair(&mut self, pair: &TPair) { - let key = (TPair::KEY_TYPE, pair.public().to_raw_vec()); + fn insert_pair(&mut self, pair: &TPair, key_type: KeyTypeId) { + let key = (key_type, pair.public().to_raw_vec()); self.additional.insert(key, pair.to_raw_vec()); } /// Generate a new key, placing it into the store. - pub fn generate(&self, password: &str) -> Result { + pub fn generate_by_type(&self, password: &str, key_type: KeyTypeId) -> Result { let (pair, phrase, _) = TPair::generate_with_phrase(Some(password)); - let mut file = File::create(self.key_file_path::(&pair.public()))?; + let mut file = File::create(self.key_file_path::(&pair.public(), key_type))?; ::serde_json::to_writer(&file, &phrase)?; file.flush()?; Ok(pair) } /// Create a new key from seed. Do not place it into the store. - pub fn generate_from_seed(&mut self, seed: &str) -> Result { + pub fn generate_from_seed_by_type(&mut self, seed: &str, key_type: KeyTypeId) -> Result { let pair = TPair::from_string(seed, None) .ok().ok_or(Error::InvalidSeed)?; - self.insert_pair(&pair); + self.insert_pair(&pair, key_type); Ok(pair) } + /// Generate a new key, placing it into the store. + pub fn generate< + Pair: AppPair + >(&self, password: &str) -> Result { + self.generate_by_type::(password, Pair::ID) + .map(Into::into) + } + + /// Create a new key from seed. Do not place it into the store. + pub fn generate_from_seed< + Pair: AppPair, + >(&mut self, seed: &str) -> Result { + self.generate_from_seed_by_type::(seed, Pair::ID) + .map(Into::into) + } + /// Load a key file with given public key. - pub fn load(&self, public: &TPair::Public, password: &str) -> Result { - if let Some(pair) = self.get_pair(public)? { + pub fn load_by_type(&self, + public: &TPair::Public, + password: &str, + key_type: KeyTypeId + ) -> Result { + if let Some(pair) = self.get_pair(public, key_type)? { return Ok(pair) } - let path = self.key_file_path::(public); + let path = self.key_file_path::(public, key_type); let file = File::open(path)?; let phrase: String = ::serde_json::from_reader(&file)?; @@ -119,18 +139,25 @@ impl Store { Ok(pair) } + /// Load a key file with given public key. + pub fn load< + Pair_: AppPair + >(&self, public: &Pair_::Public, password: &str) -> Result { + self.load_by_type::(IsWrappedBy::from_ref(public), password, Pair_::ID) + .map(Into::into) + } + /// Get public keys of all stored keys. - pub fn contents(&self) -> Result> { + pub fn contents_by_type(&self, key_type: KeyTypeId) -> Result> { let mut public_keys: Vec = self.additional.keys() .filter_map(|(ty, public)| { - if *ty != TPublic::KEY_TYPE { + if *ty != key_type { return None } Some(TPublic::from_slice(public)) }) .collect(); - let key_type: [u8; 4] = TPublic::KEY_TYPE.to_le_bytes(); for entry in fs::read_dir(&self.path)? { let entry = entry?; let path = entry.path(); @@ -151,10 +178,22 @@ impl Store { Ok(public_keys) } - fn key_file_path(&self, public: &TPair::Public) -> PathBuf { + /// Get public keys of all stored keys. + /// + /// This will just use the type of the public key (a list of which to be returned) in order + /// to determine the key type. Unless you use a specialised application-type public key, then + /// this only give you keys registered under generic cryptography, and will not return keys + /// registered under the application type. + pub fn contents< + Public: AppPublic + >(&self) -> Result> { + self.contents_by_type::(Public::ID) + .map(|v| v.into_iter().map(Into::into).collect()) + } + + fn key_file_path(&self, public: &TPair::Public, key_type: KeyTypeId) -> PathBuf { let mut buf = self.path.clone(); - let bytes: [u8; 4] = TPair::KEY_TYPE.to_le_bytes(); - let key_type = hex::encode(bytes); + let key_type = hex::encode(key_type); let key = hex::encode(public.as_slice()); buf.push(key_type + key.as_str()); buf diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 711611ada5e20..6d9ad678e12e5 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -67,6 +67,7 @@ impl StoredKey { let phrase = sr25519::Pair::generate_with_phrase(password).1; Self { kind, phrase } } + CryptoKind::Dummy => Self { kind, phrase: String::new() }, } } @@ -80,6 +81,7 @@ impl StoredKey { sr25519::Pair::from_phrase(&self.phrase, password) .map(|x| LocalKey::Sr25519(x.0)) } + CryptoKind::Dummy => Err(())?, } .map_err(|e| { warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 327a8a3eb1254..4348295aaba77 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -24,7 +24,6 @@ use std::convert::{TryFrom, TryInto}; use parking_lot::Mutex; #[cfg(feature = "std")] use rand::{RngCore, rngs::OsRng}; -#[cfg(feature = "std")] use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use regex::Regex; @@ -457,7 +456,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } /// Trait suitable for typical cryptographic PKI key public type. -pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync { +pub trait Public: AsRef<[u8]> + CryptoType + PartialEq + Eq + Clone + Send + Sync { /// A new instance from the given slice that should be 32 bytes long. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if @@ -466,17 +465,85 @@ pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync /// Return a `Vec` filled with raw data. #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec; + fn to_raw_vec(&self) -> Vec { self.as_slice().to_owned() } /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8]; + fn as_slice(&self) -> &[u8] { self.as_ref() } +} + +/// Dummy cryptography. Doesn't do anything. +#[derive(Clone, Hash, Default, Eq, PartialEq)] +pub struct Dummy; + +impl AsRef<[u8]> for Dummy { + fn as_ref(&self) -> &[u8] { &b""[..] } +} + +impl AsMut<[u8]> for Dummy { + fn as_mut(&mut self) -> &mut[u8] { + unsafe { + #[allow(mutable_transmutes)] + rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..]) + } + } +} + +impl CryptoType for Dummy { + const KIND: Kind = Kind::Dummy; + type Pair = Dummy; +} + +/// Trait suitable for typical cryptographic PKI key public type. +impl Public for Dummy { + fn from_slice(_: &[u8]) -> Self { Self } + #[cfg(feature = "std")] + fn to_raw_vec(&self) -> Vec { vec![] } + fn as_slice(&self) -> &[u8] { b"" } +} +#[cfg(feature = "std")] +impl Pair for Dummy { + type Public = Dummy; + type Seed = Dummy; + type Signature = Dummy; + type DeriveError = (); + fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() } + fn from_phrase(_: &str, _: Option<&str>) + -> Result<(Self, Self::Seed), SecretStringError> + { + Ok(Default::default()) + } + fn derive< + Iter: Iterator + >(&self, _: Iter) -> Result { Ok(Self) } + fn from_seed(_: &Self::Seed) -> Self { Self } + fn from_seed_slice(_: &[u8]) -> Result { Ok(Self) } + fn from_standard_components< + I: Iterator + >( + _: &str, + _: Option<&str>, + _: I + ) -> Result { Ok(Self) } + fn sign(&self, _: &[u8]) -> Self::Signature { Self } + fn verify, M: AsRef<[u8]>>( + _: &Self::Signature, + _: M, + _: P + ) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>( + _: &[u8], + _: M, + _: P + ) -> bool { true } + fn public(&self) -> Self::Public { Self } + fn to_raw_vec(&self) -> Vec { vec![] } } /// Trait suitable for typical cryptographic PKI key pair type. /// /// For now it just specifies how to create a key from a phrase and derivation path. #[cfg(feature = "std")] -pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static { +pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// The type which is used to encode a public key. type Public: Public + Hash; @@ -603,26 +670,432 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static { fn to_raw_vec(&self) -> Vec; } +/// A type of supported crypto. +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +#[repr(u32)] +pub enum Kind { + /// SR25519 crypto (Schnorrkel) + Sr25519 = 0, + /// ED25519 crypto (Edwards) + Ed25519 = 1, + + /// Dummy kind, just for testing. + #[cfg(feature = "std")] + Dummy = !0, +} + +impl TryFrom for Kind { + type Error = (); + + fn try_from(kind: u32) -> Result { + Ok(match kind { + e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, + e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, + _ => Err(())?, + }) + } +} + +impl From for u32 { + fn from(kind: Kind) -> Self { + kind as u32 + } +} + +/// One type is wrapped by another. +pub trait IsWrappedBy: From + Into { + /// Get a reference to the inner from the outer. + fn from_ref(outer: &Outer) -> &Self; + /// Get a mutable reference to the inner from the outer. + fn from_mut(outer: &mut Outer) -> &mut Self; +} + +/// Opposite of `IsWrappedBy` - denotes a type which is a simple wrapper around another type. +pub trait Wraps: Sized { + /// The inner type it is wrapping. + type Inner: IsWrappedBy; +} + +impl IsWrappedBy for T where + Outer: AsRef + AsMut + From, + T: From, +{ + /// Get a reference to the inner from the outer. + fn from_ref(outer: &Outer) -> &Self { outer.as_ref() } + + /// Get a mutable reference to the inner from the outer. + fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() } +} + +impl UncheckedFrom for Outer where + Outer: Wraps, + Inner: IsWrappedBy + UncheckedFrom, +{ + fn unchecked_from(t: T) -> Self { + let inner: Inner = t.unchecked_into(); + inner.into() + } +} + +/// An application-specific key. +pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { + /// The corresponding type as a generic crypto type. + type UntypedGeneric: IsWrappedBy; + + /// The corresponding public key type in this application scheme. + type Public: AppPublic; + + /// The corresponding key pair type in this application scheme. + type Pair: AppPair; + + /// The corresponding signature type in this application scheme. + type Signature: AppSignature; + + /// An identifier for this application-specific key type. + const ID: KeyTypeId; +} + +/// Type which implements Debug and Hash in std, not when no-std (std variant). +#[cfg(feature = "std")] +pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} +#[cfg(feature = "std")] +impl MaybeDebugHash for T {} + +/// Type which implements Debug and Hash in std, not when no-std (no-std variant). +#[cfg(not(feature = "std"))] +pub trait MaybeDebugHash {} + +/// A application's public key. +pub trait AppPublic: AppKey + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash { + /// The wrapped type which is just a plain instance of `Public`. + type Generic: IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash; +} + +/// A application's public key. +pub trait AppPair: AppKey { + /// The wrapped type which is just a plain instance of `Pair`. + type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; +} + +/// A application's public key. +pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { + /// The wrapped type which is just a plain instance of `Signature`. + type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; +} + +/// Implement `AsRef` and `AsMut` for the provided type. +#[macro_export] +macro_rules! impl_as_ref_mut { + ($name:ty) => { + impl AsMut for $name { + fn as_mut(&mut self) -> &mut Self { + self + } + } + impl AsRef for $name { + fn as_ref(&self) -> &Self { + &self + } + } + } +} + +/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer` +/// where . +/// +/// ```rust +/// impl_wrapper! { +/// pub struct Outer(Inner); +/// } +/// ``` +#[macro_export] +macro_rules! wrap { + ($( #[ $attr:meta ] )* struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($( #[ $attr:meta ] )* pub struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + pub struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($inner:ty, $outer:ty) => { + impl $crate::crypto::Wraps for $outer { + type Inner = $inner; + } + impl From<$inner> for $outer { + fn from(inner: $inner) -> Self { + Self(inner) + } + } + impl From<$outer> for $inner { + fn from(outer: $outer) -> Self { + outer.0 + } + } + impl AsRef<$inner> for $outer { + fn as_ref(&self) -> &$inner { + &self.0 + } + } + impl AsMut<$inner> for $outer { + fn as_mut(&mut self) -> &mut $inner { + &mut self.0 + } + } + } +} + +/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new +/// Application-specific types whose identifier is `$key_type`. +/// +/// ```rust +/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` +/// // of value `b"fuba"`. +/// app_crypto!(ed25519, *b"fuba"); +/// ``` +#[macro_export] +macro_rules! app_crypto { + ($pair:ty, $public:ty, $sig:ty, $key_type:expr) => { + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Public($public); + } + // TODO: needed for verify since it takes an AsRef, but should be removed once that is + // refactored. + $crate::impl_as_ref_mut!(Public); + + #[cfg(feature = "std")] + impl $crate::crypto::Derive for Public { + fn derive>(&self, + path: Iter + ) -> Option { + self.0.derive(path).map(Self) + } + } + #[cfg(feature = "std")] + impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use $crate::crypto::Ss58Codec; + write!(f, "{}", self.0.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl $crate::serde::Serialize for Public { + fn serialize(&self, serializer: S) -> std::result::Result where + S: $crate::serde::Serializer + { + use $crate::crypto::Ss58Codec; + serializer.serialize_str(&self.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl<'de> $crate::serde::Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> std::result::Result where + D: $crate::serde::Deserializer<'de> + { + use $crate::crypto::Ss58Codec; + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) + } + } + impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } + } + impl $crate::crypto::CryptoType for Public { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + impl $crate::crypto::Public for Public { + fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } + } + impl $crate::crypto::AppKey for Public { + type UntypedGeneric = $public; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppPublic for Public { + type Generic = $public; + } + + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone)] + pub struct Pair($pair); + } + + impl $crate::crypto::CryptoType for Pair { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + #[cfg(feature = "std")] + impl $crate::crypto::Pair for Pair { + type Public = Public; + type Seed = <$pair as $crate::crypto::Pair>::Seed; + type Signature = Signature; + type DeriveError = <$pair as $crate::crypto::Pair>::DeriveError; + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { + let r = <$pair>::generate_with_phrase(password); + (Self(r.0), r.1, r.2) + } + fn from_phrase(phrase: &str, password: Option<&str>) + -> Result<(Self, Self::Seed), $crate::crypto::SecretStringError> + { + <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) + } + fn derive< + Iter: Iterator + >(&self, path: Iter) -> Result { + self.0.derive(path).map(Self) + } + fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) } + fn from_seed_slice(seed: &[u8]) -> Result { + <$pair>::from_seed_slice(seed).map(Self) + } + fn from_standard_components< + I: Iterator + >( + seed: &str, + password: Option<&str>, + path: I + ) -> Result { + <$pair>::from_standard_components::(seed, password, path).map(Self) + } + fn sign(&self, msg: &[u8]) -> Self::Signature { + Signature(self.0.sign(msg)) + } + fn verify, M: AsRef<[u8]>>( + sig: &Self::Signature, + message: M, + pubkey: P + ) -> bool { + <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) + } + fn verify_weak, M: AsRef<[u8]>>( + sig: &[u8], + message: M, + pubkey: P + ) -> bool { + <$pair>::verify_weak(sig, message, pubkey) + } + fn public(&self) -> Self::Public { Public(self.0.public()) } + fn to_raw_vec(&self) -> Vec { self.0.to_raw_vec() } + } + impl $crate::crypto::AppKey for Pair { + type UntypedGeneric = $pair; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppPair for Pair { + type Generic = $pair; + } + + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, $crate::Encode, $crate::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Signature($sig); + } + + impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + impl $crate::crypto::CryptoType for Signature { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + impl $crate::crypto::AppKey for Signature { + type UntypedGeneric = $sig; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppSignature for Signature { + type Generic = $sig; + } + } +} + +// TODO: remove default cryptos + +/// Type which has a particular kind of crypto associated with it. +pub trait CryptoType { + /// The kind of crypto it has. + const KIND: Kind; + + /// The pair key type of this crypto. + type Pair: Pair; +} + /// An identifier for a type of cryptographic key. /// -/// 0-1024 are reserved. -pub type KeyTypeId = u32; +/// To avoid clashes with other modules when distributing your module publically, register your +/// `KeyTypeId` on the list here by making a PR. +/// +/// Values whose first character is `_` are reserved for private use and won't conflict with any +/// public modules. +pub type KeyTypeId = [u8; 4]; -/// Constant key types. +/// Known key types; this also functions as a global registry of key types for projects wishing to +/// avoid collisions with each other. pub mod key_types { use super::KeyTypeId; - /// ED25519 public key. - pub const ED25519: KeyTypeId = 10; + /// Key type for generic S/R 25519 key. + pub const SR25519: KeyTypeId = *b"sr25"; + /// Key type for generic Ed25519 key. + pub const ED25519: KeyTypeId = *b"ed25"; + /// Key type for Aura module, build-in. + pub const AURA: KeyTypeId = *b"aura"; + /// Key type for Babe module, build-in. + pub const BABE: KeyTypeId = *b"babe"; + /// Key type for Grandpa module, build-in. + pub const GRANDPA: KeyTypeId = *b"gran"; + /// A key type ID useful for tests. + #[cfg(feature = "std")] + pub const DUMMY: KeyTypeId = *b"dumy"; +} + +impl TryFrom for Kind { + type Error = (); - /// SR25519 public key. - pub const SR25519: KeyTypeId = 20; + fn try_from(kind: KeyTypeId) -> Result { + Ok(match kind { + e if e == key_types::SR25519 => Kind::Sr25519, + e if e == key_types::ED25519 => Kind::Ed25519, + e if e == key_types::BABE => Kind::Sr25519, + e if e == key_types::GRANDPA => Kind::Ed25519, + #[cfg(feature = "std")] + e if e == key_types::DUMMY => Kind::Dummy, + _ => Err(())?, + }) + } } -/// A trait for something that has a key type ID. -pub trait TypedKey { - /// The type ID of this key. - const KEY_TYPE: KeyTypeId; +// This doesn't make much sense and should be reconsidered. +impl TryFrom for KeyTypeId { + type Error = (); + + fn try_from(kind: Kind) -> Result { + Ok(match kind { + Kind::Sr25519 => key_types::SR25519, + Kind::Ed25519 => key_types::ED25519, + #[cfg(feature = "std")] + Kind::Dummy => key_types::DUMMY, + }) + } } #[cfg(test)] @@ -659,7 +1132,7 @@ mod tests { } } impl TypedKey for TestPublic { - const KEY_TYPE: u32 = 4242; + const KEY_TYPE: KeyTypeId = TEST_KEY_TYPE; } impl Pair for TestPair { type Public = TestPublic; diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 5d1fe884a5180..4e34c53fd7230 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -32,7 +32,9 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec}; #[cfg(feature = "std")] use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; -use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; +use crate::{impl_as_ref_mut, crypto::{ + Public as TraitPublic, UncheckedFrom, CryptoType, Kind +}}; /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we @@ -90,12 +92,6 @@ impl From for Public { } } -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self - } -} - impl From for H256 { fn from(x: Public) -> Self { x.0.into() @@ -296,6 +292,8 @@ impl Public { } } +impl_as_ref_mut!(Public); + impl TraitPublic for Public { /// A new instance from the given slice that should be 32 bytes long. /// @@ -306,31 +304,11 @@ impl TraitPublic for Public { r.copy_from_slice(data); Public(r) } - - /// Return a `Vec` filled with raw data. - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { - let r: &[u8; 32] = self.as_ref(); - r.to_vec() - } - - /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8] { - let r: &[u8; 32] = self.as_ref(); - &r[..] - } } #[cfg(feature = "std")] impl Derive for Public {} -#[cfg(feature = "std")] -impl AsRef for Pair { - fn as_ref(&self) -> &Pair { - &self - } -} - /// Derive a single hard junction. #[cfg(feature = "std")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { @@ -488,19 +466,31 @@ impl Pair { } } -impl TypedKey for Public { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Public { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; } -impl TypedKey for Signature { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Signature { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; } #[cfg(feature = "std")] -impl TypedKey for Pair { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Pair { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; +} + +mod app { + use crate::crypto::key_types::ED25519; + crate::app_crypto!(super::Pair, super::Public, super::Signature, ED25519); } +pub use app::Public as AppPublic; +pub use app::Pair as AppPair; +pub use app::Signature as AppSignature; + #[cfg(test)] mod test { use super::*; diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 4fabb04ccb038..5d4210cb4f2d7 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -33,11 +33,13 @@ macro_rules! map { use rstd::prelude::*; use rstd::ops::Deref; -use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use std::borrow::Cow; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; +#[cfg(feature = "std")] +pub use serde;// << for macro +pub use parity_codec::{Encode, Decode};// << for macro #[cfg(feature = "std")] pub use impl_serde::serialize as bytes; diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 5b6f8f5c22556..931597a6dde8f 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -16,11 +16,12 @@ //! Offchain workers types -use crate::crypto; use parity_codec::{Encode, Decode}; use rstd::prelude::{Vec, Box}; use rstd::convert::TryFrom; +pub use crate::crypto::Kind as CryptoKind; + /// A type of supported crypto. #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] @@ -58,35 +59,6 @@ impl From for u32 { } } -/// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] -#[repr(C)] -pub enum CryptoKind { - /// SR25519 crypto (Schnorrkel) - Sr25519 = crypto::key_types::SR25519 as isize, - /// ED25519 crypto (Edwards) - Ed25519 = crypto::key_types::ED25519 as isize, -} - -impl TryFrom for CryptoKind { - type Error = (); - - fn try_from(kind: u32) -> Result { - match kind { - e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519), - e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519), - _ => Err(()), - } - } -} - -impl From for u32 { - fn from(c: CryptoKind) -> Self { - c as isize as u32 - } -} - /// Key to use in the offchain worker crypto api. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index e01d989143c6b..37263ce982403 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -30,8 +30,10 @@ use substrate_bip39::mini_secret_from_entropy; #[cfg(feature = "std")] use bip39::{Mnemonic, Language, MnemonicType}; #[cfg(feature = "std")] -use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec}; -use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; +use crate::crypto::{ + Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec +}; +use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Kind}}; use crate::hash::{H256, H512}; use parity_codec::{Encode, Decode}; @@ -63,11 +65,7 @@ impl Clone for Pair { } } -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self - } -} +impl_as_ref_mut!(Public); impl AsRef<[u8; 32]> for Public { fn as_ref(&self) -> &[u8; 32] { @@ -318,24 +316,6 @@ impl TraitPublic for Public { r.copy_from_slice(data); Public(r) } - - /// Return a `Vec` filled with raw data. - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { - self.0.to_vec() - } - - /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8] { - &self.0 - } -} - -#[cfg(feature = "std")] -impl AsRef for Pair { - fn as_ref(&self) -> &Pair { - &self - } } #[cfg(feature = "std")] @@ -523,19 +503,31 @@ impl Pair { } } -impl TypedKey for Public { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Public { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; } -impl TypedKey for Signature { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Signature { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; } #[cfg(feature = "std")] -impl TypedKey for Pair { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Pair { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; +} + +mod app { + use crate::crypto::key_types::SR25519; + crate::app_crypto!(super::Pair, super::Public, super::Signature, SR25519); } +pub use app::Public as AppPublic; +pub use app::Pair as AppPair; +pub use app::Signature as AppSignature; + #[cfg(test)] mod test { use super::*; diff --git a/core/service/src/components.rs b/core/service/src/components.rs index e81380b3202fd..99570d1b91da4 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -30,7 +30,7 @@ use runtime_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256, Pair}; +use primitives::{Blake2Hasher, H256, crypto::AppPair}; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor, sync::mpsc}; @@ -294,9 +294,9 @@ pub trait ServiceFactory: 'static + Sized { /// Block type. type Block: BlockT; /// Consensus crypto type. - type ConsensusPair: Pair; + type ConsensusPair: AppPair; /// Finality crypto type. - type FinalityPair: Pair; + type FinalityPair: AppPair; /// The type that implements the runtime API. type RuntimeApi: Send + Sync; /// Network protocol extensions. diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index bd600b81cbbb3..08a4f0772b29d 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -41,9 +41,9 @@ use keystore::Store as Keystore; use network::{NetworkState, NetworkStateInfo}; use log::{log, info, warn, debug, error, Level}; use parity_codec::{Encode, Decode}; -use primitives::{Pair, ed25519, sr25519, crypto}; +use primitives::{crypto::{self, AppPair}}; use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero}; +use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion}; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -187,12 +187,15 @@ impl Service { // Keep the public key for telemetry let public_key: String; + /* // This is meant to be for testing only // FIXME #1063 remove this if let Some(keystore) = keystore.as_mut() { for seed in &config.keys { - keystore.generate_from_seed::(seed)?; - keystore.generate_from_seed::(seed)?; + // this won't work as desired since it's only generating "plain" + // keys here, not app-specific keys as the engines will need. + keystore.generate_from_seed::(seed)?; + keystore.generate_from_seed::(seed)?; } public_key = match keystore.contents::()?.get(0) { @@ -207,6 +210,8 @@ impl Service { } else { public_key = format!(""); } + */ + public_key = format!(""); let (client, on_demand) = Components::build_client(&config, executor)?; let select_chain = Components::build_select_chain(&mut config, client.clone())?; @@ -501,7 +506,7 @@ impl Service { _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), }) } - +/* /// give the authority key, if we are an authority and have a key pub fn authority_key(&self) -> Option> { use offchain::AuthorityKeyProvider; @@ -515,7 +520,7 @@ impl Service { self.keystore.fg_authority_key(&BlockId::Number(Zero::zero())) } - +*/ /// return a shared instance of Telemetry (if enabled) pub fn telemetry(&self) -> Option { self._telemetry.as_ref().map(|t| t.clone()) @@ -914,14 +919,15 @@ pub struct AuthorityKeyProvider { impl offchain::AuthorityKeyProvider - for AuthorityKeyProvider +for + AuthorityKeyProvider where Block: runtime_primitives::traits::Block, - ConsensusPair: Pair, - FinalityPair: Pair, + ConsensusPair: AppPair, + FinalityPair: AppPair, { - type ConsensusPair = ConsensusPair; - type FinalityPair = FinalityPair; + type ConsensusPair = ConsensusPair::Generic; + type FinalityPair = FinalityPair::Generic; fn authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { @@ -934,9 +940,12 @@ where }; let loaded_key = keystore - .contents() + .contents::() .map(|keys| keys.get(0) - .map(|k| keystore.load(k, self.password.as_ref())) + .map(|k| + keystore.load::(k, self.password.as_ref()) + .map(Into::into) + ) ); if let Ok(Some(Ok(key))) = loaded_key { @@ -957,9 +966,12 @@ where }; let loaded_key = keystore - .contents() + .contents::() .map(|keys| keys.get(0) - .map(|k| keystore.load(k, self.password.as_ref())) + .map(|k| + keystore.load::(k, self.password.as_ref()) + .map(Into::into) + ) ); if let Ok(Some(Ok(key))) = loaded_key { diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 922fe7f9defdb..de0895a1b4bc8 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -52,7 +52,7 @@ pub mod transaction_validity; pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. -pub use substrate_primitives::crypto::{key_types, KeyTypeId}; +pub use substrate_primitives::crypto::{key_types, KeyTypeId, AppKey, Kind, CryptoType}; /// A message indicating an invalid signature in extrinsic. pub const BAD_SIGNATURE: &str = "bad signature in extrinsic"; diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index b12c7258c2638..40cb9d084773b 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -20,19 +20,18 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializ use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{ - self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult, + self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, DispatchError, DispatchResult, ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use substrate_primitives::H256; -use substrate_primitives::U256; +use substrate_primitives::{crypto::{Kind, CryptoType, Dummy, key_types}, U256}; use substrate_primitives::ed25519::{Public as AuthorityId}; use crate::transaction_validity::TransactionValidity; /// Authority Id -#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize)] pub struct UintAuthorityId(pub u64); impl Into for UintAuthorityId { fn into(self) -> AuthorityId { @@ -41,25 +40,15 @@ impl Into for UintAuthorityId { } } -/// The key-type of the `UintAuthorityId` -pub const UINT_DUMMY_KEY: KeyTypeId = 0xdeadbeef; - -impl TypedKey for UintAuthorityId { - const KEY_TYPE: KeyTypeId = UINT_DUMMY_KEY; -} - -impl AsRef<[u8]> for UintAuthorityId { - fn as_ref(&self) -> &[u8] { - let ptr = self.0 as *const _; - // It's safe to do this here since `UintAuthorityId` is `u64`. - unsafe { std::slice::from_raw_parts(ptr, 8) } - } +impl CryptoType for UintAuthorityId { + const KIND: Kind = Kind::Dummy; + type Pair = Dummy; } impl OpaqueKeys for UintAuthorityId { type KeyTypeIds = std::iter::Cloned>; - fn key_ids() -> Self::KeyTypeIds { [UINT_DUMMY_KEY].iter().cloned() } + fn key_ids() -> Self::KeyTypeIds { [key_types::DUMMY].iter().cloned() } // Unsafe, i know, but it's test code and it's just there because it's really convenient to // keep `UintAuthorityId` as a u64 under the hood. fn get_raw(&self, _: KeyTypeId) -> &[u8] { diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 7b7d6a5a27e67..30f2971cf2347 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -26,7 +26,6 @@ use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::{ValidTransaction, TransactionValidity}; use crate::generic::{Digest, DigestItem}; use crate::weights::DispatchInfo; -pub use substrate_primitives::crypto::TypedKey; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 26e54f6ee650c..e7926ae72887c 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -16,8 +16,7 @@ //! Substrate chain configurations. -use babe_primitives::AuthorityId as BabeId; -use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto}; +use primitives::{sr25519, Pair, crypto::UncheckedInto}; use node_primitives::{AccountId, Balance}; use node_runtime::{ BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, @@ -30,7 +29,8 @@ pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::hex; use substrate_telemetry::TelemetryEndpoints; -use grandpa::AuthorityId as GrandpaId; +use grandpa_primitives::{AuthorityId as GrandpaId, AuthorityPair as GrandpaPair}; +use babe_primitives::{AuthorityId as BabeId, AuthorityPair as BabePair}; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -42,11 +42,8 @@ pub fn flaming_fir_config() -> Result { ChainSpec::from_embedded(include_bytes!("../res/flaming-fir.json")) } -fn session_keys(ed_key: ed25519::Public, sr_key: sr25519::Public) -> SessionKeys { - SessionKeys { - ed25519: ed_key, - sr25519: sr_key, - } +fn session_keys(grandpa: GrandpaId, babe: BabeId) -> SessionKeys { + SessionKeys { grandpa, babe } } fn staging_testnet_config_genesis() -> GenesisConfig { @@ -56,7 +53,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // and // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done - let initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)> = vec![( + // TODO: actually use sr25519 for babe keys (right now they seems to just be copies of the + // ed25519 grandpa key). + let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)> = vec![( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq @@ -122,7 +121,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.3.clone(), x.2.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -159,14 +158,14 @@ fn staging_testnet_config_genesis() -> GenesisConfig { key: endowed_accounts[0].clone(), }), babe: Some(BabeConfig { - authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), }), im_online: Some(ImOnlineConfig { gossip_at: 0, last_new_era_start: 0, }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } @@ -195,31 +194,31 @@ pub fn get_account_id_from_seed(seed: &str) -> AccountId { /// Helper function to generate BabeId from seed pub fn get_babe_id_from_seed(seed: &str) -> BabeId { - sr25519::Pair::from_string(&format!("//{}", seed), None) + BabePair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } /// Helper function to generate GrandpaId from seed pub fn get_grandpa_id_from_seed(seed: &str) -> GrandpaId { - ed25519::Pair::from_string(&format!("//{}", seed), None) + GrandpaPair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } /// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, BabeId, GrandpaId) { +pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId) { ( get_account_id_from_seed(&format!("{}//stash", seed)), get_account_id_from_seed(seed), + get_grandpa_id_from_seed(seed), get_babe_id_from_seed(seed), - get_grandpa_id_from_seed(seed) ) } /// Helper function to create GenesisConfig for testing pub fn testnet_genesis( - initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)>, + initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>, root_key: AccountId, endowed_accounts: Option>, enable_println: bool, @@ -260,7 +259,7 @@ pub fn testnet_genesis( }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.3.clone(), x.2.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -302,14 +301,14 @@ pub fn testnet_genesis( key: root_key, }), babe: Some(BabeConfig { - authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), }), im_online: Some(ImOnlineConfig{ gossip_at: 0, last_new_era_start: 0, }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index aeeb8e2061fdf..39b288fdb9171 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -119,7 +119,12 @@ construct_service_factory! { } } - if let Some(babe_key) = service.authority_key() { + // TODO: key used should be automated and both of these should be plugins. + + let maybe_babe_key: Option = None;//service.authority_key(); + let maybe_grandpa_key = None;//service.fg_authority_key(); + + if let Some(babe_key) = maybe_babe_key { info!("Using BABE key {}", babe_key.public()); let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { @@ -149,14 +154,14 @@ construct_service_factory! { service.spawn_task(Box::new(select)); } - let grandpa_key = if service.config.disable_grandpa { + let maybe_grandpa_key = if service.config.disable_grandpa { None } else { - service.fg_authority_key() + maybe_grandpa_key }; let config = grandpa::Config { - local_key: grandpa_key.map(Arc::new), + local_key: maybe_grandpa_key.map(Arc::new), // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 4096, diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index e79036c0a8b82..a6c3b94a489ab 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -191,10 +191,10 @@ type SessionHandlers = (Grandpa, Babe); impl_opaque_keys! { pub struct SessionKeys { - #[id(key_types::ED25519)] - pub ed25519: GrandpaId, - #[id(key_types::SR25519)] - pub sr25519: BabeId, + #[id(key_types::GRANDPA)] + pub grandpa: GrandpaId, + #[id(key_types::BABE)] + pub babe: BabeId, } } diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index b57024ac1068d..ec20c31722056 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -69,7 +69,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use substrate_primitives::{ - crypto::TypedKey, offchain::CryptoKey, + crypto::{AppKey, CryptoType}, offchain::CryptoKey, offchain::OpaqueNetworkState, offchain::StorageKind, sr25519, ed25519, @@ -151,7 +151,7 @@ pub trait Trait: system::Trait + session::Trait { type UncheckedExtrinsic: ExtrinsicT::Call> + Encode + Decode; /// The identifier type for an authority. - type AuthorityId: Member + Parameter + Default + TypedKey + Decode + Encode + AsRef<[u8]>; + type AuthorityId: Member + Parameter + Default + AppKey + Decode + Encode + AsRef<[u8]>; /// Number of sessions per era. type SessionsPerEra: Get; @@ -428,10 +428,10 @@ impl srml_support::unsigned::ValidateUnsigned for Module { let encoded_heartbeat = heartbeat.encode(); - let signature_valid = match ::KEY_TYPE { - ed25519::Public::KEY_TYPE => + let signature_valid = match ::KIND { + ed25519::Public::KIND => sr_io::ed25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), - sr25519::Public::KEY_TYPE => + sr25519::Public::KIND => sr_io::sr25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), _ => return TransactionValidity::Invalid(ApplyError::BadSignature as i8), }; diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 7bdc1f96a0fa2..cd1673b81912a 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -121,9 +121,9 @@ use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; use parity_codec::Decode; -use primitives::KeyTypeId; +use primitives::{KeyTypeId, AppKey}; use primitives::weights::SimpleDispatchInfo; -use primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey}; +use primitives::traits::{Convert, Zero, Member, OpaqueKeys}; use srml_support::{ dispatch::Result, ConsensusEngineId, StorageValue, StorageDoubleMap, for_each_tuple, decl_module, decl_event, decl_storage, @@ -201,7 +201,7 @@ pub trait SessionHandler { /// One session-key type handler. pub trait OneSessionHandler { /// The key type expected. - type Key: Decode + Default + TypedKey; + type Key: Decode + Default + AppKey; fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued_validators: I) where I: Iterator, ValidatorId: 'a; @@ -225,10 +225,10 @@ macro_rules! impl_session_handlers { ) { $( let our_keys: Box> = Box::new(validators.iter() - .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as TypedKey>::KEY_TYPE) + .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID) .unwrap_or_default()))); let queued_keys: Box> = Box::new(queued_validators.iter() - .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as TypedKey>::KEY_TYPE) + .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID) .unwrap_or_default()))); $t::on_new_session(changed, our_keys, queued_keys); )* From 5aad05b00a1d009c2599718f2baa7cd54541c311 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 28 Jul 2019 21:24:57 +0800 Subject: [PATCH 10/80] Introduce new AuthorityProvider API into Aura This will eventually allow for dynamic determination of authority keys and avoid having to set them directly on CLI. --- Cargo.lock | 4 ++ core/client/src/client.rs | 14 ++++ core/client/src/lib.rs | 2 +- core/consensus/aura/Cargo.toml | 1 + core/consensus/aura/primitives/src/lib.rs | 34 ++++++++++ core/consensus/aura/src/lib.rs | 81 ++++++++++++++++++++--- core/consensus/babe/src/lib.rs | 2 +- core/keystore/src/lib.rs | 6 +- core/network/Cargo.toml | 1 + core/network/src/test/mod.rs | 2 +- core/primitives/src/crypto.rs | 22 +++--- core/service/src/lib.rs | 24 +++---- core/test-runtime/client/src/lib.rs | 7 +- node-template/Cargo.toml | 2 + node-template/runtime/src/lib.rs | 6 +- node-template/src/chain_spec.rs | 5 +- node-template/src/service.rs | 10 +-- srml/aura/src/lib.rs | 5 +- 18 files changed, 179 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f77a7f38fb26..a951d5da7bb41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2388,7 +2388,9 @@ dependencies = [ "substrate-cli 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura 2.0.0", + "substrate-consensus-aura-primitives 2.0.0", "substrate-executor 2.0.0", + "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", @@ -4297,6 +4299,7 @@ dependencies = [ "substrate-executor 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", @@ -4565,6 +4568,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", "substrate-consensus-common 2.0.0", "substrate-keyring 2.0.0", "substrate-peerset 2.0.0", diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 6decdfc9cacdd..c572c39a73677 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -291,6 +291,20 @@ pub fn new_with_backend( Client::new(backend, call_executor, build_genesis_storage, Default::default()) } +/// Figure out the block type for a given type (for now, just a `Client`). +pub trait BlockOf { + /// The type of the block. + type Type: BlockT; +} + +impl BlockOf for Client where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + type Type = Block; +} + impl Client where B: backend::Backend, E: CallExecutor, diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 441b2480e91ee..b3d260aacff4d 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -59,7 +59,7 @@ pub use crate::client::{ new_in_mem, BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents, BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification, - LongestChain, + LongestChain, BlockOf, utils, }; #[cfg(feature = "std")] diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index add7d8b217bf7..fda2acd1f283b 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -17,6 +17,7 @@ inherents = { package = "substrate-inherents", path = "../../inherents" } srml-aura = { path = "../../../srml/aura" } client = { package = "substrate-client", path = "../../client" } substrate-telemetry = { path = "../../telemetry" } +substrate-keystore = { path = "../../keystore" } consensus_common = { package = "substrate-consensus-common", path = "../common" } runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 47b1399a677f4..d16ee9e0666bd 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -23,6 +23,40 @@ use substrate_client::decl_runtime_apis; use rstd::vec::Vec; use runtime_primitives::ConsensusEngineId; +mod app_sr25519 { + use substrate_primitives::{app_crypto, crypto::key_types::AURA, sr25519}; + app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, AURA); +} + +pub mod sr25519 { + /// An Aura authority keypair using S/R 25519 as its crypto. + #[cfg(feature = "std")] + pub type AuthorityPair = super::app_sr25519::Pair; + + /// An Aura authority signature using S/R 25519 as its crypto. + pub type AuthoritySignature = super::app_sr25519::Signature; + + /// An Aura authority identifier using S/R 25519 as its crypto. + pub type AuthorityId = super::app_sr25519::Public; +} + +mod app_ed25519 { + use substrate_primitives::{app_crypto, crypto::key_types::AURA, ed25519}; + app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, AURA); +} + +pub mod ed25519 { + /// An Aura authority keypair using Ed25519 as its crypto. + #[cfg(feature = "std")] + pub type AuthorityPair = super::app_ed25519::Pair; + + /// An Aura authority signature using Ed25519 as its crypto. + pub type AuthoritySignature = super::app_ed25519::Signature; + + /// An Aura authority identifier using Ed25519 as its crypto. + pub type AuthorityId = super::app_ed25519::Public; +} + /// The `ConsensusEngineId` of AuRa. pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a']; diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 485d4c78d00a9..83441b7eda531 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -40,16 +40,18 @@ use consensus_common::import_queue::{ }; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, - blockchain::ProvideCache, + blockchain::{ProvideCache, HeaderBackend}, runtime_api::ApiExt, error::Result as CResult, backend::AuxStore, + BlockOf }; +use substrate_keystore::Store; use runtime_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification}; use runtime_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member}; -use primitives::Pair; +use primitives::crypto::{Pair, AppPair, AppKey}; use inherents::{InherentDataProviders, InherentData}; use futures::{prelude::*, future}; @@ -141,7 +143,7 @@ pub fn start_aura( force_authoring: bool, ) -> Result, consensus_common::Error> where B: BlockT, - C: ProvideRuntimeApi + ProvideCache + AuxStore + Send + Sync, + C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + Send + Sync, C::Api: AuraApi>, SC: SelectChain, E::Proposer: Proposer, @@ -188,7 +190,7 @@ struct AuraWorker { impl SlotWorker for AuraWorker where B: BlockT, - C: ProvideRuntimeApi + ProvideCache + Sync, + C: ProvideRuntimeApi + BlockOf + ProvideCache + Sync, C::Api: AuraApi>, E: Environment, E::Proposer: Proposer, @@ -508,7 +510,7 @@ impl AuraVerifier #[forbid(deprecated)] impl Verifier for AuraVerifier where - C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache, + C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache + BlockOf, C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

, P: Pair + Send + Sync + 'static, @@ -611,7 +613,7 @@ impl Verifier for AuraVerifier where fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusError> where A: Codec, B: BlockT, - C: ProvideRuntimeApi + ProvideCache, + C: ProvideRuntimeApi + BlockOf + ProvideCache, C::Api: AuraApi, { // no cache => no initialization @@ -645,7 +647,7 @@ fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusErro fn authorities(client: &C, at: &BlockId) -> Result, ConsensusError> where A: Codec, B: BlockT, - C: ProvideRuntimeApi + ProvideCache, + C: ProvideRuntimeApi + BlockOf + ProvideCache, C::Api: AuraApi, { client @@ -658,6 +660,69 @@ fn authorities(client: &C, at: &BlockId) -> Result, Consensus .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) } +/// Means of determining a list of authority keys, generally used to determine if we are an +/// authority by cross-referencing this list against the keys in the store and finding one that +/// appears in both. +/// +/// This is implemented directly on the `AppPair` key type. +pub trait AuthorityProvider: AppPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>; + + /// Provide a list of authority keys that is current. By default this will just use the state of + /// the best block, but you might want it to use some other block's state instead if it's + /// more sophisticated. Grandpa, for example, will probably want to use the state of the last + /// finalised block. + fn authorities(client: &C) -> Result::Public>, ConsensusError> where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: AuraApi<::Type, ::Public> + { + Self::authorities_at::(client, &BlockId::Number(client.info().best_number)) + } + + /// Provide the authority key, if any, that is controlled by this node as of the given block. + fn authority(client: &C, keystore: Arc) -> Option where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: AuraApi<::Type, ::Public> + { + let owned = keystore.contents::<::Public>().ok()?; + let authorities = Self::authorities(client).ok()?; + let maybe_pub = owned.into_iter() + .find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.load(&public, "").ok()) + } +} + +impl AuthorityProvider for aura_primitives::ed25519::AuthorityPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>, + { + authorities::(client, at) + } +} + +impl AuthorityProvider for aura_primitives::sr25519::AuthorityPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>, + { + authorities::(client, at) + } +} + /// The Aura import queue type. pub type AuraImportQueue = BasicQueue; @@ -686,7 +751,7 @@ pub fn import_queue( inherent_data_providers: InherentDataProviders, ) -> Result, consensus_common::Error> where B: BlockT, - C: 'static + ProvideRuntimeApi + ProvideCache + Send + Sync + AuxStore, + C: 'static + ProvideRuntimeApi + BlockOf + ProvideCache + Send + Sync + AuxStore, C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

; @@ -739,7 +740,7 @@ pub(crate) mod tests { let proof_of_4 = prove_finality::<_, _, TestJustification>( &blockchain, &( - |_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]), + |_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]), |_| unreachable!("authorities didn't change => ProveAuthorities won't be called"), ), 0, @@ -762,7 +763,7 @@ pub(crate) mod tests { let proof_of_5: FinalityProof = Decode::decode(&mut &prove_finality::<_, _, TestJustification>( &blockchain, &( - |_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]), + |_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]), |_| unreachable!("should return before calling ProveAuthorities"), ), 0, @@ -788,7 +789,7 @@ pub(crate) mod tests { let proof_of_5: FinalityProof = Decode::decode(&mut &prove_finality::<_, _, TestJustification>( &blockchain, &( - |_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]), + |_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]), |_| unreachable!("should return before calling ProveAuthorities"), ), 0, @@ -820,10 +821,12 @@ pub(crate) mod tests { &blockchain, &( |block_id| match block_id { - BlockId::Hash(h) if h == header(3).hash() => Ok(vec![(AuthorityId::from_raw([3u8; 32]), 1u64)]), - BlockId::Number(3) => Ok(vec![(AuthorityId::from_raw([3u8; 32]), 1u64)]), - BlockId::Number(4) => Ok(vec![(AuthorityId::from_raw([4u8; 32]), 1u64)]), - BlockId::Number(6) => Ok(vec![(AuthorityId::from_raw([6u8; 32]), 1u64)]), + BlockId::Hash(h) if h == header(3).hash() => Ok( + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)] + ), + BlockId::Number(3) => Ok(vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)]), + BlockId::Number(4) => Ok(vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)]), + BlockId::Number(6) => Ok(vec![(AuthorityId::from_slice(&[6u8; 32]), 1u64)]), _ => unreachable!("no other authorities should be fetched: {:?}", block_id), }, |block_id| match block_id { @@ -864,7 +867,7 @@ pub(crate) mod tests { do_check_finality_proof::<_, _, TestJustification>( &blockchain, 1, - vec![(AuthorityId::from_raw([3u8; 32]), 1u64)], + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], &ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")), vec![42], ).unwrap_err(); @@ -878,7 +881,7 @@ pub(crate) mod tests { do_check_finality_proof::<_, _, TestJustification>( &blockchain, 1, - vec![(AuthorityId::from_raw([3u8; 32]), 1u64)], + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], &ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")), Vec::::new().encode(), ).unwrap_err(); @@ -892,7 +895,7 @@ pub(crate) mod tests { do_check_finality_proof::<_, _, TestJustification>( &blockchain, 1, - vec![(AuthorityId::from_raw([3u8; 32]), 1u64)], + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], &ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")), vec![FinalityProofFragment { block: header(4).hash(), @@ -916,7 +919,7 @@ pub(crate) mod tests { do_check_finality_proof::<_, _, TestJustification>( &blockchain, 1, - vec![(AuthorityId::from_raw([3u8; 32]), 1u64)], + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], &ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")), vec![FinalityProofFragment { block: header(4).hash(), @@ -939,8 +942,8 @@ pub(crate) mod tests { let effects = do_check_finality_proof::<_, _, TestJustification>( &blockchain, 1, - vec![(AuthorityId::from_raw([3u8; 32]), 1u64)], - &ClosureAuthoritySetForFinalityChecker(|_, _, _| Ok(vec![(AuthorityId::from_raw([4u8; 32]), 1u64)])), + vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)], + &ClosureAuthoritySetForFinalityChecker(|_, _, _| Ok(vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)])), vec![FinalityProofFragment { block: header(2).hash(), justification: TestJustification(true, vec![7]).encode(), @@ -958,7 +961,7 @@ pub(crate) mod tests { block: header(4).hash(), justification: TestJustification(true, vec![8]).encode(), new_set_id: 2, - new_authorities: vec![(AuthorityId::from_raw([4u8; 32]), 1u64)], + new_authorities: vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)], }); } @@ -975,7 +978,7 @@ pub(crate) mod tests { let proof_of_4 = prove_finality::<_, _, TestJustification>( &blockchain, &( - |_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]), + |_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]), |_| unreachable!("should return before calling ProveAuthorities"), ), 0, diff --git a/core/finality-grandpa/src/light_import.rs b/core/finality-grandpa/src/light_import.rs index abc98976fda6b..b34295656a9ad 100644 --- a/core/finality-grandpa/src/light_import.rs +++ b/core/finality-grandpa/src/light_import.rs @@ -538,7 +538,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus pub mod tests { use super::*; use consensus_common::ForkChoiceStrategy; - use primitives::H256; + use primitives::{H256, crypto::Public}; use test_client::client::in_mem::Blockchain as InMemoryAuxStore; use test_client::runtime::{Block, Header}; use crate::tests::TestApi; @@ -637,7 +637,7 @@ pub mod tests { let client = test_client::new_light(); let mut import_data = LightImportData { last_finalized: Default::default(), - authority_set: LightAuthoritySet::genesis(vec![(AuthorityId::from_raw([1; 32]), 1)]), + authority_set: LightAuthoritySet::genesis(vec![(AuthorityId::from_slice(&[1; 32]), 1)]), consensus_changes: ConsensusChanges::empty(), }; let block = BlockImportParams { @@ -688,7 +688,7 @@ pub mod tests { #[test] fn finality_proof_required_when_consensus_data_changes_and_no_justification_provided() { let mut cache = HashMap::new(); - cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_raw([2; 32])].encode()); + cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_slice(&[2; 32])].encode()); assert_eq!(import_block(cache, None), ImportResult::Imported(ImportedAux { clear_justification_requests: false, needs_justification: false, @@ -701,7 +701,7 @@ pub mod tests { fn finality_proof_required_when_consensus_data_changes_and_incorrect_justification_provided() { let justification = TestJustification(false, Vec::new()).encode(); let mut cache = HashMap::new(); - cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_raw([2; 32])].encode()); + cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_slice(&[2; 32])].encode()); assert_eq!( import_block(cache, Some(justification)), ImportResult::Imported(ImportedAux { @@ -717,7 +717,7 @@ pub mod tests { #[test] fn aux_data_updated_on_start() { let aux_store = InMemoryAuxStore::::new(); - let api = Arc::new(TestApi::new(vec![(AuthorityId::from_raw([1; 32]), 1)])); + let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); // when aux store is empty initially assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none()); @@ -732,7 +732,7 @@ pub mod tests { #[test] fn aux_data_loaded_on_restart() { let aux_store = InMemoryAuxStore::::new(); - let api = Arc::new(TestApi::new(vec![(AuthorityId::from_raw([1; 32]), 1)])); + let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); // when aux store is non-empty initially let mut consensus_changes = ConsensusChanges::::empty(); @@ -741,7 +741,9 @@ pub mod tests { &[ ( LIGHT_AUTHORITY_SET_KEY, - LightAuthoritySet::genesis(vec![(AuthorityId::from_raw([42; 32]), 2)]).encode().as_slice(), + LightAuthoritySet::genesis( + vec![(AuthorityId::from_slice(&[42; 32]), 2)] + ).encode().as_slice(), ), ( LIGHT_CONSENSUS_CHANGES_KEY, @@ -753,7 +755,7 @@ pub mod tests { // importer uses it on start let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap(); - assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_raw([42; 32]), 2)]); + assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[42; 32]), 2)]); assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]); } } diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 797463f5dec86..4689e1f23820a 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -37,7 +37,7 @@ use std::result; use parity_codec::Decode; use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::generic::BlockId; -use primitives::{NativeOrEncoded, ExecutionContext}; +use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; use fg_primitives::AuthorityId; use authorities::AuthoritySet; @@ -273,7 +273,7 @@ impl GrandpaApi for RuntimeApi { _: ExecutionContext, _: Option<()>, _: Vec, - ) -> Result>> { + ) -> Result>> { Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native) } @@ -342,11 +342,8 @@ impl AuthoritySetForFinalityChecker for TestApi { const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); -fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(primitives::ed25519::Public, u64)> { - keys.iter() - .map(|key| AuthorityId::from_raw(key.to_raw_public())) - .map(|id| (id, 1)) - .collect() +fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { + keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() } // run the voters to completion. provide a closure to be invoked after @@ -405,7 +402,7 @@ fn run_to_completion_with( config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(key.clone().into())), + local_key: Some(Arc::new(key.clone().pair().into())), name: Some(format!("peer#{}", peer_id)), }, link: link, @@ -482,7 +479,7 @@ fn finalize_3_voters_1_full_observer() { let all_peers = peers.iter() .cloned() - .map(|key| Some(Arc::new(key.into()))) + .map(|key| Some(Arc::new(key.pair().into()))) .chain(::std::iter::once(None)); for (peer_id, local_key) in all_peers.enumerate() { @@ -521,7 +518,7 @@ fn finalize_3_voters_1_full_observer() { } // wait for all finalized on each. - let wait_for = ::futures::future::join_all(finality_notifications) + let wait_for = futures::future::join_all(finality_notifications) .map(|_| ()) .map_err(|_| ()); @@ -640,7 +637,7 @@ fn transition_3_voters_twice_1_full_observer() { .cloned() .collect::>() // deduplicate .into_iter() - .map(|key| Some(Arc::new(key.into()))) + .map(|key| Some(Arc::new(key.pair().into()))) .enumerate(); for (peer_id, local_key) in all_peers { @@ -704,7 +701,7 @@ fn justification_is_emitted_when_consensus_data_changes() { let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3); // import block#1 WITH consensus data change - let new_authorities = vec![primitives::sr25519::Public::from_raw([42; 32])]; + let new_authorities = vec![babe_primitives::AuthorityId::from_slice(&[42; 32])]; net.peer(0).push_authorities_change_block(new_authorities); net.block_until_sync(&mut runtime); let net = Arc::new(Mutex::new(net)); @@ -1095,10 +1092,10 @@ fn voter_persists_its_votes() { config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(peers[0].clone().into())), + local_key: Some(Arc::new(peers[0].clone().pair().into())), name: Some(format!("peer#{}", 0)), }, - link: link, + link, network: net.lock().peers[0].network_service().clone(), inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, @@ -1147,7 +1144,7 @@ fn voter_persists_its_votes() { let config = Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(peers[1].clone().into())), + local_key: Some(Arc::new(peers[1].clone().pair().into())), name: Some(format!("peer#{}", 1)), }; @@ -1320,7 +1317,7 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() { // import block#1 WITH consensus data change. Light client ignores justification // && instead fetches finality proof for block #1 - net.peer(0).push_authorities_change_block(vec![primitives::sr25519::Public::from_raw([42; 32])]); + net.peer(0).push_authorities_change_block(vec![babe_primitives::AuthorityId::from_slice(&[42; 32])]); let net = Arc::new(Mutex::new(net)); run_to_completion(&mut runtime, 1, net.clone(), peers); net.lock().block_until_sync(&mut runtime); @@ -1383,7 +1380,7 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ // normally it will reach light client, but because of the forced change, it will not net.lock().peer(0).push_blocks(8, false); // best is #9 net.lock().peer(0).push_authorities_change_block( - vec![primitives::sr25519::Public::from_raw([42; 32])] + vec![babe_primitives::AuthorityId::from_slice(&[42; 32])] ); // #10 net.lock().peer(0).push_blocks(1, false); // best is #11 net.lock().block_until_sync(&mut runtime); @@ -1425,7 +1422,7 @@ fn voter_catches_up_to_latest_round_when_behind() { local_key, name: Some(format!("peer#{}", peer_id)), }, - link: link, + link, network: net.lock().peer(peer_id).network_service().clone(), inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, @@ -1453,7 +1450,7 @@ fn voter_catches_up_to_latest_round_when_behind() { .for_each(move |_| Ok(())) ); - let voter = voter(Some(Arc::new((*key).into())), peer_id, link, net.clone()); + let voter = voter(Some(Arc::new(key.pair().into())), peer_id, link, net.clone()); runtime.spawn(voter); } From d437907071c0b238c542b2fd64648f97c3921566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Aug 2019 10:32:45 +0200 Subject: [PATCH 34/80] Fix `consensus-aura` --- core/consensus/aura/src/lib.rs | 14 +++++++------- core/test-runtime/src/lib.rs | 16 +++++++++++++--- core/test-runtime/src/system.rs | 3 +-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 28e8d635ddcc9..abe3b4ea12105 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -785,9 +785,9 @@ mod tests { use parking_lot::Mutex; use tokio::runtime::current_thread; use keyring::sr25519::Keyring; - use primitives::sr25519; use client::{LongestChain, BlockchainEvents}; use test_client; + use aura_primitives::sr25519::AuthorityPair; type Error = client::error::Error; @@ -835,7 +835,7 @@ mod tests { impl TestNetFactory for AuraTestNet { type Specialization = DummySpecialization; - type Verifier = AuraVerifier; + type Verifier = AuraVerifier; type PeerData = (); /// Create new test network with peers and given config. @@ -919,9 +919,9 @@ mod tests { &inherent_data_providers, slot_duration.get() ).expect("Registers aura inherent data provider"); - let aura = start_aura::<_, _, _, _, _, sr25519::Pair, _, _, _>( + let aura = start_aura::<_, _, _, _, _, AuthorityPair, _, _, _>( slot_duration, - Arc::new(key.clone().into()), + Arc::new(key.clone().pair().into()), client.clone(), select_chain, client, @@ -949,9 +949,9 @@ mod tests { assert_eq!(client.info().chain.best_number, 0); assert_eq!(authorities(&client, &BlockId::Number(0)).unwrap(), vec![ - Keyring::Alice.into(), - Keyring::Bob.into(), - Keyring::Charlie.into() + Keyring::Alice.public().into(), + Keyring::Bob.public().into(), + Keyring::Charlie.public().into() ]); } } diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 69d88720b3807..ec4131e4ae70a 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -52,7 +52,7 @@ use cfg_if::cfg_if; // Ensure Babe and Aura use the same crypto to simplify things a bit. pub use babe_primitives::AuthorityId; -pub type AuraId = AuthorityId; +pub type AuraId = aura_primitives::sr25519::AuthorityId; // Inlucde the WASM binary #[cfg(feature = "std")] @@ -544,7 +544,12 @@ cfg_if! { impl aura_primitives::AuraApi for Runtime { fn slot_duration() -> u64 { 1000 } - fn authorities() -> Vec { system::authorities() } + fn authorities() -> Vec { + system::authorities().into_iter().map(|a| { + let authority: sr25519::Public = a.into(); + AuraId::from(authority) + }).collect() + } } impl babe_primitives::BabeApi for Runtime { @@ -735,7 +740,12 @@ cfg_if! { impl aura_primitives::AuraApi for Runtime { fn slot_duration() -> u64 { 1000 } - fn authorities() -> Vec { system::authorities() } + fn authorities() -> Vec { + system::authorities().into_iter().map(|a| { + let authority: sr25519::Public = a.into(); + AuraId::from(authority) + }).collect() + } } impl babe_primitives::BabeApi for Runtime { diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index 30cd10532879d..ad774e787c532 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -274,8 +274,7 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyResult { } fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyResult { - let new_authorities: Vec = new_authorities.iter().cloned().collect(); - ::put(new_authorities); + NewAuthorities::put(new_authorities.to_vec()); Ok(ApplyOutcome::Success) } From 79d150c26af80192cc188a7bc5d2ec0509b20050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Aug 2019 11:25:02 +0200 Subject: [PATCH 35/80] Fix cli --- core/cli/src/params.rs | 9 +++++---- node-template/src/service.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index b779f278c327f..6f92e8c9b4de8 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -426,14 +426,14 @@ pub struct RunCmd { /// Use interactive shell for entering the password used by the keystore. #[structopt( long = "password-interactive", - raw(conflicts_with_all = "&[ \"password\", \"password-filename\" ]") + raw(conflicts_with_all = "&[ \"password\", \"password_filename\" ]") )] pub password_interactive: bool, /// Password used by the keystore. #[structopt( long = "password", - raw(conflicts_with_all = "&[ \"password-interactive\", \"password-filename\" ]") + raw(conflicts_with_all = "&[ \"password_interactive\", \"password_filename\" ]") )] pub password: Option, @@ -442,7 +442,7 @@ pub struct RunCmd { long = "password-filename", value_name = "PATH", parse(from_os_str), - raw(conflicts_with_all = "&[ \"password-interactive\", \"password\" ]") + raw(conflicts_with_all = "&[ \"password_interactive\", \"password\" ]") )] pub password_filename: Option } @@ -463,7 +463,7 @@ lazy_static::lazy_static! { let conflicts_with = keyring::Sr25519Keyring::iter() .filter(|b| a != *b) .map(|b| b.to_string().to_lowercase()) - .chain(["name", "key"].iter().map(ToString::to_string)) + .chain(std::iter::once("name".to_string())) .collect::>(); let name = a.to_string().to_lowercase(); @@ -505,6 +505,7 @@ impl AugmentClap for Keyring { .long(&a.name) .help(&a.help) .conflicts_with_all(&conflicts_with_strs) + .requires("dev") .takes_value(false) ) }) diff --git a/node-template/src/service.rs b/node-template/src/service.rs index fdc1e9b84e93a..7a0f2522b4373 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -68,7 +68,7 @@ construct_service_factory! { }, AuthoritySetup = { |service: Self::FullService| { - if let Some(key) = service.authority_key() { + if let Some(key) = None:: /* service.authority_key() */ { info!("Using authority key {}", key.public()); let proposer = ProposerFactory { client: service.client(), From e41608b8b49f9bb649c459405a2e2fa0b250f04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Aug 2019 11:40:58 +0200 Subject: [PATCH 36/80] Fix `node-cli` --- node/cli/src/chain_spec.rs | 13 +++++++++++-- node/cli/src/service.rs | 6 +++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 11efb49d6ae05..0cd77ffc60e5e 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -354,7 +354,7 @@ pub(crate) mod tests { vec![ get_authority_keys_from_seed("Alice"), ], - get_from_seed("Alice"), + get_from_seed::("Alice"), None, false, ) @@ -376,7 +376,16 @@ pub(crate) mod tests { /// Local testnet config (multivalidator Alice + Bob) pub fn integration_test_config_with_two_authorities() -> ChainSpec { - ChainSpec::from_genesis("Integration Test", "test", local_testnet_genesis, vec![], None, None, None, None) + ChainSpec::from_genesis( + "Integration Test", + "test", + local_testnet_genesis, + vec![], + None, + None, + None, + None, + ) } #[test] diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 0f19b75395ca1..9a2ec6a7a1b74 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -346,7 +346,7 @@ mod tests { fn test_sync() { let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); - let alice = Arc::new(Sr25519Keyring::Alice.pair()); + let alice = Sr25519Keyring::Alice.pair(); let mut slot_num = 1u64; let block_factory = |service: &SyncService<::FullService>| { let service = service.get(); @@ -375,7 +375,7 @@ mod tests { &*service.client(), &parent_id, slot_num, - &alice, + &alice.clone().into(), (278, 1000), ) { break babe_pre_digest; @@ -400,7 +400,7 @@ mod tests { let to_sign = pre_hash.encode(); let signature = alice.sign(&to_sign[..]); let item = ::babe_seal( - signature, + signature.into(), ); slot_num += 1; From 77668e506238e5bcbebde550815efc6a39b8549d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Aug 2019 11:53:40 +0200 Subject: [PATCH 37/80] Fix chain_spec builder --- node/cli/src/chain_spec.rs | 2 +- test-utils/chain-spec-builder/src/main.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 0cd77ffc60e5e..580610d6ff516 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -17,7 +17,7 @@ //! Substrate chain configurations. use primitives::{Pair, Public, crypto::UncheckedInto}; -use node_primitives::{AccountId, Balance}; +pub use node_primitives::{AccountId, Balance}; use node_runtime::{ BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, Perbill, diff --git a/test-utils/chain-spec-builder/src/main.rs b/test-utils/chain-spec-builder/src/main.rs index 211e8321e3fd1..13b4cc38a1646 100644 --- a/test-utils/chain-spec-builder/src/main.rs +++ b/test-utils/chain-spec-builder/src/main.rs @@ -1,6 +1,6 @@ use clap::{App, load_yaml}; -use node_cli::chain_spec; +use node_cli::chain_spec::{self, AccountId}; use substrate_service::chain_ops::build_spec; fn genesis_constructor() -> chain_spec::GenesisConfig { @@ -13,11 +13,11 @@ fn genesis_constructor() -> chain_spec::GenesisConfig { let endowed_accounts = matches.values_of("endowed_account_seed") .unwrap() - .map(chain_spec::get_account_id_from_seed) + .map(chain_spec::get_from_seed::) .collect(); let sudo_key_seed = matches.value_of("sudo_key_seed").unwrap(); - let sudo_key = chain_spec::get_account_id_from_seed(sudo_key_seed); + let sudo_key = chain_spec::get_from_seed::(sudo_key_seed); let enable_println = true; From 51677a88226a9a6e3d75bb9e2e195b2b1cca33ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 1 Aug 2019 12:03:30 +0200 Subject: [PATCH 38/80] Fix doc tests --- core/primitives/src/crypto.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 6966d613b88e8..00b1421cdc0e2 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -833,8 +833,8 @@ macro_rules! impl_as_ref_mut { /// where . /// /// ```rust -/// impl_wrapper! { -/// pub struct Outer(Inner); +/// substrate_primitives::wrap! { +/// pub struct Wrapper(u32); /// } /// ``` #[macro_export] @@ -880,9 +880,10 @@ macro_rules! wrap { /// Application-specific types whose identifier is `$key_type`. /// /// ```rust +///# use substrate_primitives::{app_crypto, wrap, ed25519, crypto::KeyTypeId}; /// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` /// // of value `b"fuba"`. -/// app_crypto!(ed25519, *b"fuba"); +/// app_crypto!(ed25519, KeyTypeId(*b"_uba")); /// ``` #[macro_export] macro_rules! app_crypto { From 3ca64cdba139454c64d65ee41736f472ab3cd5b4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 3 Aug 2019 12:42:22 +0200 Subject: [PATCH 39/80] Add authority getter for grandpa. --- Cargo.lock | 1 + core/finality-grandpa/Cargo.toml | 1 + core/finality-grandpa/src/lib.rs | 50 +++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9d9ae4a5e158..884d0908da3a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4523,6 +4523,7 @@ dependencies = [ "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index b395257b2fa24..3b0d7391ce9d1 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -18,6 +18,7 @@ sr-primitives = { path = "../sr-primitives" } consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } primitives = { package = "substrate-primitives", path = "../primitives" } substrate-telemetry = { path = "../telemetry" } +substrate-keystore = { path = "../keystore" } serde_json = "1.0" client = { package = "substrate-client", path = "../client" } inherents = { package = "substrate-inherents", path = "../../core/inherents" } diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 64ee4d23beb55..31505ae474be9 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -55,16 +55,20 @@ use futures::prelude::*; use log::{debug, info, warn}; use futures::sync::mpsc; -use client::{BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError}; +use client::{ + BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError, BlockOf, + blockchain::ProvideCache +}; use client::blockchain::HeaderBackend; -use parity_codec::Encode; +use parity_codec::{Encode, Decode}; use sr_primitives::generic::BlockId; use sr_primitives::traits::{ - NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi, + NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi }; use fg_primitives::{GrandpaApi, AuthorityPair}; +use substrate_keystore::Store; use inherents::InherentDataProviders; -use consensus_common::SelectChain; +use consensus_common::{SelectChain, well_known_cache_keys, Error as ConsensusError}; use primitives::{H256, Pair, Blake2Hasher}; use substrate_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG, CONSENSUS_WARN}; use serde_json; @@ -777,3 +781,41 @@ pub fn run_grandpa, N, RA, SC, X>( { run_grandpa_voter(grandpa_params) } + +/// Provide a list of authority keys that is current as of a given block. +#[allow(deprecated)] +fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result, ConsensusError> +where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: GrandpaApi<::Type> +{ + client + .cache() + .and_then(|cache| cache + .get_at(&well_known_cache_keys::AUTHORITIES, at) + .and_then(|v| Decode::decode(&mut &v[..])) + ) + .or_else(|| GrandpaApi::grandpa_authorities(&*client.runtime_api(), at).ok() + .map(|authorities| authorities.into_iter().map(|x| x.0).collect()) + ) + .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) +} + +/// Provide the authority key, if any, that is controlled by this node as of the given block. +fn authority(client: &C, keystore: Arc) -> Option where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: GrandpaApi<::Type> +{ + let owned = keystore.public_keys::().ok()?; + let at = BlockId::Number(client.info().best_number); + // The list of authority keys that is current. By default this will just use the state of + // the best block, but you might want it to use some other block's state instead if it's + // more sophisticated. Grandpa, for example, will probably want to use the state of the last + // finalised block. + let authorities = authorities_at::(client, &at).ok()?; + let maybe_pub = owned.into_iter() + .find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) +} From 2f7055fa1d3291fa2f0aa283fda794903c231e51 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 3 Aug 2019 13:36:32 +0200 Subject: [PATCH 40/80] Test fix --- core/service/src/lib.rs | 6 ++++-- node/cli/src/service.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 3e252848a0137..a9fdc8af0ae58 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -886,6 +886,8 @@ impl network::TransactionPool, ComponentBlock< /// # use node_runtime::{GenesisConfig, RuntimeApi}; /// # use std::sync::Arc; /// # use node_primitives::Block; +/// # use babe_primitives::AuthorityPair as BabePair; +/// # use grandpa_primitives::AuthorityPair as GrandpaPair; /// # use sr_primitives::Justification; /// # use sr_primitives::traits::Block as BlockT; /// # use grandpa; @@ -913,8 +915,8 @@ impl network::TransactionPool, ComponentBlock< /// struct Factory { /// // Declare the block type /// Block = Block, -/// ConsensusPair = primitives::ed25519::Pair, -/// FinalityPair = primitives::ed25519::Pair, +/// ConsensusPair = BabePair, +/// FinalityPair = GrandpaPair, /// RuntimeApi = RuntimeApi, /// // Declare the network protocol and give an initializer. /// NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 73fcb5cba1730..afc361796a11e 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -23,11 +23,11 @@ use std::time::Duration; use babe::{import_queue, start_babe, BabeImportQueue, Config}; use babe_primitives::AuthorityPair as BabePair; +use grandpa_primitives::AuthorityPair as GrandpaPair; use client::{self, LongestChain}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use node_executor; use primitives::Pair; -use grandpa_primitives::AuthorityPair as GrandpaPair; use futures::prelude::*; use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; From 7638de24c69427b397355b4a91e0a2383781f0ca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 3 Aug 2019 14:38:24 +0200 Subject: [PATCH 41/80] Fixes --- Cargo.lock | 2 ++ core/service/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 884d0908da3a9..e1c4f4185702b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4799,9 +4799,11 @@ dependencies = [ "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", "substrate-consensus-common 2.0.0", "substrate-executor 2.0.0", "substrate-finality-grandpa 2.0.0", + "substrate-finality-grandpa-primitives 2.0.0", "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-offchain 2.0.0", diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 4ce3facb52372..b0f95e4e64b9d 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -40,4 +40,6 @@ substrate-test-runtime-client = { path = "../test-runtime/client" } node-executor = { path = "../../node/executor" } node-primitives = { path = "../../node/primitives" } node-runtime = { path = "../../node/runtime" } +babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives" } grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" } +grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" } From f698f9892db18875c76d1c1acb572c628cb8fa54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 3 Aug 2019 10:43:37 +0200 Subject: [PATCH 42/80] Make keystore accessible from the runtime --- Cargo.lock | 41 +++++- core/client/db/src/lib.rs | 3 +- core/client/src/call_executor.rs | 22 +++- core/client/src/client.rs | 6 +- core/client/src/genesis.rs | 6 + core/client/src/lib.rs | 3 +- core/client/src/light/call_executor.rs | 2 + core/client/src/light/fetcher.rs | 1 - core/client/src/light/mod.rs | 2 +- core/consensus/rhd/src/misbehaviour_check.rs | 2 +- core/executor/src/wasm_executor.rs | 106 ++++++++++++++- core/executor/src/wasm_utils.rs | 25 +++- core/keystore/src/lib.rs | 41 +++++- core/offchain/src/api.rs | 74 ++--------- core/offchain/src/lib.rs | 20 +-- core/primitives/Cargo.toml | 2 +- core/primitives/src/crypto.rs | 9 +- core/primitives/src/ed25519.rs | 38 ++++-- core/primitives/src/lib.rs | 4 +- core/primitives/src/sr25519.rs | 22 +++- core/primitives/src/traits.rs | 46 +++++++ core/service/Cargo.toml | 2 +- core/service/src/components.rs | 42 ++++-- core/service/src/lib.rs | 42 +++--- core/sr-api-macros/tests/runtime_calls.rs | 1 + core/sr-io/src/lib.rs | 50 +++++-- core/sr-io/with_std.rs | 59 ++++++++- core/sr-io/without_std.rs | 129 +++++++++++++++++-- core/state-machine/Cargo.toml | 2 +- core/state-machine/src/basic.rs | 7 +- core/state-machine/src/ext.rs | 35 +++-- core/state-machine/src/lib.rs | 127 ++++++++++++------ core/state-machine/src/overlayed_changes.rs | 1 + core/state-machine/src/testing.rs | 11 +- core/test-client/src/lib.rs | 22 ++-- core/test-runtime/client/src/lib.rs | 13 +- 36 files changed, 759 insertions(+), 259 deletions(-) create mode 100644 core/primitives/src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index e1c4f4185702b..88c605c4cf4f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,6 +2010,14 @@ dependencies = [ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -2705,6 +2713,16 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.2.14" @@ -2755,6 +2773,20 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "paste" version = "0.1.5" @@ -4695,7 +4727,7 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4791,7 +4823,7 @@ dependencies = [ "node-runtime 2.0.0", "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4856,7 +4888,7 @@ dependencies = [ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-panic-handler 2.0.0", "substrate-primitives 2.0.0", "substrate-trie 2.0.0", @@ -6183,6 +6215,7 @@ dependencies = [ "checksum linked_hash_set 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7c91c4c7bbeb4f2f7c4e5be11e6a05bd6830bc37249c47ce1ad86ad453ff9c" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" +"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" @@ -6236,10 +6269,12 @@ dependencies = [ "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79" "checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index b22ffc50b5b63..e4c173292650a 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -195,6 +195,7 @@ pub fn new_client( executor: E, genesis_storage: S, execution_strategies: ExecutionStrategies, + keystore: Option, ) -> Result< client::Client, client::LocalCallExecutor, E>, Block, RA>, client::error::Error @@ -205,7 +206,7 @@ pub fn new_client( S: BuildStorage, { let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?); - let executor = client::LocalCallExecutor::new(backend.clone(), executor); + let executor = client::LocalCallExecutor::new(backend.clone(), executor, keystore); Ok(client::Client::new(backend, executor, genesis_storage, execution_strategies)?) } diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 1b41cc3aa38eb..643cbaecabb26 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -150,14 +150,20 @@ where pub struct LocalCallExecutor { backend: Arc, executor: E, + keystore: Option, } impl LocalCallExecutor { /// Creates new instance of local call executor. - pub fn new(backend: Arc, executor: E) -> Self { + pub fn new( + backend: Arc, + executor: E, + keystore: Option, + ) -> Self { LocalCallExecutor { backend, executor, + keystore, } } } @@ -167,6 +173,7 @@ impl Clone for LocalCallExecutor where E: Clone { LocalCallExecutor { backend: self.backend.clone(), executor: self.executor.clone(), + keystore: self.keystore.clone(), } } } @@ -197,6 +204,7 @@ where &self.executor, method, call_data, + self.keystore.clone(), ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( strategy.get_manager(), false, @@ -262,6 +270,7 @@ where &self.executor, method, call_data, + self.keystore.clone(), ) .execute_using_consensus_failure_handler( execution_manager, @@ -279,6 +288,7 @@ where &self.executor, method, call_data, + self.keystore.clone(), ) .execute_using_consensus_failure_handler( execution_manager, @@ -293,7 +303,13 @@ where fn runtime_version(&self, id: &BlockId) -> error::Result { let mut overlay = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; - let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage(), NeverOffchainExt::new()); + let mut ext = Ext::new( + &mut overlay, + &state, + self.backend.changes_trie_storage(), + NeverOffchainExt::new(), + None, + ); self.executor.runtime_version(&mut ext).ok_or(error::Error::VersionInvalid.into()) } @@ -327,6 +343,7 @@ where &self.executor, method, call_data, + self.keystore.clone(), ).execute_using_consensus_failure_handler( manager, true, @@ -353,6 +370,7 @@ where &self.executor, method, call_data, + self.keystore.clone(), ) .map_err(Into::into) } diff --git a/core/client/src/client.rs b/core/client/src/client.rs index ac653e1c2bae9..b5c60cea22358 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -253,6 +253,7 @@ impl PrePostHeader { pub fn new_in_mem( executor: E, genesis_storage: S, + keystore: Option, ) -> error::Result, LocalCallExecutor, E>, @@ -263,7 +264,7 @@ pub fn new_in_mem( S: BuildStorage, Block: BlockT, { - new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage) + new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage, keystore) } /// Create a client with the explicitly provided backend. @@ -272,6 +273,7 @@ pub fn new_with_backend( backend: Arc, executor: E, build_genesis_storage: S, + keystore: Option, ) -> error::Result, Block, RA>> where E: CodeExecutor + RuntimeInfo, @@ -279,7 +281,7 @@ pub fn new_with_backend( Block: BlockT, B: backend::LocalBackend { - let call_executor = LocalCallExecutor::new(backend.clone(), executor); + let call_executor = LocalCallExecutor::new(backend.clone(), executor, keystore); Client::new(backend, call_executor, build_genesis_storage, Default::default()) } diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index ad52c0cfa7c10..095306851dc7d 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -96,6 +96,7 @@ mod tests { &executor(), "Core_initialize_block", &header.encode(), + None, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -109,6 +110,7 @@ mod tests { &executor(), "BlockBuilder_apply_extrinsic", &tx.encode(), + None, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -122,6 +124,7 @@ mod tests { &executor(), "BlockBuilder_finalize_block", &[], + None, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -170,6 +173,7 @@ mod tests { &executor(), "Core_execute_block", &b1data, + None, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -200,6 +204,7 @@ mod tests { &executor(), "Core_execute_block", &b1data, + None, ).execute( ExecutionStrategy::AlwaysWasm, ).unwrap(); @@ -230,6 +235,7 @@ mod tests { &executor(), "Core_execute_block", &b1data, + None, ).execute( ExecutionStrategy::NativeElseWasm, ); diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index fa0003e2f57fb..ba5f316d0c6d6 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -62,7 +62,8 @@ //! backend.clone(), //! LocalCallExecutor::new( //! backend.clone(), -//! NativeExecutor::::new(None) +//! NativeExecutor::::new(None), +//! None, //! ), //! // This parameter provides the storage for the chain genesis. //! <(StorageOverlay, ChildrenStorageOverlay)>::default(), diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index 5cd630ed797a8..cf5aaadcb0770 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -463,6 +463,7 @@ pub fn check_execution_proof( executor, "Core_initialize_block", &next_block.encode(), + None, )?; // execute method @@ -472,6 +473,7 @@ pub fn check_execution_proof( executor, &request.method, &request.call_data, + None, )?; Ok(local_result) diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index b83907c932c5f..48bc8ffa0d04f 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -424,7 +424,6 @@ impl FetchChecker for LightDataChecker, body: Vec ) -> ClientResult> { - // TODO: #2621 let extrinsics_root = HashFor::::ordered_trie_root(body.iter().map(Encode::encode)); if *request.header.extrinsics_root() == extrinsics_root { diff --git a/core/client/src/light/mod.rs b/core/client/src/light/mod.rs index 69ba4d9f73ce3..89d3c60ddc372 100644 --- a/core/client/src/light/mod.rs +++ b/core/client/src/light/mod.rs @@ -73,7 +73,7 @@ pub fn new_light( E: CodeExecutor + RuntimeInfo, { let remote_executor = RemoteCallExecutor::new(backend.blockchain().clone(), fetcher); - let local_executor = LocalCallExecutor::new(backend.clone(), code_executor); + let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, None); let executor = RemoteOrLocalCallExecutor::new(backend.clone(), remote_executor, local_executor); Client::new(backend, executor, genesis_storage, Default::default()) } diff --git a/core/consensus/rhd/src/misbehaviour_check.rs b/core/consensus/rhd/src/misbehaviour_check.rs index e40311c14f323..bde3976c19b09 100644 --- a/core/consensus/rhd/src/misbehaviour_check.rs +++ b/core/consensus/rhd/src/misbehaviour_check.rs @@ -26,7 +26,7 @@ use runtime_io; fn check_message_sig( message: Message, signature: &Signature, - from: &AuthorityId + from: &AuthorityId, ) -> bool { let msg: Vec = message.encode(); runtime_io::ed25519_verify(&signature.0, &msg, from) diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 8512d4817d377..3f780a4db1fc2 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -27,11 +27,10 @@ use wasmi::{ use state_machine::{Externalities, ChildStorageKey}; use crate::error::{Error, Result}; use parity_codec::Encode; -use primitives::{blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair}; -use primitives::offchain; -use primitives::hexdisplay::HexDisplay; -use primitives::sandbox as sandbox_primitives; -use primitives::{H256, Blake2Hasher}; +use primitives::{ + blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair, crypto::KeyTypeId, + offchain, hexdisplay::HexDisplay, sandbox as sandbox_primitives, H256, Blake2Hasher, +}; use trie::{TrieConfiguration, trie_types::Layout}; use crate::sandbox; use crate::allocator; @@ -641,7 +640,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_keccak_256")?; Ok(()) }, - ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => { + ext_ed25519_verify( + msg_data: *const u8, + msg_len: u32, + sig_data: *const u8, + pubkey_data: *const u8, + ) -> u32 => { let mut sig = [0u8; 64]; this.memory.get_into(sig_data, &mut sig[..]) .map_err(|_| "Invalid attempt to get signature in ext_ed25519_verify")?; @@ -657,7 +661,54 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, 5 }) }, - ext_sr25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => { + ext_ed25519_generate(id_data: *const u8, out: *mut u8) => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_ed25519_generate")?; + let key_type = KeyTypeId(id); + + let pubkey = runtime_io::ed25519_generate(key_type); + + this.memory.set(out, pubkey.as_ref()) + .map_err(|_| "Invalid attempt to set out in ext_ed25519_generate".into()) + }, + ext_ed25519_sign( + id_data: *const u8, + pubkey_data: *const u8, + msg_data: *const u8, + msg_len: u32, + out: *mut u8, + ) -> u32 => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_ed25519_sign")?; + let key_type = KeyTypeId(id); + + let mut pubkey = [0u8; 32]; + this.memory.get_into(pubkey_data, &mut pubkey[..]) + .map_err(|_| "Invalid attempt to get pubkey in ext_ed25519_sign")?; + + let msg = this.memory.get(msg_data, msg_len as usize) + .map_err(|_| "Invalid attempt to get message in ext_ed25519_sign")?; + + let signature = runtime_io::ed25519_sign(key_type, &pubkey, &msg); + + match signature { + Some(signature) => { + this.memory + .set(out, signature.as_ref()) + .map_err(|_| "Invalid attempt to set out in ext_ed25519_sign")?; + Ok(0) + }, + None => Ok(1), + } + }, + ext_sr25519_verify( + msg_data: *const u8, + msg_len: u32, + sig_data: *const u8, + pubkey_data: *const u8, + ) -> u32 => { let mut sig = [0u8; 64]; this.memory.get_into(sig_data, &mut sig[..]) .map_err(|_| "Invalid attempt to get signature in ext_sr25519_verify")?; @@ -673,6 +724,47 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, 5 }) }, + ext_sr25519_generate(id_data: *const u8, out: *mut u8) => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_sr25519_generate")?; + let key_type = KeyTypeId(id); + + let pubkey = runtime_io::sr25519_generate(key_type); + + this.memory.set(out, pubkey.as_ref()) + .map_err(|_| "Invalid attempt to set out in ext_sr25519_generate".into()) + }, + ext_sr25519_sign( + id_data: *const u8, + pubkey_data: *const u8, + msg_data: *const u8, + msg_len: u32, + out: *mut u8, + ) -> u32 => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_sr25519_sign")?; + let key_type = KeyTypeId(id); + + let mut pubkey = [0u8; 32]; + this.memory.get_into(pubkey_data, &mut pubkey[..]) + .map_err(|_| "Invalid attempt to get pubkey in ext_sr25519_sign")?; + + let msg = this.memory.get(msg_data, msg_len as usize) + .map_err(|_| "Invalid attempt to get message in ext_sr25519_sign")?; + + let signature = runtime_io::sr25519_sign(key_type, &pubkey, &msg); + + match signature { + Some(signature) => { + this.memory.set(out, signature.as_ref()) + .map_err(|_| "Invalid attempt to set out in ext_sr25519_sign")?; + Ok(0) + }, + None => Ok(1), + } + }, ext_secp256k1_ecdsa_recover(msg_data: *const u8, sig_data: *const u8, pubkey_data: *mut u8) -> u32 => { let mut sig = [0u8; 65]; this.memory.get_into(sig_data, &mut sig[..]) diff --git a/core/executor/src/wasm_utils.rs b/core/executor/src/wasm_utils.rs index 47867f7b4849b..80ef376df5212 100644 --- a/core/executor/src/wasm_utils.rs +++ b/core/executor/src/wasm_utils.rs @@ -217,9 +217,15 @@ macro_rules! dispatch_fn { /// Implements `wasmi::Externals` trait and `Resolver` for given struct. #[macro_export] macro_rules! impl_function_executor { - ( $objectname:ident : $structname:ty, - $( $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt , )* - => $($pre:tt)+ ) => ( + ( + $objectname:ident : $structname:ty, + $( + $name:ident + ( $( $names:ident : $params:ty ),* $(,)? ) + $( -> $returns:ty )? => { $( $body:tt )* }, + )* + => $( $pre:tt )+ + ) => ( impl $( $pre ) + $structname { #[allow(unused)] fn resolver() -> &'static dyn $crate::wasmi::ModuleImportResolver { @@ -230,7 +236,11 @@ macro_rules! impl_function_executor { name: &str, signature: &$crate::wasmi::Signature ) -> std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> { - resolve_fn!(signature, name, $( $name( $( $params ),* ) $( -> $returns )* => )*); + resolve_fn!( + signature, + name, + $( $name( $( $params ),* ) $( -> $returns )? => )* + ); Err($crate::wasmi::Error::Instantiation( format!("Export {} not found", name), @@ -249,7 +259,12 @@ macro_rules! impl_function_executor { ) -> std::result::Result, $crate::wasmi::Trap> { let $objectname = self; let mut args = args.as_ref().iter(); - dispatch_fn!(index, $objectname, args, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*); + dispatch_fn! { + index, + $objectname, + args, + $( $name( $( $names : $params ),* ) $( -> $returns )? => { $( $body )* } ),* + }; } } ); diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 7aaafaf5771fd..f60b55fd84f27 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -20,8 +20,9 @@ use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}}; -use primitives::crypto::{ - KeyTypeId, AppPublic, AppKey, AppPair, Pair as PairT, Public, IsWrappedBy, Protected, +use primitives::{ + crypto::{KeyTypeId, AppPublic, AppKey, AppPair, Pair as PairT, Public, IsWrappedBy, Protected}, + traits::KeyStore, ed25519, sr25519, }; /// Keystore error. @@ -216,6 +217,42 @@ impl Store { } } +impl KeyStore for Store { + fn sr25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result<[u8; 32], String> { + let pair = match seed { + Some(seed) => self.generate_from_seed_by_type::(seed, id), + None => self.generate_by_type::(id), + }.map_err(|e| e.to_string())?; + + Ok(pair.public().into()) + } + + fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { + self.key_pair_by_type::(pub_key, id).ok() + } + + fn ed25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result<[u8; 32], String> { + let pair = match seed { + Some(seed) => self.generate_from_seed_by_type::(seed, id), + None => self.generate_by_type::(id), + }.map_err(|e| e.to_string())?; + + Ok(pair.public().into()) + } + + fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { + self.key_pair_by_type::(pub_key, id).ok() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index be1b4e0ea80b7..dfc42829bbd4a 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -33,7 +33,7 @@ use primitives::offchain::{ CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use primitives::{ed25519, sr25519}; +use primitives::{ed25519, sr25519, traits::KeyStorePtr}; use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; @@ -89,7 +89,7 @@ impl KnownCryptoKey { pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, - keystore: Arc>, + keystore: Option, network_state: Arc, at: BlockId, } @@ -107,10 +107,7 @@ fn log_error(err: keystore::Error) -> () { const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; const STORAGE_PREFIX: &[u8] = b"storage"; -impl Api where - Storage: OffchainStorage, - Block: traits::Block, -{ +impl Api where Storage: OffchainStorage, Block: traits::Block { fn check_allowed(&self, key_type: &KeyTypeId) -> Result<(), ()> { let blacklist = vec![ crypto::key_types::SR25519, @@ -134,38 +131,8 @@ impl Api where key_type: KeyTypeId, ) -> Result, ()> { self.check_allowed(&key_type)?; - - let keystore = (&*self.keystore).as_ref().ok_or(())?; - match kind { - CryptoKind::Sr25519 => { - Ok(keystore.public_keys_by_type::(key_type) - .map_err(log_error)? - .into_iter() - .map(|key| CryptoKey { - public: key.to_raw_vec(), - key_type, - kind, - }).collect()) - }, - CryptoKind::Ed25519 => { - Ok(keystore.public_keys_by_type::(key_type) - .map_err(log_error)? - .into_iter() - .map(|key| CryptoKey { - public: key.to_raw_vec(), - key_type, - kind, - }).collect()) - }, - CryptoKind::User => { - unavailable_yet::<()>("custom crypto"); - Err(()) - }, - CryptoKind::Dummy => { - unavailable_yet::<()>("dummy crypto"); - Err(()) - }, - } + unavailable_yet::<()>("keys"); + Err(()) } fn get_key( @@ -174,31 +141,8 @@ impl Api where ) -> Result { self.check_allowed(&key.key_type)?; - // TODO [ToDr] Remove - let keystore = (&*self.keystore).as_ref().ok_or(())?; - - match key.kind { - CryptoKind::Sr25519 => { - let public = sr25519::Public::from_slice(&key.public); - keystore.key_pair_by_type(&public, key.key_type) - .map_err(log_error) - .map(KnownCryptoKey::Sr25519) - }, - CryptoKind::Ed25519 => { - let public = ed25519::Public::from_slice(&key.public); - keystore.key_pair_by_type(&public, key.key_type) - .map_err(log_error) - .map(KnownCryptoKey::Ed25519) - }, - CryptoKind::User => { - unavailable_yet::<()>("custom crypto"); - Err(()) - }, - CryptoKind::Dummy => { - unavailable_yet::<()>("dummy crypto"); - Err(()) - }, - } + unavailable_yet::<()>("get key"); + Err(()) } } @@ -447,7 +391,7 @@ impl AsyncApi { pub fn new( transaction_pool: Arc>, db: S, - keystore: Arc>, + keystore: Option, at: BlockId, network_state: Arc, ) -> (Api, AsyncApi) { @@ -534,7 +478,7 @@ mod tests { AsyncApi::new( pool, db, - Arc::new(None), + None, BlockId::Number(Zero::zero()), mock, ) diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index d9818dc767e42..d683127120293 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -44,7 +44,7 @@ use futures::future::Future; use keystore::Store as Keystore; use log::{debug, warn}; use network::NetworkStateInfo; -use primitives::ExecutionContext; +use primitives::{ExecutionContext, traits::KeyStorePtr}; use sr_primitives::{ generic::BlockId, traits::{self, ProvideRuntimeApi}, @@ -58,14 +58,10 @@ pub mod testing; pub use offchain_primitives::OffchainWorkerApi; /// An offchain workers manager. -pub struct OffchainWorkers< - Client, - Storage, - Block: traits::Block, -> { +pub struct OffchainWorkers { client: Arc, db: Storage, - keystore: Arc>, + keystore: Option, _block: PhantomData, } @@ -75,11 +71,7 @@ impl OffchainWorkers< Block, > { /// Creates new `OffchainWorkers`. - pub fn new( - client: Arc, - db: Storage, - keystore: Arc>, - ) -> Self { + pub fn new(client: Arc, db: Storage, keystore: Option) -> Self { Self { client, db, @@ -196,10 +188,8 @@ mod tests { let db = client_db::offchain::LocalStorage::new_test(); let network_state = Arc::new(MockNetworkStateInfo()); // TODO Test keystore - let keystore = Arc::new(None); - // when - let offchain = OffchainWorkers::new(client, db, keystore); + let offchain = OffchainWorkers::new(client, db, None); runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone())); // then diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index d0cdf34141b1a..cc575077ad467 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -29,7 +29,7 @@ regex = { version = "1.1", optional = true } num-traits = { version = "0.2", default-features = false } zeroize = { version = "0.9.2", default-features = false } lazy_static = { version = "1.3", optional = true } -parking_lot = { version = "0.8", optional = true } +parking_lot = { version = "0.9.0", optional = true } [dev-dependencies] substrate-serializer = { path = "../serializer" } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 00b1421cdc0e2..b6c2a5baf89f1 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -935,7 +935,7 @@ macro_rules! app_crypto { >( seed: &str, password: Option<&str>, - path: I + path: I, ) -> Result { <$pair>::from_standard_components::(seed, password, path).map(Self) } @@ -945,14 +945,14 @@ macro_rules! app_crypto { fn verify, M: AsRef<[u8]>>( sig: &Self::Signature, message: M, - pubkey: P + pubkey: P, ) -> bool { <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) } fn verify_weak, M: AsRef<[u8]>>( sig: &[u8], message: M, - pubkey: P + pubkey: P, ) -> bool { <$pair>::verify_weak(sig, message, pubkey) } @@ -1030,6 +1030,7 @@ macro_rules! app_crypto { #[cfg(feature="std")] type Pair = Pair; } + impl $crate::crypto::Public for Public { fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } } @@ -1047,7 +1048,7 @@ macro_rules! app_crypto { type Generic = $public; } - $crate::wrap!{ + $crate::wrap! { /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. #[derive(Clone, Default, Eq, PartialEq, $crate::Encode, $crate::Decode)] #[cfg_attr(feature = "std", derive(Debug, Hash))] diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 213bfa8843ffb..a44bf8409fb5a 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -79,6 +79,20 @@ impl AsMut<[u8]> for Public { } } +impl rstd::convert::TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 32 { + let mut inner = [0u8; 32]; + inner.copy_from_slice(data); + Ok(Public(inner)) + } else { + Err(()) + } + } +} + impl From for [u8; 32] { fn from(x: Public) -> Self { x.0 @@ -111,15 +125,15 @@ impl UncheckedFrom for Public { } #[cfg(feature = "std")] -impl ::std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl std::fmt::Display for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } #[cfg(feature = "std")] -impl ::std::fmt::Debug for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl std::fmt::Debug for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } @@ -141,8 +155,8 @@ impl<'de> Deserialize<'de> for Public { } #[cfg(feature = "std")] -impl ::std::hash::Hash for Public { - fn hash(&self, state: &mut H) { +impl std::hash::Hash for Public { + fn hash(&self, state: &mut H) { self.0.hash(state); } } @@ -167,7 +181,7 @@ impl Default for Signature { impl PartialEq for Signature { fn eq(&self, b: &Self) -> bool { - &self.0[..] == &b.0[..] + self.0[..] == b.0[..] } } @@ -204,16 +218,16 @@ impl AsMut<[u8]> for Signature { } #[cfg(feature = "std")] -impl ::std::fmt::Debug for Signature { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl std::fmt::Debug for Signature { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) } } #[cfg(feature = "std")] -impl ::std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - ::std::hash::Hash::hash(&self.0[..], state); +impl std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + std::hash::Hash::hash(&self.0[..], state); } } diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 5d4210cb4f2d7..cd69b52c619bc 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -63,6 +63,7 @@ pub mod sandbox; pub mod storage; pub mod uint; mod changes_trie; +pub mod traits; #[cfg(test)] mod tests; @@ -149,7 +150,7 @@ impl ::std::fmt::Debug for NativeOrEncoded { #[cfg(feature = "std")] impl NativeOrEncoded { /// Return the value as the encoded format. - pub fn as_encoded<'a>(&'a self) -> Cow<'a, [u8]> { + pub fn as_encoded(&self) -> Cow<'_, [u8]> { match self { NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()), NativeOrEncoded::Native(n) => Cow::Owned(n.encode()), @@ -198,3 +199,4 @@ impl parity_codec::Decode for NeverNativeValue { None } } + diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index a37e239159a06..60814baff915d 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -97,6 +97,20 @@ impl From for H256 { } } +impl rstd::convert::TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 32 { + let mut inner = [0u8; 32]; + inner.copy_from_slice(data); + Ok(Public(inner)) + } else { + Err(()) + } + } +} + impl UncheckedFrom<[u8; 32]> for Public { fn unchecked_from(x: [u8; 32]) -> Self { Public::from_raw(x) @@ -110,15 +124,15 @@ impl UncheckedFrom for Public { } #[cfg(feature = "std")] -impl ::std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl std::fmt::Display for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } #[cfg(feature = "std")] -impl ::std::fmt::Debug for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl std::fmt::Debug for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs new file mode 100644 index 0000000000000..61921e5f035c6 --- /dev/null +++ b/core/primitives/src/traits.rs @@ -0,0 +1,46 @@ +// Copyright 2017-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 . + +//! Shareable Substrate traits. + +use crate::{crypto::KeyTypeId, ed25519, sr25519}; + +/// Something that generates, stores and provides access to keys. +#[cfg(feature = "std")] +pub trait KeyStore: Send + Sync { + /// Generate a new sr25519 key pair for the given key type and an optional seed. + /// + /// If the given seed is `Some(_)`, the key pair will only be stored in memory. + /// + /// Returns the public key of the generated key pair. + fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String>; + /// Returns the sr25519 key pair for the given key type and public key combination. + fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option; + + /// Generate a new ed25519 key pair for the given key type and an optional seed. + /// + /// If the given seed is `Some(_)`, the key pair will only be stored in memory. + /// + /// Returns the public key of the generated key pair. + fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String>; + + /// Returns the ed25519 key pair for the given key type and public key combination. + fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option; +} + +/// A pointer to the key store. +#[cfg(feature = "std")] +pub type KeyStorePtr = std::sync::Arc>; \ No newline at end of file diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index b0f95e4e64b9d..ac899f689afaa 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" derive_more = "0.14.0" futures = "0.1.17" futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } -parking_lot = "0.8.0" +parking_lot = "0.9.0" lazy_static = "1.0" log = "0.4" slog = {version = "^2", features = ["nested-values"]} diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 8b08a842f0125..d6f0147638e6e 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -23,14 +23,16 @@ use client_db; use client::{self, Client, runtime_api}; use crate::{error, Service}; use consensus_common::{import_queue::ImportQueue, SelectChain}; -use network::{self, OnDemand, FinalityProofProvider, NetworkStateInfo, config::BoxFinalityProofRequestBuilder}; +use network::{ + self, OnDemand, FinalityProofProvider, NetworkStateInfo, config::BoxFinalityProofRequestBuilder +}; use substrate_executor::{NativeExecutor, NativeExecutionDispatch}; use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool}; use sr_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256, crypto::AppPair}; +use primitives::{Blake2Hasher, H256, crypto::AppPair, traits::KeyStorePtr}; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor}; use futures03::channel::mpsc; @@ -406,6 +408,7 @@ pub trait Components: Sized + 'static { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, + keystore: Option, ) -> Result< ( Arc>, @@ -492,11 +495,11 @@ impl Components for FullComponents { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, - ) - -> Result<( - Arc>, - Option>>> - ), error::Error> + keystore: Option, + ) -> Result< + (Arc>, Option>>>), + error::Error, + > { let db_settings = client_db::DatabaseSettings { cache_size: config.database_cache_size.map(|u| u as usize), @@ -506,12 +509,19 @@ impl Components for FullComponents { path: config.database_path.clone(), pruning: config.pruning.clone(), }; - Ok((Arc::new(client_db::new_client( - db_settings, - executor, - &config.chain_spec, - config.execution_strategies.clone(), - )?), None)) + + Ok(( + Arc::new( + client_db::new_client( + db_settings, + executor, + &config.chain_spec, + config.execution_strategies.clone(), + keystore, + )? + ), + None, + )) } fn build_transaction_pool( @@ -594,6 +604,7 @@ impl Components for LightComponents { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, + _: Option, ) -> Result< ( @@ -609,9 +620,12 @@ impl Components for LightComponents { path: config.database_path.clone(), pruning: config.pruning.clone(), }; + let db_storage = client_db::light::LightStorage::new(db_settings)?; let light_blockchain = client::light::new_light_blockchain(db_storage); - let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor.clone())); + let fetch_checker = Arc::new( + client::light::new_fetch_checker(light_blockchain.clone(), executor.clone()) + ); let fetcher = Arc::new(network::OnDemand::new(fetch_checker)); let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone()); let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec, executor)?; diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index a9fdc8af0ae58..4a78e9bfb96f7 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -42,6 +42,7 @@ use log::{log, info, warn, debug, error, Level}; use parity_codec::{Encode, Decode}; use sr_primitives::generic::BlockId; use sr_primitives::traits::{Header, NumberFor, SaturatedConversion}; +use primitives::traits::KeyStorePtr; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -107,15 +108,16 @@ pub struct Service { } /// Creates bare client without any networking. -pub fn new_client(config: &FactoryFullConfiguration) - -> Result>>, error::Error> -{ +pub fn new_client( + config: &FactoryFullConfiguration, +) -> Result>>, error::Error> { let executor = NativeExecutor::new(config.default_heap_pages); - let (client, _) = components::FullComponents::::build_client( + + components::FullComponents::::build_client( config, executor, - )?; - Ok(client) + None, + ).map(|r| r.0) } /// An handle for spawning tasks in the service. @@ -168,9 +170,17 @@ impl Service { // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let mut keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { + let keystore: Option = if let Some(keystore_path) = config.keystore_path.as_ref() { match Keystore::open(keystore_path.clone(), config.keystore_password.clone()) { - Ok(ks) => Some(ks), + Ok(mut ks) => { + if let Some(ref seed) = config.dev_key_seed { + //TODO: Make sure we generate for all types and apps + ks.generate_from_seed::(&seed)?; + ks.generate_from_seed::(&seed)?; + } + + Some(Arc::new(parking_lot::RwLock::new(ks))) + }, Err(err) => { error!("Failed to initialize keystore: {}", err); None @@ -180,17 +190,7 @@ impl Service { None }; - if let Some((keystore, seed)) = keystore.as_mut() - .and_then(|k| config.dev_key_seed.clone().map(|s| (k, s))) - { - //TODO: Make sure we generate for all types and apps - keystore.generate_from_seed::(&seed)?; - keystore.generate_from_seed::(&seed)?; - } - - let keystore = Arc::new(keystore); - - let (client, on_demand) = Components::build_client(&config, executor)?; + let (client, on_demand) = Components::build_client(&config, executor, keystore.clone())?; let select_chain = Components::build_select_chain(&mut config, client.clone())?; let (import_queue, finality_proof_request_builder) = Components::build_import_queue( &mut config, @@ -203,7 +203,9 @@ impl Service { let version = config.full_version(); info!("Highest known block at #{}", chain_info.best_number); - telemetry!(SUBSTRATE_INFO; "node.start"; + telemetry!( + SUBSTRATE_INFO; + "node.start"; "height" => chain_info.best_number.saturated_into::(), "best" => ?chain_info.best_hash ); diff --git a/core/sr-api-macros/tests/runtime_calls.rs b/core/sr-api-macros/tests/runtime_calls.rs index 75da2fe292889..6b79e52ee21d0 100644 --- a/core/sr-api-macros/tests/runtime_calls.rs +++ b/core/sr-api-macros/tests/runtime_calls.rs @@ -190,5 +190,6 @@ fn record_proof_works() { &executor, "Core_execute_block", &block.encode(), + None, ).expect("Executes block while using the proof backend"); } diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index f321cae68c75c..fe638dcac8236 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -33,12 +33,12 @@ use rstd::vec::Vec; pub use codec; pub use primitives::Blake2Hasher; -use primitives::offchain::{ - Timestamp, - HttpRequestId, HttpRequestStatus, HttpError, - CryptoKind, CryptoKey, KeyTypeId, - StorageKind, - OpaqueNetworkState, +use primitives::{ + crypto::KeyTypeId, + offchain::{ + Timestamp, HttpRequestId, HttpRequestStatus, HttpError, CryptoKind, CryptoKey, StorageKind, + OpaqueNetworkState, + } }; /// Error verifying ECDSA signature @@ -69,7 +69,7 @@ macro_rules! export_api { $( #[$attr:meta] )* fn $name:ident $(< $( $g_name:ident $( : $g_ty:path )? ),+ >)? - ( $( $arg:ident : $arg_ty:ty ),* ) + ( $( $arg:ident : $arg_ty:ty ),* $(,)? ) $( -> $ret:ty )? $( where $( $w_name:path : $w_ty:path ),+ )?; )* @@ -200,11 +200,41 @@ export_api! { export_api! { pub(crate) trait CryptoApi { - /// Verify a ed25519 signature. - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool; + /// Generate an ed22519 key for the given key type and store it in the keystore. + /// + /// Returns the raw public key. + fn ed25519_generate(id: KeyTypeId) -> [u8; 32]; + /// Sign the given `msg` with the ed25519 key that corresponds to the given public key and + /// key type in the keystore. + /// + /// Returns the raw signature. + fn ed25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]>; + /// Verify an ed25519 signature. + /// + /// Returns `true` when the verification in successful. + fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool; + /// Generate an sr22519 key for the given key type and store it in the keystore. + /// + /// Returns the raw public key. + fn sr25519_generate(id: KeyTypeId) -> [u8; 32]; + /// Sign the given `msg` with the sr25519 key that corresponds to the given public key and + /// key type in the keystore. + /// + /// Returns the raw signature. + fn sr25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]>; /// Verify an sr25519 signature. - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool; + /// + /// Returns `true` when the verification in successful. + fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool; /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 1a2918bc72d7b..6185aea4b930f 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -31,8 +31,7 @@ use environmental::environmental; use primitives::{offchain, hexdisplay::HexDisplay, H256}; use trie::{TrieConfiguration, trie_types::Layout}; -#[cfg(feature = "std")] -use std::collections::HashMap; +use std::{collections::HashMap, convert::TryFrom}; environmental!(ext: trait Externalities); @@ -208,11 +207,63 @@ impl OtherApi for () { } impl CryptoApi for () { - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + fn ed25519_generate(id: KeyTypeId) -> [u8; 32] { + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .write() + .ed25519_generate_new(id, None) + .expect("`ed25519_generate` failed") + }).expect("`ed25519_generate` cannot be called outside of an Externalities-provided environment.") + } + + fn ed25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]> { + let pub_key = ed25519::Public::try_from(pubkey.as_ref()).ok()?; + + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .read() + .ed25519_key_pair(id, &pub_key) + .map(|k| k.sign(msg.as_ref()).into()) + }).expect("`ed25519_sign` cannot be called outside of an Externalities-provided environment.") + } + + fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { ed25519::Pair::verify_weak(sig, msg, pubkey) } - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + fn sr25519_generate(id: KeyTypeId) -> [u8; 32] { + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .write() + .sr25519_generate_new(id, None) + .expect("`sr25519_generate` failed") + }).expect("`sr25519_generate` cannot be called outside of an Externalities-provided environment.") + } + + fn sr25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]> { + let pub_key = sr25519::Public::try_from(pubkey.as_ref()).ok()?; + + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .read() + .sr25519_key_pair(id, &pub_key) + .map(|k| k.sign(msg.as_ref()).into()) + }).expect("`sr25519_sign` cannot be called outside of an Externalities-provided environment.") + } + + fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { sr25519::Pair::verify_weak(sig, msg, pubkey) } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 3b38045818e48..84a4b30f3f5db 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -158,7 +158,7 @@ pub mod ext { ( $( $( #[$attr:meta] )* - fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) $( -> $ret:ty )?; + fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* $(,)? ) $( -> $ret:ty )?; )* ) => { $( @@ -352,25 +352,66 @@ pub mod ext { fn ext_twox_256(data: *const u8, len: u32, out: *mut u8); /// Keccak256 hash fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8); - /// Note: ext_ed25519_verify returns 0 if the signature is correct, nonzero otherwise. + + /// Note: `ext_ed25519_verify` returns `0` if the signature is correct, nonzero otherwise. fn ext_ed25519_verify( msg_data: *const u8, msg_len: u32, sig_data: *const u8, - pubkey_data: *const u8 + pubkey_data: *const u8, + ) -> u32; + + /// Generate an `ed25519` key pair for the given key type id and store the public key + /// in `out`. + fn ext_ed25519_generate(id: *const u8, out: *mut u8); + + /// Sign the given `msg` with the `ed25519` key pair that corresponds to then given key + /// type id and public key. The raw signature is stored in `out`. + /// + /// # Returns + /// + /// - `0` on success + /// - nonezero if something failed, e.g. retrieving of the key. + fn ext_ed25519_sign( + id: *const u8, + pubkey: *const u8, + msg: *const u8, + msg_len: u32, + out: *mut u8, ) -> u32; - /// Note: ext_sr25519_verify returns 0 if the signature is correct, nonzero otherwise. + + /// Note: `ext_sr25519_verify` returns 0 if the signature is correct, nonzero otherwise. fn ext_sr25519_verify( msg_data: *const u8, msg_len: u32, sig_data: *const u8, - pubkey_data: *const u8 + pubkey_data: *const u8, ) -> u32; + + /// Generate an `sr25519` key pair for the given key type id and store the public + /// key in `out`. + fn ext_sr25519_generate(id: *const u8, out: *mut u8); + + /// Sign the given `msg` with the `sr25519` key pair that corresponds to then given key + /// type id and public key. The raw signature is stored in `out`. + /// + /// # Returns + /// + /// - `0` on success + /// - nonezero if something failed, e.g. retrieving of the key. + fn ext_sr25519_sign( + id: *const u8, + pubkey: *const u8, + msg: *const u8, + msg_len: u32, + out: *mut u8, + ) -> u32; + /// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise. fn ext_secp256k1_ecdsa_recover( msg_data: *const u8, sig_data: *const u8, - pubkey_data: *mut u8 + pubkey_data: *mut u8, ) -> u32; //================================ @@ -871,15 +912,83 @@ impl HashingApi for () { } impl CryptoApi for () { - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + fn ed25519_generate(id: KeyTypeId) -> [u8; 32] { + let mut res = [0u8; 32]; + unsafe { ext_ed25519_generate.get()(id.0.as_ptr(), res.as_mut_ptr()) }; + res + } + + fn ed25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]> { + let mut res = [0u8; 64]; + let success = unsafe { + ext_ed25519_sign.get()( + id.0.as_ptr(), + pubkey.as_ref().as_ptr(), + msg.as_ref().as_ptr(), + msg.as_ref().len() as u32, + res.as_mut_ptr(), + ) == 0 + }; + + if success { + Some(res) + } else { + None + } + } + + fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { unsafe { - ext_ed25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 + ext_ed25519_verify.get()( + msg.as_ptr(), + msg.len() as u32, + sig.as_ptr(), + pubkey.as_ref().as_ptr(), + ) == 0 + } + } + + fn sr25519_generate(id: KeyTypeId) -> [u8; 32] { + let mut res = [0u8;32]; + unsafe { ext_sr25519_generate.get()(id.0.as_ptr(), res.as_mut_ptr()) }; + res + } + + fn sr25519_sign, M: AsRef<[u8]>>( + id: KeyTypeId, + pubkey: &P, + msg: &M, + ) -> Option<[u8; 64]> { + let mut res = [0u8; 64]; + let success = unsafe { + ext_sr25519_sign.get()( + id.0.as_ptr(), + pubkey.as_ref().as_ptr(), + msg.as_ref().as_ptr(), + msg.as_ref().len() as u32, + res.as_mut_ptr(), + ) == 0 + }; + + if success { + Some(res) + } else { + None } } - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { unsafe { - ext_sr25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 + ext_sr25519_verify.get()( + msg.as_ptr(), + msg.len() as u32, + sig.as_ptr(), + pubkey.as_ref().as_ptr(), + ) == 0 } } diff --git a/core/state-machine/Cargo.toml b/core/state-machine/Cargo.toml index c7a15bf9572a6..aa4422e055ecc 100644 --- a/core/state-machine/Cargo.toml +++ b/core/state-machine/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] log = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" hash-db = "0.15.0" trie-db = "0.15.0" trie-root = "0.15.0" diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs index 53ab731671314..a99133b481afe 100644 --- a/core/state-machine/src/basic.rs +++ b/core/state-machine/src/basic.rs @@ -168,7 +168,12 @@ impl Externalities for BasicExternalities where H::Out: Ord { } fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { - warn!("Call to non-existent out offchain externalities set."); + warn!("Call to non-existent offchain externalities set."); + None + } + + fn keystore(&self) -> Option { + warn!("Call to non-existent keystore."); None } } diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index 7f0fa1de3f009..7ae663bc016f5 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -22,8 +22,7 @@ use crate::backend::Backend; use crate::changes_trie::{Storage as ChangesTrieStorage, build_changes_trie}; use crate::{Externalities, OverlayedChanges, ChildStorageKey}; use hash_db::Hasher; -use primitives::offchain; -use primitives::storage::well_known_keys::is_child_storage_key; +use primitives::{offchain, storage::well_known_keys::is_child_storage_key, traits::KeyStorePtr}; use trie::{MemoryDB, default_child_trie_root}; use trie::trie_types::Layout; @@ -84,6 +83,8 @@ where /// /// If None, some methods from the trait might not be supported. offchain_externalities: Option<&'a mut O>, + /// The keystore that manages the keys of the node. + keystore: Option, /// Dummy usage of N arg. _phantom: ::std::marker::PhantomData, } @@ -103,6 +104,7 @@ where backend: &'a B, changes_trie_storage: Option<&'a T>, offchain_externalities: Option<&'a mut O>, + keystore: Option, ) -> Self { Ext { overlay, @@ -111,6 +113,7 @@ where changes_trie_storage, changes_trie_transaction: None, offchain_externalities, + keystore, _phantom: Default::default(), } } @@ -333,6 +336,10 @@ where fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { self.offchain_externalities.as_mut().map(|x| &mut **x as _) } + + fn keystore(&self) -> Option { + self.keystore.clone() + } } #[cfg(test)] @@ -375,7 +382,7 @@ mod tests { fn storage_changes_root_is_none_when_storage_is_not_provided() { let mut overlay = prepare_overlay_with_changes(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, None, None); + let mut ext = TestExt::new(&mut overlay, &backend, None, None, None); assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None); } @@ -385,7 +392,7 @@ mod tests { overlay.changes_trie_config = None; let storage = TestChangesTrieStorage::with_blocks(vec![(100, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None); } @@ -394,11 +401,11 @@ mod tests { let mut overlay = prepare_overlay_with_changes(); let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); - let root = hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into(); - - assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), - Some(root)); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); + assert_eq!( + ext.storage_changes_root(Default::default()).unwrap(), + Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into()), + ); } #[test] @@ -407,10 +414,10 @@ mod tests { overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None; let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); - let root = hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into(); - - assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), - Some(root)); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); + assert_eq!( + ext.storage_changes_root(Default::default()).unwrap(), + Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into()), + ); } } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 8498b25873962..ca327c1e147c1 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -24,7 +24,7 @@ use log::warn; use hash_db::Hasher; use parity_codec::{Decode, Encode}; use primitives::{ - storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain, + storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain, traits::KeyStorePtr, }; pub mod backend; @@ -61,6 +61,7 @@ pub use proving_backend::{ pub use trie_backend_essence::{TrieBackendStorage, Storage}; pub use trie_backend::TrieBackend; + /// A wrapper around a child storage key. /// /// This wrapper ensures that the child storage key is correct and properly used. It is @@ -224,6 +225,9 @@ pub trait Externalities { /// Returns offchain externalities extension if present. fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities>; + + /// Returns the keystore. + fn keystore(&self) -> Option; } /// An implementation of offchain extensions that should never be triggered. @@ -483,6 +487,7 @@ pub fn new<'a, H, N, B, T, O, Exec>( exec: &'a Exec, method: &'a str, call_data: &'a [u8], + keystore: Option, ) -> StateMachine<'a, H, N, B, T, O, Exec> { StateMachine { backend, @@ -492,6 +497,7 @@ pub fn new<'a, H, N, B, T, O, Exec>( exec, method, call_data, + keystore, _hasher: PhantomData, } } @@ -505,6 +511,7 @@ pub struct StateMachine<'a, H, N, B, T, O, Exec> { exec: &'a Exec, method: &'a str, call_data: &'a [u8], + keystore: Option, _hasher: PhantomData<(H, N)>, } @@ -562,6 +569,7 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where self.backend, self.changes_trie_storage, self.offchain_ext.as_mut().map(|x| &mut **x), + self.keystore.clone(), ); let (result, was_native) = self.exec.call( &mut externalities, @@ -709,6 +717,7 @@ pub fn prove_execution( exec: &Exec, method: &str, call_data: &[u8], + keystore: Option, ) -> Result<(Vec, Vec>), Box> where B: Backend, @@ -718,7 +727,7 @@ where { let trie_backend = backend.as_trie_backend() .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; - prove_execution_on_trie_backend(trie_backend, overlay, exec, method, call_data) + prove_execution_on_trie_backend(trie_backend, overlay, exec, method, call_data, keystore) } /// Prove execution using the given trie backend, overlayed changes, and call executor. @@ -736,6 +745,7 @@ pub fn prove_execution_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], + keystore: Option, ) -> Result<(Vec, Vec>), Box> where S: trie_backend_essence::TrieBackendStorage, @@ -752,6 +762,7 @@ where exec, method, call_data, + keystore, _hasher: PhantomData, }; let (result, _, _) = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -771,6 +782,7 @@ pub fn execution_proof_check( exec: &Exec, method: &str, call_data: &[u8], + keystore: Option, ) -> Result, Box> where H: Hasher, @@ -778,7 +790,7 @@ where H::Out: Ord + 'static, { let trie_backend = create_proof_check_backend::(root.into(), proof)?; - execution_proof_check_on_trie_backend(&trie_backend, overlay, exec, method, call_data) + execution_proof_check_on_trie_backend(&trie_backend, overlay, exec, method, call_data, keystore) } /// Check execution proof on proving backend, generated by `prove_execution` call. @@ -788,6 +800,7 @@ pub fn execution_proof_check_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], + keystore: Option, ) -> Result, Box> where H: Hasher, @@ -802,6 +815,7 @@ where exec, method, call_data, + keystore, _hasher: PhantomData, }; sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -1052,6 +1066,7 @@ mod tests { }, "test", &[], + None, ).execute( ExecutionStrategy::NativeWhenPossible ).unwrap().0, vec![66]); @@ -1073,6 +1088,7 @@ mod tests { }, "test", &[], + None, ).execute( ExecutionStrategy::NativeElseWasm ).unwrap().0, vec![66]); @@ -1094,6 +1110,7 @@ mod tests { }, "test", &[], + None, ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( ExecutionManager::Both(|we, _ne| { consensus_failed = true; @@ -1116,13 +1133,26 @@ mod tests { // fetch execution proof from 'remote' full node let remote_backend = trie_backend::tests::test_trie(); - let remote_root = remote_backend.storage_root(::std::iter::empty()).0; - let (remote_result, remote_proof) = prove_execution(remote_backend, - &mut Default::default(), &executor, "test", &[]).unwrap(); + let remote_root = remote_backend.storage_root(std::iter::empty()).0; + let (remote_result, remote_proof) = prove_execution( + remote_backend, + &mut Default::default(), + &executor, + "test", + &[], + None, + ).unwrap(); // check proof locally - let local_result = execution_proof_check::(remote_root, remote_proof, - &mut Default::default(), &executor, "test", &[]).unwrap(); + let local_result = execution_proof_check::( + remote_root, + remote_proof, + &mut Default::default(), + &executor, + "test", + &[], + None, + ).unwrap(); // check that both results are correct assert_eq!(remote_result, vec![66]); @@ -1153,7 +1183,13 @@ mod tests { { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); - let mut ext = Ext::new(&mut overlay, backend, Some(&changes_trie_storage), NeverOffchainExt::new()); + let mut ext = Ext::new( + &mut overlay, + backend, + Some(&changes_trie_storage), + NeverOffchainExt::new(), + None, + ); ext.clear_prefix(b"ab"); } overlay.commit_prospective(); @@ -1182,7 +1218,8 @@ mod tests { &mut overlay, backend, Some(&changes_trie_storage), - NeverOffchainExt::new() + NeverOffchainExt::new(), + None, ); ext.set_child_storage( @@ -1254,41 +1291,47 @@ mod tests { #[test] fn cannot_change_changes_trie_config() { - assert!(new( - &trie_backend::tests::test_trie(), - Some(&InMemoryChangesTrieStorage::::new()), - NeverOffchainExt::new(), - &mut Default::default(), - &DummyCodeExecutor { - change_changes_trie_config: true, - native_available: false, - native_succeeds: true, - fallback_succeeds: true, - }, - "test", - &[], - ).execute( - ExecutionStrategy::NativeWhenPossible - ).is_err()); + assert!( + new( + &trie_backend::tests::test_trie(), + Some(&InMemoryChangesTrieStorage::::new()), + NeverOffchainExt::new(), + &mut Default::default(), + &DummyCodeExecutor { + change_changes_trie_config: true, + native_available: false, + native_succeeds: true, + fallback_succeeds: true, + }, + "test", + &[], + None, + ) + .execute(ExecutionStrategy::NativeWhenPossible) + .is_err() + ); } #[test] fn cannot_change_changes_trie_config_with_native_else_wasm() { - assert!(new( - &trie_backend::tests::test_trie(), - Some(&InMemoryChangesTrieStorage::::new()), - NeverOffchainExt::new(), - &mut Default::default(), - &DummyCodeExecutor { - change_changes_trie_config: true, - native_available: false, - native_succeeds: true, - fallback_succeeds: true, - }, - "test", - &[], - ).execute( - ExecutionStrategy::NativeElseWasm - ).is_err()); + assert!( + new( + &trie_backend::tests::test_trie(), + Some(&InMemoryChangesTrieStorage::::new()), + NeverOffchainExt::new(), + &mut Default::default(), + &DummyCodeExecutor { + change_changes_trie_config: true, + native_available: false, + native_succeeds: true, + fallback_succeeds: true, + }, + "test", + &[], + None, + ) + .execute(ExecutionStrategy::NativeElseWasm) + .is_err() + ); } } diff --git a/core/state-machine/src/overlayed_changes.rs b/core/state-machine/src/overlayed_changes.rs index 34bf8ca3c5d8b..b09dc3025c110 100644 --- a/core/state-machine/src/overlayed_changes.rs +++ b/core/state-machine/src/overlayed_changes.rs @@ -371,6 +371,7 @@ mod tests { &backend, Some(&changes_trie_storage), crate::NeverOffchainExt::new(), + None, ); const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index 73c0b38ef4359..37ba4dccff262 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -25,8 +25,9 @@ use crate::changes_trie::{ build_changes_trie, InMemoryStorage as ChangesTrieInMemoryStorage, BlockNumber as ChangesTrieBlockNumber, }; -use primitives::offchain; -use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}; +use primitives::{ + storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}, traits::KeyStorePtr, offchain +}; use parity_codec::Encode; use super::{ChildStorageKey, Externalities, OverlayedChanges}; @@ -40,6 +41,7 @@ pub struct TestExternalities { backend: InMemory, changes_trie_storage: ChangesTrieInMemoryStorage, offchain: Option>, + keystore: Option, } impl TestExternalities { @@ -84,6 +86,7 @@ impl TestExternalities { changes_trie_storage: ChangesTrieInMemoryStorage::new(), backend: backend.into(), offchain: None, + keystore: None, } } @@ -263,6 +266,10 @@ impl Externalities for TestExternalities .as_mut() .map(|x| &mut **x as _) } + + fn keystore(&self) -> Option { + self.keystore.clone() + } } #[cfg(test)] diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index 175996a43260c..c9e1f2332a0e7 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -30,7 +30,7 @@ pub use keyring::{ ed25519::Keyring as Ed25519Keyring, sr25519::Keyring as Sr25519Keyring, }; -pub use primitives::Blake2Hasher; +pub use primitives::{Blake2Hasher, traits::KeyStorePtr}; pub use sr_primitives::{StorageOverlay, ChildrenStorageOverlay}; pub use state_machine::ExecutionStrategy; @@ -73,6 +73,7 @@ pub struct TestClientBuilder { child_storage_extension: HashMap, Vec<(Vec, Vec)>>, backend: Arc, _executor: std::marker::PhantomData, + keystore: Option, } impl Default for TestClientBuilder< @@ -100,11 +101,7 @@ impl TestClientBuilder< } } -impl TestClientBuilder< - Executor, - Backend, - G, -> { +impl TestClientBuilder { /// Create a new instance of the test client builder. pub fn with_backend(backend: Arc) -> Self { TestClientBuilder { @@ -113,9 +110,16 @@ impl TestClientBuilder< child_storage_extension: Default::default(), genesis_init: Default::default(), _executor: Default::default(), + keystore: None, } } + /// Set the keystore that should be used by the externalities. + pub fn set_keystore(mut self, keystore: KeyStorePtr) -> Self { + self.keystore = Some(keystore); + self + } + /// Alter the genesis storage parameters. pub fn genesis_init_mut(&mut self) -> &mut G { &mut self.genesis_init @@ -184,7 +188,7 @@ impl TestClientBuilder< self.backend.clone(), executor, storage, - self.execution_strategies + self.execution_strategies, ).expect("Creates new client"); let longest_chain = client::LongestChain::new(self.backend); @@ -200,7 +204,7 @@ impl TestClientBuilder< > { /// Build the test client with the given native executor. pub fn build_with_native_executor( - self, + mut self, executor: I, ) -> ( client::Client< @@ -217,7 +221,7 @@ impl TestClientBuilder< Block: BlockT::Out>, { let executor = executor.into().unwrap_or_else(|| executor::NativeExecutor::new(None)); - let executor = LocalCallExecutor::new(self.backend.clone(), executor); + let executor = LocalCallExecutor::new(self.backend.clone(), executor, self.keystore.take()); self.build_with_executor(executor) } diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index 9c7fddb95d6c7..03f7bb3ddb7db 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -211,9 +211,16 @@ pub fn new_light() -> client::Client Date: Sun, 4 Aug 2019 19:34:22 +0200 Subject: [PATCH 43/80] Move app crypto to its own crate --- Cargo.lock | 25 +- Cargo.toml | 1 + core/application-crypto/Cargo.toml | 16 + core/application-crypto/src/lib.rs | 377 ++++++++++++++++++++ core/consensus/aura/Cargo.toml | 1 + core/consensus/aura/primitives/Cargo.toml | 4 +- core/consensus/aura/primitives/src/lib.rs | 4 +- core/consensus/aura/src/lib.rs | 3 +- core/consensus/babe/Cargo.toml | 1 + core/consensus/babe/primitives/Cargo.toml | 3 +- core/consensus/babe/primitives/src/lib.rs | 2 +- core/consensus/babe/src/lib.rs | 2 +- core/finality-grandpa/primitives/Cargo.toml | 4 +- core/finality-grandpa/primitives/src/lib.rs | 2 +- core/keystore/Cargo.toml | 3 +- core/keystore/src/lib.rs | 6 +- core/primitives/src/crypto.rs | 311 +--------------- core/primitives/src/ed25519.rs | 10 - core/primitives/src/sr25519.rs | 10 - core/primitives/src/traits.rs | 1 + core/service/Cargo.toml | 3 +- core/service/src/components.rs | 3 +- core/service/src/lib.rs | 4 +- core/sr-primitives/Cargo.toml | 2 + core/sr-primitives/src/lib.rs | 3 +- srml/aura/Cargo.toml | 2 + srml/aura/src/lib.rs | 2 +- srml/im-online/Cargo.toml | 2 + srml/im-online/src/lib.rs | 4 +- 29 files changed, 455 insertions(+), 356 deletions(-) create mode 100644 core/application-crypto/Cargo.toml create mode 100644 core/application-crypto/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 88c605c4cf4f0..c9069f5e3abd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3641,6 +3641,7 @@ dependencies = [ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-std 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-primitives 2.0.0", ] @@ -3705,6 +3706,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-consensus-aura-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", @@ -3924,6 +3926,7 @@ dependencies = [ "srml-session 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-primitives 2.0.0", ] @@ -4221,6 +4224,16 @@ dependencies = [ "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-application-crypto" +version = "2.0.0" +dependencies = [ + "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "substrate-basic-authorship" version = "2.0.0" @@ -4355,6 +4368,7 @@ dependencies = [ "sr-version 2.0.0", "srml-aura 2.0.0", "srml-support 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura-primitives 2.0.0", "substrate-consensus-common 2.0.0", @@ -4378,8 +4392,8 @@ dependencies = [ "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", - "substrate-primitives 2.0.0", ] [[package]] @@ -4405,6 +4419,7 @@ dependencies = [ "sr-version 2.0.0", "srml-babe 2.0.0", "srml-support 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", "substrate-consensus-babe-primitives 2.0.0", "substrate-consensus-common 2.0.0", @@ -4429,9 +4444,9 @@ dependencies = [ "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", "substrate-consensus-slots 2.0.0", - "substrate-primitives 2.0.0", ] [[package]] @@ -4574,8 +4589,8 @@ dependencies = [ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", - "substrate-primitives 2.0.0", ] [[package]] @@ -4603,10 +4618,11 @@ dependencies = [ name = "substrate-keystore" version = "2.0.0" dependencies = [ - "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-application-crypto 2.0.0", "substrate-primitives 2.0.0", "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4829,6 +4845,7 @@ dependencies = [ "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", "substrate-consensus-babe-primitives 2.0.0", diff --git a/Cargo.toml b/Cargo.toml index a6a7b8d17ba35..9ecf79257d8a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ vergen = "3" [workspace] members = [ + "core/application-crypto", "core/cli", "core/client", "core/client/db", diff --git a/core/application-crypto/Cargo.toml b/core/application-crypto/Cargo.toml new file mode 100644 index 0000000000000..06b1a6143ab12 --- /dev/null +++ b/core/application-crypto/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "substrate-application-crypto" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" +description = "Provides facilities for generating application specific crypto wrapper types." + +[dependencies] +primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } +codec = { package = "parity-codec", version = "4.1.3", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } + +[features] +default = [ "std" ] +std = [ "primitives/std", "codec/std", "serde", "rstd/std" ] diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs new file mode 100644 index 0000000000000..9baa9d314f139 --- /dev/null +++ b/core/application-crypto/src/lib.rs @@ -0,0 +1,377 @@ +// 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 . + +//! Traits and macros for constructing application specific strongly typed crypto wrappers. + +#![warn(missing_docs)] + +#![cfg_attr(not(feature = "std"), no_std)] + +#[doc(hidden)] +pub use primitives::{self, crypto::{CryptoType, Public, Derive, IsWrappedBy, Wraps}}; +#[doc(hidden)] +#[cfg(feature = "std")] +pub use primitives::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair}; +pub use primitives::{crypto::{KeyTypeId, key_types, Kind}}; + +#[doc(hidden)] +pub use codec; +#[doc(hidden)] +#[cfg(feature = "std")] +pub use serde; +#[doc(hidden)] +pub use rstd::ops::Deref; + +/// `ed25519` crypto types. +pub mod ed25519 { + pub use primitives::ed25519::*; + + mod app { + use crate::key_types::ED25519; + crate::app_crypto!(super, ED25519); + } + + pub use app::Public as AppPublic; + pub use app::Signature as AppSignature; + #[cfg(feature="std")] + pub use app::Pair as AppPair; +} + +/// `sr25519` crypto types. +pub mod sr25519 { + pub use primitives::sr25519::*; + + mod app { + use crate::key_types::SR25519; + crate::app_crypto!(super, SR25519); + } + + pub use app::Public as AppPublic; + pub use app::Signature as AppSignature; + #[cfg(feature="std")] + pub use app::Pair as AppPair; +} + +/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new +/// Application-specific types whose identifier is `$key_type`. +/// +/// ```rust +///# use substrate_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId}; +/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` +/// // of value `b"fuba"`. +/// app_crypto!(ed25519, KeyTypeId(*b"_uba")); +/// ``` +#[macro_export] +macro_rules! app_crypto { + ($module:ident, $key_type:expr) => { + #[cfg(feature="std")] + $crate::app_crypto!($module::Pair, $module::Public, $module::Signature, $key_type); + #[cfg(not(feature="std"))] + $crate::app_crypto!($module::Public, $module::Signature, $key_type); + }; + ($pair:ty, $public:ty, $sig:ty, $key_type:expr) => { + $crate::app_crypto!($public, $sig, $key_type); + + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone)] + pub struct Pair($pair); + } + + impl $crate::CryptoType for Pair { + const KIND: $crate::Kind = <$pair as $crate::CryptoType>::KIND; + type Pair = Pair; + } + + #[cfg(feature = "std")] + impl $crate::Pair for Pair { + type Public = Public; + type Seed = <$pair as $crate::Pair>::Seed; + type Signature = Signature; + type DeriveError = <$pair as $crate::Pair>::DeriveError; + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { + let r = <$pair>::generate_with_phrase(password); + (Self(r.0), r.1, r.2) + } + fn from_phrase(phrase: &str, password: Option<&str>) + -> Result<(Self, Self::Seed), $crate::SecretStringError> + { + <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) + } + fn derive< + Iter: Iterator + >(&self, path: Iter) -> Result { + self.0.derive(path).map(Self) + } + fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) } + fn from_seed_slice(seed: &[u8]) -> Result { + <$pair>::from_seed_slice(seed).map(Self) + } + fn from_standard_components< + I: Iterator + >( + seed: &str, + password: Option<&str>, + path: I, + ) -> Result { + <$pair>::from_standard_components::(seed, password, path).map(Self) + } + fn sign(&self, msg: &[u8]) -> Self::Signature { + Signature(self.0.sign(msg)) + } + fn verify, M: AsRef<[u8]>>( + sig: &Self::Signature, + message: M, + pubkey: P, + ) -> bool { + <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) + } + fn verify_weak, M: AsRef<[u8]>>( + sig: &[u8], + message: M, + pubkey: P, + ) -> bool { + <$pair>::verify_weak(sig, message, pubkey) + } + fn public(&self) -> Self::Public { Public(self.0.public()) } + fn to_raw_vec(&self) -> Vec { self.0.to_raw_vec() } + } + impl $crate::AppKey for Pair { + type UntypedGeneric = $pair; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::KeyTypeId = $key_type; + } + impl $crate::AppPair for Pair { + type Generic = $pair; + } + }; + ($public:ty, $sig:ty, $key_type:expr) => { + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive( + Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::codec::Encode, + $crate::codec::Decode, + )] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Public($public); + } + // TODO: needed for verify since it takes an AsRef, but should be removed once that is + // refactored. + $crate::primitives::impl_as_ref_mut!(Public); + + impl $crate::Derive for Public { + #[cfg(feature = "std")] + fn derive>(&self, + path: Iter + ) -> Option { + self.0.derive(path).map(Self) + } + } + + #[cfg(feature = "std")] + impl std::fmt::Display for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + use $crate::Ss58Codec; + write!(f, "{}", self.0.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl $crate::serde::Serialize for Public { + fn serialize(&self, serializer: S) -> std::result::Result where + S: $crate::serde::Serializer + { + use $crate::Ss58Codec; + serializer.serialize_str(&self.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl<'de> $crate::serde::Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> std::result::Result where + D: $crate::serde::Deserializer<'de> + { + use $crate::Ss58Codec; + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) + } + } + + impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + + impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } + } + + impl $crate::CryptoType for Public { + const KIND: $crate::Kind = <$public as $crate::CryptoType>::KIND; + #[cfg(feature="std")] + type Pair = Pair; + } + + impl $crate::Public for Public { + fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } + } + + impl $crate::AppKey for Public { + type UntypedGeneric = $public; + type Public = Public; + #[cfg(feature="std")] + type Pair = Pair; + type Signature = Signature; + const ID: $crate::KeyTypeId = $key_type; + } + + impl $crate::AppPublic for Public { + type Generic = $public; + } + + $crate::wrap! { + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Signature($sig); + } + + impl $crate::Deref for Signature { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { self.0.as_ref() } + } + + impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + + impl $crate::CryptoType for Signature { + const KIND: $crate::Kind = <$public as $crate::CryptoType>::KIND; + #[cfg(feature="std")] + type Pair = Pair; + } + + impl $crate::AppKey for Signature { + type UntypedGeneric = $sig; + type Public = Public; + #[cfg(feature="std")] + type Pair = Pair; + type Signature = Signature; + const ID: $crate::KeyTypeId = $key_type; + } + + impl $crate::AppSignature for Signature { + type Generic = $sig; + } + } +} + +/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer`. +/// +/// ```rust +/// substrate_application_crypto::wrap! { +/// pub struct Wrapper(u32); +/// } +/// ``` +#[macro_export] +macro_rules! wrap { + ($( #[ $attr:meta ] )* struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($( #[ $attr:meta ] )* pub struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + pub struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($inner:ty, $outer:ty) => { + impl $crate::Wraps for $outer { + type Inner = $inner; + } + impl From<$inner> for $outer { + fn from(inner: $inner) -> Self { + Self(inner) + } + } + impl From<$outer> for $inner { + fn from(outer: $outer) -> Self { + outer.0 + } + } + impl AsRef<$inner> for $outer { + fn as_ref(&self) -> &$inner { + &self.0 + } + } + impl AsMut<$inner> for $outer { + fn as_mut(&mut self) -> &mut $inner { + &mut self.0 + } + } + } +} + +/// An application-specific key. +pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { + /// The corresponding type as a generic crypto type. + type UntypedGeneric: IsWrappedBy; + + /// The corresponding public key type in this application scheme. + type Public: AppPublic; + + /// The corresponding key pair type in this application scheme. + #[cfg(feature="std")] + type Pair: AppPair; + + /// The corresponding signature type in this application scheme. + type Signature: AppSignature; + + /// An identifier for this application-specific key type. + const ID: KeyTypeId; +} + +/// Type which implements Debug and Hash in std, not when no-std (std variant). +#[cfg(feature = "std")] +pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} +#[cfg(feature = "std")] +impl MaybeDebugHash for T {} + +/// Type which implements Debug and Hash in std, not when no-std (no-std variant). +#[cfg(not(feature = "std"))] +pub trait MaybeDebugHash {} +#[cfg(not(feature = "std"))] +impl MaybeDebugHash for T {} + +/// A application's public key. +pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec { + /// The wrapped type which is just a plain instance of `Public`. + type Generic: + IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec; +} + +/// A application's public key. +#[cfg(feature = "std")] +pub trait AppPair: AppKey + Pair::Public> { + /// The wrapped type which is just a plain instance of `Pair`. + type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; +} + +/// A application's public key. +pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { + /// The wrapped type which is just a plain instance of `Signature`. + type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; +} diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index 6c701925cb4d6..290361fe3ad2c 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] parity-codec = "4.1.1" primitives = { package = "substrate-primitives", path = "../../primitives" } +app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto" } runtime_support = { package = "srml-support", path = "../../../srml/support" } runtime_version = { package = "sr-version", path = "../../sr-version" } runtime_io = { package = "sr-io", path = "../../sr-io" } diff --git a/core/consensus/aura/primitives/Cargo.toml b/core/consensus/aura/primitives/Cargo.toml index cbebd10a4dcda..8d55c1e95d386 100644 --- a/core/consensus/aura/primitives/Cargo.toml +++ b/core/consensus/aura/primitives/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] parity-codec = { version = "4.1.1", default-features = false } substrate-client = { path = "../../../client", default-features = false } -primitives = { package = "substrate-primitives", path = "../../../primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../../../application-crypto", default-features = false } rstd = { package = "sr-std", path = "../../../sr-std", default-features = false } sr-primitives = { path = "../../../sr-primitives", default-features = false } @@ -19,5 +19,5 @@ std = [ "parity-codec/std", "sr-primitives/std", "substrate-client/std", - "primitives/std", + "app-crypto/std", ] diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index bc1bf3939a1af..258f6dd95c564 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -24,7 +24,7 @@ use rstd::vec::Vec; use sr_primitives::ConsensusEngineId; mod app_sr25519 { - use primitives::{app_crypto, crypto::key_types::AURA, sr25519}; + use app_crypto::{app_crypto, key_types::AURA, sr25519}; app_crypto!(sr25519, AURA); } @@ -41,7 +41,7 @@ pub mod sr25519 { } mod app_ed25519 { - use primitives::{app_crypto, crypto::key_types::AURA, ed25519}; + use app_crypto::{app_crypto, key_types::AURA, ed25519}; app_crypto!(ed25519, AURA); } diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index abe3b4ea12105..d503859a9ebe8 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -51,7 +51,8 @@ use substrate_keystore::Store; use sr_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification}; use sr_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member}; -use primitives::crypto::{Pair, AppPair, AppKey}; +use primitives::crypto::Pair; +use app_crypto::{AppPair, AppKey}; use inherents::{InherentDataProviders, InherentData}; use futures::{prelude::*, future}; diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index 44125f8a55952..0d48e65810e8e 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" parity-codec = { version = "4.1.1", features = ["derive"] } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "primitives" } primitives = { package = "substrate-primitives", path = "../../primitives" } +app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto" } num-bigint = "0.2" num-rational = "0.2" num-traits = "0.2" diff --git a/core/consensus/babe/primitives/Cargo.toml b/core/consensus/babe/primitives/Cargo.toml index 2c6ba886f40ef..3966ba5ac2f29 100644 --- a/core/consensus/babe/primitives/Cargo.toml +++ b/core/consensus/babe/primitives/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" substrate-client = { path = "../../../client", default-features = false } rstd = { package = "sr-std", path = "../../../sr-std", default-features = false } sr-primitives = { path = "../../../sr-primitives", default-features = false } -primitives = { package = "substrate-primitives", path = "../../../primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../../../application-crypto", default-features = false } slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true } parity-codec = { version = "4.1.1", default-features = false } schnorrkel = { version = "0.1.1", optional = true } @@ -23,4 +23,5 @@ std = [ "parity-codec/std", "schnorrkel", "slots", + "app-crypto/std", ] diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index 7dd5f0ff81bd8..a9e55f07c2f58 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -31,7 +31,7 @@ pub use digest::{BabePreDigest, CompatibleDigestItem}; pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest}; mod app { - use primitives::{app_crypto, crypto::key_types::BABE, sr25519}; + use app_crypto::{app_crypto, key_types::BABE, sr25519}; app_crypto!(sr25519, BABE); } diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index ff0e2fa05e29c..3538458ed3c7d 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -1243,7 +1243,7 @@ pub trait SealingSource { fn format(&self) -> String; } -impl SealingSource for T { +impl SealingSource for T { const SEALER_TYPE: &'static str = "Key"; fn format(&self) -> String { use primitives::crypto::Ss58Codec; self.to_ss58check() } } diff --git a/core/finality-grandpa/primitives/Cargo.toml b/core/finality-grandpa/primitives/Cargo.toml index 75e6b5f608f63..d73121490a8f7 100644 --- a/core/finality-grandpa/primitives/Cargo.toml +++ b/core/finality-grandpa/primitives/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../client", default-features = false } -primitives = { package = "substrate-primitives", path = "../../primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto", default-features = false } parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } sr-primitives = { path = "../../sr-primitives", default-features = false } rstd = { package = "sr-std", path = "../../sr-std", default-features = false } @@ -15,10 +15,10 @@ serde = { version = "1.0", optional = true, features = ["derive"] } [features] default = ["std"] std = [ - "primitives/std", "client/std", "parity-codec/std", "sr-primitives/std", "rstd/std", "serde", + "app-crypto/std", ] diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 009b8dcfa85e9..be5d861522e1c 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -29,7 +29,7 @@ use client::decl_runtime_apis; use rstd::vec::Vec; mod app { - use primitives::{app_crypto, crypto::key_types::GRANDPA, ed25519}; + use app_crypto::{app_crypto, key_types::GRANDPA, ed25519}; app_crypto!(ed25519, GRANDPA); } diff --git a/core/keystore/Cargo.toml b/core/keystore/Cargo.toml index 00a653c114168..2e40e5953fffa 100644 --- a/core/keystore/Cargo.toml +++ b/core/keystore/Cargo.toml @@ -5,8 +5,9 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -derive_more = "0.14.0" +derive_more = "0.15.0" primitives = { package = "substrate-primitives", path = "../primitives" } +app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" } hex = "0.3" rand = "0.6" serde_json = "1.0" diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index f60b55fd84f27..eabdcf9cac086 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -21,10 +21,11 @@ use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}}; use primitives::{ - crypto::{KeyTypeId, AppPublic, AppKey, AppPair, Pair as PairT, Public, IsWrappedBy, Protected}, - traits::KeyStore, ed25519, sr25519, + crypto::{KeyTypeId, Pair as PairT, Public, IsWrappedBy, Protected}, traits::KeyStore, }; +use app_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519}; + /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] pub enum Error { @@ -257,7 +258,6 @@ impl KeyStore for Store { mod tests { use super::*; use tempdir::TempDir; - use primitives::{ed25519, sr25519}; use primitives::crypto::Ss58Codec; #[test] diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index b6c2a5baf89f1..67a39bcd4a700 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -18,12 +18,13 @@ //! Cryptographic utilities. // end::description[] +#[cfg(feature ="std")] use rstd::convert::{TryFrom, TryInto}; #[cfg(feature = "std")] use parking_lot::Mutex; #[cfg(feature = "std")] use rand::{RngCore, rngs::OsRng}; -use parity_codec::{Encode, Decode, Codec}; +use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use regex::Regex; #[cfg(feature = "std")] @@ -761,57 +762,6 @@ impl UncheckedFrom for Outer where } } -/// An application-specific key. -pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { - /// The corresponding type as a generic crypto type. - type UntypedGeneric: IsWrappedBy; - - /// The corresponding public key type in this application scheme. - type Public: AppPublic; - - /// The corresponding key pair type in this application scheme. - #[cfg(feature="std")] - type Pair: AppPair; - - /// The corresponding signature type in this application scheme. - type Signature: AppSignature; - - /// An identifier for this application-specific key type. - const ID: KeyTypeId; -} - -/// Type which implements Debug and Hash in std, not when no-std (std variant). -#[cfg(feature = "std")] -pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} -#[cfg(feature = "std")] -impl MaybeDebugHash for T {} - -/// Type which implements Debug and Hash in std, not when no-std (no-std variant). -#[cfg(not(feature = "std"))] -pub trait MaybeDebugHash {} -#[cfg(not(feature = "std"))] -impl MaybeDebugHash for T {} - -/// A application's public key. -pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec { - /// The wrapped type which is just a plain instance of `Public`. - type Generic: - IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec; -} - -/// A application's public key. -#[cfg(feature = "std")] -pub trait AppPair: AppKey + Pair::Public> { - /// The wrapped type which is just a plain instance of `Pair`. - type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; -} - -/// A application's public key. -pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { - /// The wrapped type which is just a plain instance of `Signature`. - type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; -} - /// Implement `AsRef` and `AsMut` for the provided type. #[macro_export] macro_rules! impl_as_ref_mut { @@ -829,263 +779,6 @@ macro_rules! impl_as_ref_mut { } } -/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer` -/// where . -/// -/// ```rust -/// substrate_primitives::wrap! { -/// pub struct Wrapper(u32); -/// } -/// ``` -#[macro_export] -macro_rules! wrap { - ($( #[ $attr:meta ] )* struct $outer:ident($inner:ty);) => { - $( #[ $attr ] )* - struct $outer( $inner ); - $crate::wrap!($inner, $outer); - }; - ($( #[ $attr:meta ] )* pub struct $outer:ident($inner:ty);) => { - $( #[ $attr ] )* - pub struct $outer( $inner ); - $crate::wrap!($inner, $outer); - }; - ($inner:ty, $outer:ty) => { - impl $crate::crypto::Wraps for $outer { - type Inner = $inner; - } - impl From<$inner> for $outer { - fn from(inner: $inner) -> Self { - Self(inner) - } - } - impl From<$outer> for $inner { - fn from(outer: $outer) -> Self { - outer.0 - } - } - impl AsRef<$inner> for $outer { - fn as_ref(&self) -> &$inner { - &self.0 - } - } - impl AsMut<$inner> for $outer { - fn as_mut(&mut self) -> &mut $inner { - &mut self.0 - } - } - } -} - -/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new -/// Application-specific types whose identifier is `$key_type`. -/// -/// ```rust -///# use substrate_primitives::{app_crypto, wrap, ed25519, crypto::KeyTypeId}; -/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` -/// // of value `b"fuba"`. -/// app_crypto!(ed25519, KeyTypeId(*b"_uba")); -/// ``` -#[macro_export] -macro_rules! app_crypto { - ($module:ident, $key_type:expr) => { - #[cfg(feature="std")] - $crate::app_crypto!($module::Pair, $module::Public, $module::Signature, $key_type); - #[cfg(not(feature="std"))] - $crate::app_crypto!($module::Public, $module::Signature, $key_type); - }; - ($pair:ty, $public:ty, $sig:ty, $key_type:expr) => { - $crate::app_crypto!($public, $sig, $key_type); - - $crate::wrap!{ - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. - #[derive(Clone)] - pub struct Pair($pair); - } - - impl $crate::crypto::CryptoType for Pair { - const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; - type Pair = Pair; - } - #[cfg(feature = "std")] - impl $crate::crypto::Pair for Pair { - type Public = Public; - type Seed = <$pair as $crate::crypto::Pair>::Seed; - type Signature = Signature; - type DeriveError = <$pair as $crate::crypto::Pair>::DeriveError; - fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { - let r = <$pair>::generate_with_phrase(password); - (Self(r.0), r.1, r.2) - } - fn from_phrase(phrase: &str, password: Option<&str>) - -> Result<(Self, Self::Seed), $crate::crypto::SecretStringError> - { - <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) - } - fn derive< - Iter: Iterator - >(&self, path: Iter) -> Result { - self.0.derive(path).map(Self) - } - fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) } - fn from_seed_slice(seed: &[u8]) -> Result { - <$pair>::from_seed_slice(seed).map(Self) - } - fn from_standard_components< - I: Iterator - >( - seed: &str, - password: Option<&str>, - path: I, - ) -> Result { - <$pair>::from_standard_components::(seed, password, path).map(Self) - } - fn sign(&self, msg: &[u8]) -> Self::Signature { - Signature(self.0.sign(msg)) - } - fn verify, M: AsRef<[u8]>>( - sig: &Self::Signature, - message: M, - pubkey: P, - ) -> bool { - <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) - } - fn verify_weak, M: AsRef<[u8]>>( - sig: &[u8], - message: M, - pubkey: P, - ) -> bool { - <$pair>::verify_weak(sig, message, pubkey) - } - fn public(&self) -> Self::Public { Public(self.0.public()) } - fn to_raw_vec(&self) -> Vec { self.0.to_raw_vec() } - } - impl $crate::crypto::AppKey for Pair { - type UntypedGeneric = $pair; - type Public = Public; - type Pair = Pair; - type Signature = Signature; - const ID: $crate::crypto::KeyTypeId = $key_type; - } - impl $crate::crypto::AppPair for Pair { - type Generic = $pair; - } - }; - ($public:ty, $sig:ty, $key_type:expr) => { - $crate::wrap!{ - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)] - #[cfg_attr(feature = "std", derive(Debug, Hash))] - pub struct Public($public); - } - // TODO: needed for verify since it takes an AsRef, but should be removed once that is - // refactored. - $crate::impl_as_ref_mut!(Public); - - impl $crate::crypto::Derive for Public { - #[cfg(feature = "std")] - fn derive>(&self, - path: Iter - ) -> Option { - self.0.derive(path).map(Self) - } - } - - #[cfg(feature = "std")] - impl std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - use $crate::crypto::Ss58Codec; - write!(f, "{}", self.0.to_ss58check()) - } - } - #[cfg(feature = "std")] - impl $crate::serde::Serialize for Public { - fn serialize(&self, serializer: S) -> std::result::Result where - S: $crate::serde::Serializer - { - use $crate::crypto::Ss58Codec; - serializer.serialize_str(&self.to_ss58check()) - } - } - #[cfg(feature = "std")] - impl<'de> $crate::serde::Deserialize<'de> for Public { - fn deserialize(deserializer: D) -> std::result::Result where - D: $crate::serde::Deserializer<'de> - { - use $crate::crypto::Ss58Codec; - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) - } - } - - impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { self.0.as_ref() } - } - - impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } - } - - impl $crate::crypto::CryptoType for Public { - const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; - #[cfg(feature="std")] - type Pair = Pair; - } - - impl $crate::crypto::Public for Public { - fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } - } - - impl $crate::crypto::AppKey for Public { - type UntypedGeneric = $public; - type Public = Public; - #[cfg(feature="std")] - type Pair = Pair; - type Signature = Signature; - const ID: $crate::crypto::KeyTypeId = $key_type; - } - - impl $crate::crypto::AppPublic for Public { - type Generic = $public; - } - - $crate::wrap! { - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, $crate::Encode, $crate::Decode)] - #[cfg_attr(feature = "std", derive(Debug, Hash))] - pub struct Signature($sig); - } - - impl $crate::crypto::Deref for Signature { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { self.0.as_ref() } - } - - impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { self.0.as_ref() } - } - - impl $crate::crypto::CryptoType for Signature { - const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; - #[cfg(feature="std")] - type Pair = Pair; - } - - impl $crate::crypto::AppKey for Signature { - type UntypedGeneric = $sig; - type Public = Public; - #[cfg(feature="std")] - type Pair = Pair; - type Signature = Signature; - const ID: $crate::crypto::KeyTypeId = $key_type; - } - - impl $crate::crypto::AppSignature for Signature { - type Generic = $sig; - } - } -} - // TODO: remove default cryptos /// Type which has a particular kind of crypto associated with it. diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index a44bf8409fb5a..095e8917d723d 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -497,16 +497,6 @@ impl CryptoType for Pair { type Pair = Pair; } -mod app { - use crate::crypto::key_types::ED25519; - crate::app_crypto!(super, ED25519); -} - -pub use app::Public as AppPublic; -pub use app::Signature as AppSignature; -#[cfg(feature="std")] -pub use app::Pair as AppPair; - #[cfg(test)] mod test { use super::*; diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 60814baff915d..25f4e883d9d7b 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -535,16 +535,6 @@ impl CryptoType for Pair { type Pair = Pair; } -mod app { - use crate::crypto::key_types::SR25519; - crate::app_crypto!(super, SR25519); -} - -pub use app::Public as AppPublic; -pub use app::Signature as AppSignature; -#[cfg(feature = "std")] -pub use app::Pair as AppPair; - #[cfg(test)] mod test { use super::*; diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index 61921e5f035c6..ff8d68e6494f6 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -16,6 +16,7 @@ //! Shareable Substrate traits. +#[cfg(feature = "std")] use crate::{crypto::KeyTypeId, ed25519, sr25519}; /// Something that generates, stores and provides access to keys. diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index ac899f689afaa..b991aa2de447a 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -22,7 +22,8 @@ target_info = "0.1" keystore = { package = "substrate-keystore", path = "../../core/keystore" } sr-io = { path = "../../core/sr-io" } sr-primitives = { path = "../../core/sr-primitives" } -primitives = { package = "substrate-primitives", path = "../../core/primitives" } +primitives = { package = "substrate-primitives", path = "../primitives" } +app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" } 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/core/service/src/components.rs b/core/service/src/components.rs index d6f0147638e6e..61dd35c7635ce 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -32,7 +32,8 @@ use sr_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256, crypto::AppPair, traits::KeyStorePtr}; +use primitives::{Blake2Hasher, H256, traits::KeyStorePtr}; +use app_crypto::AppPair; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor}; use futures03::channel::mpsc; diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 4a78e9bfb96f7..6300cc90143c0 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -175,8 +175,8 @@ impl Service { Ok(mut ks) => { if let Some(ref seed) = config.dev_key_seed { //TODO: Make sure we generate for all types and apps - ks.generate_from_seed::(&seed)?; - ks.generate_from_seed::(&seed)?; + ks.generate_from_seed::(&seed)?; + ks.generate_from_seed::(&seed)?; } Some(Arc::new(parking_lot::RwLock::new(ks))) diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index f736df0e01da2..1d49045aaf126 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -10,6 +10,7 @@ integer-sqrt = { version = "0.1.2" } serde = { version = "1.0", optional = true, features = ["derive"] } codec = { package = "parity-codec", version = "4.1.1", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../application-crypto", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4", optional = true } @@ -29,4 +30,5 @@ std = [ "runtime_io/std", "codec/std", "primitives/std", + "app-crypto/std", ] diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 2325678073fb4..ee26335d6609a 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -52,7 +52,8 @@ pub mod transaction_validity; pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. -pub use primitives::crypto::{key_types, KeyTypeId, AppKey, Kind, CryptoType}; +pub use primitives::crypto::{key_types, KeyTypeId, Kind, CryptoType}; +pub use app_crypto::AppKey; /// A message indicating an invalid signature in extrinsic. pub const BAD_SIGNATURE: &str = "bad signature in extrinsic"; diff --git a/srml/aura/Cargo.toml b/srml/aura/Cargo.toml index 9ce36582836ed..f25a63a732e37 100644 --- a/srml/aura/Cargo.toml +++ b/srml/aura/Cargo.toml @@ -11,6 +11,7 @@ inherents = { package = "substrate-inherents", path = "../../core/inherents", de rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../../core/application-crypto", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } @@ -37,4 +38,5 @@ std = [ "staking/std", "inherents/std", "substrate-consensus-aura-primitives/std", + "app-crypto/std", ] diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index f2f5586cae29a..ab90f4470f6c8 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -53,7 +53,7 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; -use primitives::crypto::AppPublic; +use app_crypto::AppPublic; use sr_primitives::{ traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember}, generic::DigestItem, }; diff --git a/srml/im-online/Cargo.toml b/srml/im-online/Cargo.toml index c015e5e4c51a8..e3948ff2831f1 100644 --- a/srml/im-online/Cargo.toml +++ b/srml/im-online/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] } sr-primitives = { path = "../../core/sr-primitives", default-features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../../core/application-crypto", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } serde = { version = "1.0", optional = true } session = { package = "srml-session", path = "../session", default-features = false } @@ -26,4 +27,5 @@ std = [ "srml-support/std", "sr-io/std", "system/std", + "app-crypto/std", ] diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 46d374d2e9eca..be4c966da7cb1 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -86,8 +86,8 @@ use srml_support::{ use system::ensure_none; mod app { - pub use primitives::sr25519 as crypto; - use primitives::{app_crypto, crypto::key_types::IM_ONLINE, sr25519}; + pub use app_crypto::sr25519 as crypto; + use app_crypto::{app_crypto, key_types::IM_ONLINE, sr25519}; app_crypto!(sr25519, IM_ONLINE); } From 569c8a377b59afb6f2dc513bafdbc8c3c07f0289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 5 Aug 2019 10:08:41 +0200 Subject: [PATCH 44/80] Update `Cargo.lock` --- Cargo.lock | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c9069f5e3abd3..48a6ffad4649b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -695,6 +695,19 @@ dependencies = [ "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "derive_more" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "difference" version = "2.0.0" @@ -6107,6 +6120,7 @@ dependencies = [ "checksum curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d4b820e8711c211745880150f5fac78ab07d6e3851d8ce9f5a02cedc199174c" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839" +"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" From 6820c8b7e223a87f61a00a192fe4e3aa8dee84c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 5 Aug 2019 18:22:11 +0200 Subject: [PATCH 45/80] Make the crypto stuff usable from the runtime --- Cargo.lock | 1 + core/application-crypto/Cargo.toml | 3 +- core/application-crypto/src/ed25519.rs | 47 ++++++++++ core/application-crypto/src/lib.rs | 103 ++++++---------------- core/application-crypto/src/sr25519.rs | 47 ++++++++++ core/application-crypto/src/traits.rs | 114 +++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 80 deletions(-) create mode 100644 core/application-crypto/src/ed25519.rs create mode 100644 core/application-crypto/src/sr25519.rs create mode 100644 core/application-crypto/src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index 48a6ffad4649b..96d8c8836261b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4243,6 +4243,7 @@ version = "2.0.0" dependencies = [ "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", "sr-std 2.0.0", "substrate-primitives 2.0.0", ] diff --git a/core/application-crypto/Cargo.toml b/core/application-crypto/Cargo.toml index 06b1a6143ab12..f5e9045b9cfb4 100644 --- a/core/application-crypto/Cargo.toml +++ b/core/application-crypto/Cargo.toml @@ -10,7 +10,8 @@ primitives = { package = "substrate-primitives", path = "../primitives", default codec = { package = "parity-codec", version = "4.1.3", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } +rio = { package = "sr-io", path = "../sr-io", default-features = false } [features] default = [ "std" ] -std = [ "primitives/std", "codec/std", "serde", "rstd/std" ] +std = [ "primitives/std", "codec/std", "serde", "rstd/std", "rio/std" ] diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs new file mode 100644 index 0000000000000..044a10425fe95 --- /dev/null +++ b/core/application-crypto/src/ed25519.rs @@ -0,0 +1,47 @@ +// 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 . + +//! Sr25519 crypto types. + +use crate::{RuntimePublic, KeyTypeId}; + +pub use primitives::ed25519::*; + +mod app { + use crate::key_types::ED25519; + crate::app_crypto!(super, ED25519); +} + +pub use app::Public as AppPublic; +pub use app::Signature as AppSignature; +#[cfg(feature="std")] +pub use app::Pair as AppPair; + +impl RuntimePublic for Public { + type Signature = Signature; + + fn generate_pair(key_type: KeyTypeId) -> Self { + Self::from_raw(rio::ed25519_generate(key_type)) + } + + fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { + rio::ed25519_sign(key_type, self, msg).map(Signature::from_raw) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + rio::ed25519_verify(&signature.0, msg.as_ref(), self) + } +} \ No newline at end of file diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index 9baa9d314f139..d19b69569d124 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -35,35 +35,11 @@ pub use serde; #[doc(hidden)] pub use rstd::ops::Deref; -/// `ed25519` crypto types. -pub mod ed25519 { - pub use primitives::ed25519::*; +pub mod ed25519; +pub mod sr25519; +mod traits; - mod app { - use crate::key_types::ED25519; - crate::app_crypto!(super, ED25519); - } - - pub use app::Public as AppPublic; - pub use app::Signature as AppSignature; - #[cfg(feature="std")] - pub use app::Pair as AppPair; -} - -/// `sr25519` crypto types. -pub mod sr25519 { - pub use primitives::sr25519::*; - - mod app { - use crate::key_types::SR25519; - crate::app_crypto!(super, SR25519); - } - - pub use app::Public as AppPublic; - pub use app::Signature as AppSignature; - #[cfg(feature="std")] - pub use app::Pair as AppPair; -} +pub use traits::*; /// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new /// Application-specific types whose identifier is `$key_type`. @@ -241,6 +217,26 @@ macro_rules! app_crypto { type Generic = $public; } + impl $crate::RuntimeAppPublic for Public where $public: $crate::RuntimePublic { + type Signature = Signature; + + fn generate_pair() -> Self { + Self(<$public as $crate::RuntimePublic>::generate_pair($key_type)) + } + + fn sign>(&self, msg: &M) -> Option { + <$public as $crate::RuntimePublic>::sign( + self.as_ref(), + $key_type, + msg, + ).map(Signature) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + <$public as $crate::RuntimePublic>::verify(self.as_ref(), msg, &signature.as_ref()) + } + } + $crate::wrap! { /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. #[derive(Clone, Default, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode)] @@ -324,54 +320,3 @@ macro_rules! wrap { } } } - -/// An application-specific key. -pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { - /// The corresponding type as a generic crypto type. - type UntypedGeneric: IsWrappedBy; - - /// The corresponding public key type in this application scheme. - type Public: AppPublic; - - /// The corresponding key pair type in this application scheme. - #[cfg(feature="std")] - type Pair: AppPair; - - /// The corresponding signature type in this application scheme. - type Signature: AppSignature; - - /// An identifier for this application-specific key type. - const ID: KeyTypeId; -} - -/// Type which implements Debug and Hash in std, not when no-std (std variant). -#[cfg(feature = "std")] -pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} -#[cfg(feature = "std")] -impl MaybeDebugHash for T {} - -/// Type which implements Debug and Hash in std, not when no-std (no-std variant). -#[cfg(not(feature = "std"))] -pub trait MaybeDebugHash {} -#[cfg(not(feature = "std"))] -impl MaybeDebugHash for T {} - -/// A application's public key. -pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec { - /// The wrapped type which is just a plain instance of `Public`. - type Generic: - IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec; -} - -/// A application's public key. -#[cfg(feature = "std")] -pub trait AppPair: AppKey + Pair::Public> { - /// The wrapped type which is just a plain instance of `Pair`. - type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; -} - -/// A application's public key. -pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { - /// The wrapped type which is just a plain instance of `Signature`. - type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; -} diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs new file mode 100644 index 0000000000000..22a92897b0ac7 --- /dev/null +++ b/core/application-crypto/src/sr25519.rs @@ -0,0 +1,47 @@ +// 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 . + +//! Sr25519 crypto types. + +use crate::{RuntimePublic, KeyTypeId}; + +pub use primitives::sr25519::*; + +mod app { + use crate::key_types::SR25519; + crate::app_crypto!(super, SR25519); +} + +pub use app::Public as AppPublic; +pub use app::Signature as AppSignature; +#[cfg(feature="std")] +pub use app::Pair as AppPair; + +impl RuntimePublic for Public { + type Signature = Signature; + + fn generate_pair(key_type: KeyTypeId) -> Self { + Self::from_raw(rio::sr25519_generate(key_type)) + } + + fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { + rio::sr25519_sign(key_type, self, msg).map(Signature::from_raw) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + rio::sr25519_verify(&signature.0, msg.as_ref(), self) + } +} \ No newline at end of file diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs new file mode 100644 index 0000000000000..46f1cac583521 --- /dev/null +++ b/core/application-crypto/src/traits.rs @@ -0,0 +1,114 @@ +// 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 . + +use primitives::crypto::{KeyTypeId, CryptoType, IsWrappedBy, Public}; +#[cfg(feature = "std")] +use primitives::crypto::Pair; + +/// An application-specific key. +pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { + /// The corresponding type as a generic crypto type. + type UntypedGeneric: IsWrappedBy; + + /// The corresponding public key type in this application scheme. + type Public: AppPublic; + + /// The corresponding key pair type in this application scheme. + #[cfg(feature="std")] + type Pair: AppPair; + + /// The corresponding signature type in this application scheme. + type Signature: AppSignature; + + /// An identifier for this application-specific key type. + const ID: KeyTypeId; +} + +/// Type which implements Debug and Hash in std, not when no-std (std variant). +#[cfg(feature = "std")] +pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} +#[cfg(feature = "std")] +impl MaybeDebugHash for T {} + +/// Type which implements Debug and Hash in std, not when no-std (no-std variant). +#[cfg(not(feature = "std"))] +pub trait MaybeDebugHash {} +#[cfg(not(feature = "std"))] +impl MaybeDebugHash for T {} + +/// A application's public key. +pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec { + /// The wrapped type which is just a plain instance of `Public`. + type Generic: + IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec; +} + +/// A application's key pair. +#[cfg(feature = "std")] +pub trait AppPair: AppKey + Pair::Public> { + /// The wrapped type which is just a plain instance of `Pair`. + type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; +} + +/// A application's signature. +pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { + /// The wrapped type which is just a plain instance of `Signature`. + type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; +} + +/// A runtime interface for a public key. +pub trait RuntimePublic: Sized { + /// The signature that will be generated when signing with the corresponding private key. + type Signature; + + /// Generate a public/private pair for the given key type and store it in the keystore. + /// + /// Returns the generated public key. + fn generate_pair(key_type: KeyTypeId) -> Self; + + /// Sign the given message with the corresponding private key of this public key. + /// + /// The private key will be requested from the keystore using the given key type. + /// + /// Returns the signature or `None` if the private key could not be found or some other error + /// occurred. + fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option; + + /// Verify that the given signature matches the given message using this public key. + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool; +} + +/// A runtime interface for a application's public key. +pub trait RuntimeAppPublic: Sized { + /// The signature that will be generated when signing with the corresponding private key. + type Signature; + + /// Generate a public/private pair and store it in the keystore. + /// + /// Returns the generated public key. + fn generate_pair() -> Self; + + /// Sign the given message with the corresponding private key of this public key. + /// + /// The private key will be requested from the keystore. + /// + /// Returns the signature or `None` if the private key could not be found or some other error + /// occurred. + fn sign>(&self, msg: &M) -> Option; + + /// Verify that the given signature matches the given message using this public key. + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool; +} From 3ec27bdf1be7d76b81bcb2a8b82d70722ed83a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 5 Aug 2019 23:01:22 +0200 Subject: [PATCH 46/80] Adds some runtime crypto tests --- Cargo.lock | 3 + core/application-crypto/Cargo.toml | 4 + core/application-crypto/src/ed25519.rs | 28 +++++++ core/application-crypto/src/sr25519.rs | 28 +++++++ core/primitives/src/crypto.rs | 2 +- core/primitives/src/lib.rs | 1 + core/primitives/src/testing.rs | 107 +++++++++++++++++++++++++ core/test-runtime/Cargo.toml | 2 + core/test-runtime/src/lib.rs | 51 +++++++++++- 9 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 core/primitives/src/testing.rs diff --git a/Cargo.lock b/Cargo.lock index 96d8c8836261b..edfc7064b15d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4244,8 +4244,10 @@ dependencies = [ "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", + "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-primitives 2.0.0", + "substrate-test-runtime-client 2.0.0", ] [[package]] @@ -4983,6 +4985,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura-primitives 2.0.0", "substrate-consensus-babe-primitives 2.0.0", diff --git a/core/application-crypto/Cargo.toml b/core/application-crypto/Cargo.toml index f5e9045b9cfb4..66266f3e38449 100644 --- a/core/application-crypto/Cargo.toml +++ b/core/application-crypto/Cargo.toml @@ -12,6 +12,10 @@ serde = { version = "1.0", optional = true, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } rio = { package = "sr-io", path = "../sr-io", default-features = false } +[dev-dependencies] +test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" } +sr-primitives = { path = "../sr-primitives" } + [features] default = [ "std" ] std = [ "primitives/std", "codec/std", "serde", "rstd/std", "rio/std" ] diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index 044a10425fe95..0d8a916ebe903 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -44,4 +44,32 @@ impl RuntimePublic for Public { fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { rio::ed25519_verify(&signature.0, msg.as_ref(), self) } +} + +#[cfg(test)] +mod tests { + use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; + use primitives::{testing::KeyStore, crypto::Pair}; + use test_client::{ + TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, + runtime::{TestAPI, app_crypto::ed25519::AppPair}, + }; + + #[test] + fn ed25519_works_in_runtime() { + let keystore = KeyStore::new(); + let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); + let signature = test_client.runtime_api() + .test_ed25519_crypto(&BlockId::Number(0)) + .expect("Tests `ed25519` crypto."); + + let key_pair: AppPair = keystore.read() + .ed25519_pairs(crate::key_types::ED25519) + .get(0) + .expect("There should be at least one `ed25519` key in the keystore.") + .clone() + .into(); + + assert!(AppPair::verify(&signature, "ed25519", key_pair.public())); + } } \ No newline at end of file diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 22a92897b0ac7..4d3c45a163962 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -44,4 +44,32 @@ impl RuntimePublic for Public { fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { rio::sr25519_verify(&signature.0, msg.as_ref(), self) } +} + +#[cfg(test)] +mod tests { + use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; + use primitives::{testing::KeyStore, crypto::Pair}; + use test_client::{ + TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, + runtime::{TestAPI, app_crypto::sr25519::AppPair}, + }; + + #[test] + fn sr25519_works_in_runtime() { + let keystore = KeyStore::new(); + let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); + let signature = test_client.runtime_api() + .test_sr25519_crypto(&BlockId::Number(0)) + .expect("Tests `sr25519` crypto."); + + let key_pair: AppPair = keystore.read() + .sr25519_pairs(crate::key_types::SR25519) + .get(0) + .expect("There should be at least one `sr25519` key in the keystore.") + .clone() + .into(); + + assert!(AppPair::verify(&signature, "sr25519", key_pair.public())); + } } \ No newline at end of file diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 67a39bcd4a700..49e5d04363f6a 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -467,7 +467,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { /// Trait suitable for typical cryptographic PKI key public type. pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync { - /// A new instance from the given slice that should be 32 bytes long. + /// A new instance from the given slice. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index cd69b52c619bc..5a7fa8e5219a7 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -64,6 +64,7 @@ pub mod storage; pub mod uint; mod changes_trie; pub mod traits; +pub mod testing; #[cfg(test)] mod tests; diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs new file mode 100644 index 0000000000000..33cbd0d20177c --- /dev/null +++ b/core/primitives/src/testing.rs @@ -0,0 +1,107 @@ +// Copyright 2017-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 . + +//! Types that should only be used for testing! + +#[cfg(feature = "std")] +use crate::{ed25519, sr25519, crypto::{Public, Pair, KeyTypeId}, traits::KeyStorePtr}; + +/// A keystore implementation usable in tests. +#[cfg(feature = "std")] +#[derive(Default)] +pub struct KeyStore { + /// `KeyTypeId` maps to public keys and public keys map to private keys. + keys: std::collections::HashMap, Vec>>, +} + +#[cfg(feature = "std")] +impl KeyStore { + /// Creates a new instance of `Self`. + pub fn new() -> std::sync::Arc> { + std::sync::Arc::new(parking_lot::RwLock::new(Self::default())) + } + + /// Returns all key pairs for a given key type as `sr25519` pairs. + pub fn sr25519_pairs(&self, id: KeyTypeId) -> Vec { + self.keys.get(&id) + .map(|keys| + keys.values() + .map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid")) + .collect() + ) + .unwrap_or_default() + } + + /// Returns all key pairs for a given key type as `ed25519` pairs. + pub fn ed25519_pairs(&self, id: KeyTypeId) -> Vec { + self.keys.get(&id) + .map(|keys| + keys.values() + .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) + .collect() + ) + .unwrap_or_default() + } +} + +#[cfg(feature = "std")] +impl crate::traits::KeyStore for KeyStore { + fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String> { + match seed { + Some(seed) => { + let pair = sr25519::Pair::from_string(seed, None).expect("Generates an `sr25519` pair."); + self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); + Ok(pair.public().0) + }, + None => { + let (pair, _) = sr25519::Pair::generate(); + self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); + Ok(pair.public().0) + } + } + } + + fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { + self.keys.get(&id) + .and_then(|inner| + inner.get(pub_key.as_slice()) + .map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid")) + ) + } + + fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String> { + match seed { + Some(seed) => { + let pair = ed25519::Pair::from_string(seed, None).expect("Generates an `ed25519` pair."); + self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); + Ok(pair.public().0) + }, + None => { + let (pair, _) = ed25519::Pair::generate(); + self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); + Ok(pair.public().0) + } + } + } + + fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { + self.keys.get(&id) + .and_then(|inner| + inner.get(pub_key.as_slice()) + .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) + ) + } +} \ No newline at end of file diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index 03ba10c5fbb1a..7c2758b26a49a 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -12,6 +12,7 @@ parity-codec = { version = "4.1.1", default-features = false, features = ["deriv keyring = { package = "substrate-keyring", path = "../keyring", optional = true } substrate-client = { path = "../client", default-features = false } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } +app-crypto = { package = "substrate-application-crypto", path = "../application-crypto", default-features = false } inherents = { package = "substrate-inherents", path = "../inherents", default-features = false } aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../consensus/aura/primitives", default-features = false } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives", default-features = false } @@ -67,4 +68,5 @@ std = [ "srml-babe/std", "srml-timestamp/std", "srml-system/std", + "app-crypto/std", ] diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index a5c60ef32b488..10ed3fc243c9f 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -25,7 +25,9 @@ pub mod system; use rstd::{prelude::*, marker::PhantomData}; use parity_codec::{Encode, Decode, Input}; -use primitives::Blake2Hasher; +use primitives::{Blake2Hasher, OpaqueMetadata}; +use app_crypto::{ed25519, sr25519, RuntimeAppPublic}; +pub use app_crypto; use trie_db::{TrieMut, Trie}; use substrate_trie::PrefixedMemoryDB; use substrate_trie::trie_types::{TrieDB, TrieDBMut}; @@ -44,7 +46,6 @@ use sr_primitives::{ }; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; -use primitives::{sr25519, OpaqueMetadata}; #[cfg(any(feature = "std", test))] use runtime_version::NativeVersion; use runtime_support::{impl_outer_origin, parameter_types}; @@ -266,6 +267,14 @@ cfg_if! { /// Returns if no block was initialized. #[skip_initialize_block] fn without_initialize_block() -> bool; + /// Test that `ed25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `ed25519`. + fn test_ed25519_crypto() -> ed25519::AppSignature; + /// Test that `sr25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `sr25519`. + fn test_sr25519_crypto() -> sr25519::AppSignature; } } } else { @@ -299,6 +308,14 @@ cfg_if! { /// Returns if no block was initialized. #[skip_initialize_block] fn without_initialize_block() -> bool; + /// Test that `ed25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `ed25519`. + fn test_ed25519_crypto() -> ed25519::AppSignature; + /// Test that `sr25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `sr25519`. + fn test_sr25519_crypto() -> sr25519::AppSignature; } } } @@ -545,6 +562,14 @@ cfg_if! { fn take_block_number() -> Option { system::take_block_number() } + + fn test_ed25519_crypto() -> ed25519::AppSignature { + test_ed25519_crypto() + } + + fn test_sr25519_crypto() -> sr25519::AppSignature { + test_sr25519_crypto() + } } impl aura_primitives::AuraApi for Runtime { @@ -741,6 +766,14 @@ cfg_if! { fn take_block_number() -> Option { system::take_block_number() } + + fn test_ed25519_crypto() -> ed25519::AppSignature { + test_ed25519_crypto() + } + + fn test_sr25519_crypto() -> sr25519::AppSignature { + test_sr25519_crypto() + } } impl aura_primitives::AuraApi for Runtime { @@ -786,6 +819,20 @@ cfg_if! { } } +fn test_ed25519_crypto() -> ed25519::AppSignature { + let public = ed25519::AppPublic::generate_pair(); + let signature = public.sign(&"ed25519").expect("Generates a valid `ed25519` signature."); + assert!(public.verify(&"ed25519", &signature)); + signature +} + +fn test_sr25519_crypto() -> sr25519::AppSignature { + let public = sr25519::AppPublic::generate_pair(); + let signature = public.sign(&"sr25519").expect("Generates a valid `sr25519` signature."); + assert!(public.verify(&"sr25519", &signature)); + signature +} + #[cfg(test)] mod tests { use substrate_test_runtime_client::{ From 1e3e1ee529aa6198f1b03be357abd87490a35cc5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Aug 2019 23:05:06 +0200 Subject: [PATCH 47/80] Use last finalized block for grandpa authority --- core/finality-grandpa/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 31505ae474be9..50f1dc84ce88e 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -809,7 +809,7 @@ fn authority(client: &C, keystore: Arc) -> Option where C::Api: GrandpaApi<::Type> { let owned = keystore.public_keys::().ok()?; - let at = BlockId::Number(client.info().best_number); + let at = BlockId::Number(client.info().finalized_number); // The list of authority keys that is current. By default this will just use the state of // the best block, but you might want it to use some other block's state instead if it's // more sophisticated. Grandpa, for example, will probably want to use the state of the last From 649510f04be33612bff2923043ab017537ffa223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 5 Aug 2019 23:27:07 +0200 Subject: [PATCH 48/80] Fix warning --- core/primitives/src/testing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index 33cbd0d20177c..c852ec5f26d52 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -17,7 +17,7 @@ //! Types that should only be used for testing! #[cfg(feature = "std")] -use crate::{ed25519, sr25519, crypto::{Public, Pair, KeyTypeId}, traits::KeyStorePtr}; +use crate::{ed25519, sr25519, crypto::{Public, Pair, KeyTypeId}}; /// A keystore implementation usable in tests. #[cfg(feature = "std")] From a8538da5e04af09862b59f614dd6a8b63fe7791d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 02:19:18 +0200 Subject: [PATCH 49/80] Adds `SessionKeys` runtime api --- Cargo.lock | 9 ++++++ Cargo.toml | 1 + core/application-crypto/src/ed25519.rs | 4 +-- core/application-crypto/src/lib.rs | 4 +-- core/application-crypto/src/sr25519.rs | 4 +-- core/application-crypto/src/traits.rs | 4 +-- core/executor/src/wasm_executor.rs | 38 +++++++++++++++++++++++--- core/session/Cargo.toml | 13 +++++++++ core/session/src/lib.rs | 33 ++++++++++++++++++++++ core/sr-io/src/lib.rs | 4 +-- core/sr-io/with_std.rs | 8 +++--- core/sr-io/without_std.rs | 18 ++++++++---- core/sr-primitives/src/lib.rs | 3 ++ core/sr-primitives/src/traits.rs | 30 ++++++++++++++------ core/test-runtime/src/lib.rs | 4 +-- node/runtime/Cargo.toml | 2 ++ node/runtime/src/lib.rs | 7 +++++ 17 files changed, 151 insertions(+), 35 deletions(-) create mode 100644 core/session/Cargo.toml create mode 100644 core/session/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index edfc7064b15d0..25cea8d4179ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2397,6 +2397,7 @@ dependencies = [ "substrate-keyring 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", + "substrate-session 2.0.0", "substrate-wasm-builder-runner 1.0.2", ] @@ -4901,6 +4902,14 @@ dependencies = [ "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-session" +version = "2.0.0" +dependencies = [ + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "substrate-state-db" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 9ecf79257d8a0..38ca09247bc14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "core/serializer", "core/service", "core/service/test", + "core/session", "core/sr-api-macros", "core/sr-io", "core/sr-primitives", diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index 0d8a916ebe903..b50424a91e12f 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -33,8 +33,8 @@ pub use app::Pair as AppPair; impl RuntimePublic for Public { type Signature = Signature; - fn generate_pair(key_type: KeyTypeId) -> Self { - Self::from_raw(rio::ed25519_generate(key_type)) + fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self { + Self::from_raw(rio::ed25519_generate(key_type, seed)) } fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index d19b69569d124..6e6be9dd89bb9 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -220,8 +220,8 @@ macro_rules! app_crypto { impl $crate::RuntimeAppPublic for Public where $public: $crate::RuntimePublic { type Signature = Signature; - fn generate_pair() -> Self { - Self(<$public as $crate::RuntimePublic>::generate_pair($key_type)) + fn generate_pair(seed: Option<&str>) -> Self { + Self(<$public as $crate::RuntimePublic>::generate_pair($key_type, seed)) } fn sign>(&self, msg: &M) -> Option { diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 4d3c45a163962..f57d29cf2d6a2 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -33,8 +33,8 @@ pub use app::Pair as AppPair; impl RuntimePublic for Public { type Signature = Signature; - fn generate_pair(key_type: KeyTypeId) -> Self { - Self::from_raw(rio::sr25519_generate(key_type)) + fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self { + Self::from_raw(rio::sr25519_generate(key_type, seed)) } fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs index 46f1cac583521..4da81f0c58a23 100644 --- a/core/application-crypto/src/traits.rs +++ b/core/application-crypto/src/traits.rs @@ -77,7 +77,7 @@ pub trait RuntimePublic: Sized { /// Generate a public/private pair for the given key type and store it in the keystore. /// /// Returns the generated public key. - fn generate_pair(key_type: KeyTypeId) -> Self; + fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self; /// Sign the given message with the corresponding private key of this public key. /// @@ -99,7 +99,7 @@ pub trait RuntimeAppPublic: Sized { /// Generate a public/private pair and store it in the keystore. /// /// Returns the generated public key. - fn generate_pair() -> Self; + fn generate_pair(seed: Option<&str>) -> Self; /// Sign the given message with the corresponding private key of this public key. /// diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 3f780a4db1fc2..75e22ec4a43bf 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -661,13 +661,28 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, 5 }) }, - ext_ed25519_generate(id_data: *const u8, out: *mut u8) => { + ext_ed25519_generate(id_data: *const u8, seed: *const u8, seed_len: u32, out: *mut u8) => { let mut id = [0u8; 4]; this.memory.get_into(id_data, &mut id[..]) .map_err(|_| "Invalid attempt to get id in ext_ed25519_generate")?; let key_type = KeyTypeId(id); - let pubkey = runtime_io::ed25519_generate(key_type); + let seed = if seed_len == 0 { + None + } else { + Some( + this.memory.get(seed, seed_len as usize) + .map_err(|_| "Invalid attempt to get seed in ext_ed25519_generate")? + ) + }; + + let seed = seed.as_ref() + .map(|seed| + std::str::from_utf8(&seed) + .map_err(|_| "Seed not a valid utf8 string in ext_sr25119_generate") + ).transpose()?; + + let pubkey = runtime_io::ed25519_generate(key_type, seed); this.memory.set(out, pubkey.as_ref()) .map_err(|_| "Invalid attempt to set out in ext_ed25519_generate".into()) @@ -724,13 +739,28 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, 5 }) }, - ext_sr25519_generate(id_data: *const u8, out: *mut u8) => { + ext_sr25519_generate(id_data: *const u8, seed: *const u8, seed_len: u32, out: *mut u8) => { let mut id = [0u8; 4]; this.memory.get_into(id_data, &mut id[..]) .map_err(|_| "Invalid attempt to get id in ext_sr25519_generate")?; let key_type = KeyTypeId(id); + let seed = if seed_len == 0 { + None + } else { + Some( + this.memory.get(seed, seed_len as usize) + .map_err(|_| "Invalid attempt to get seed in ext_sr25519_generate")? + ) + }; + + let seed = seed.as_ref() + .map(|seed| + std::str::from_utf8(&seed) + .map_err(|_| "Seed not a valid utf8 string in ext_sr25119_generate") + ) + .transpose()?; - let pubkey = runtime_io::sr25519_generate(key_type); + let pubkey = runtime_io::sr25519_generate(key_type, seed); this.memory.set(out, pubkey.as_ref()) .map_err(|_| "Invalid attempt to set out in ext_sr25519_generate".into()) diff --git a/core/session/Cargo.toml b/core/session/Cargo.toml new file mode 100644 index 0000000000000..5fc45f0cb837b --- /dev/null +++ b/core/session/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "substrate-session" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../client", default-features = false } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } + +[features] +default = [ "std" ] +std = [ "client/std", "rstd/std" ] \ No newline at end of file diff --git a/core/session/src/lib.rs b/core/session/src/lib.rs new file mode 100644 index 0000000000000..a78674283baef --- /dev/null +++ b/core/session/src/lib.rs @@ -0,0 +1,33 @@ +// 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 . + +//! Substrate core types around sessions. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::vec::Vec; + +client::decl_runtime_apis! { + /// Session keys runtime api. + pub trait SessionKeys { + /// Generate a set of session keys with optionally using the given seed. + /// + /// The seed needs to be a valid `utf8` string. + /// + /// Returns the concatenated SCALE encoded public keys. + fn generate(seed: Option>) -> Vec; + } +} \ No newline at end of file diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index fe638dcac8236..2598f3e32eab2 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -203,7 +203,7 @@ export_api! { /// Generate an ed22519 key for the given key type and store it in the keystore. /// /// Returns the raw public key. - fn ed25519_generate(id: KeyTypeId) -> [u8; 32]; + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32]; /// Sign the given `msg` with the ed25519 key that corresponds to the given public key and /// key type in the keystore. /// @@ -221,7 +221,7 @@ export_api! { /// Generate an sr22519 key for the given key type and store it in the keystore. /// /// Returns the raw public key. - fn sr25519_generate(id: KeyTypeId) -> [u8; 32]; + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32]; /// Sign the given `msg` with the sr25519 key that corresponds to the given public key and /// key type in the keystore. /// diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 6185aea4b930f..836888c1e7629 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -207,12 +207,12 @@ impl OtherApi for () { } impl CryptoApi for () { - fn ed25519_generate(id: KeyTypeId) -> [u8; 32] { + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { ext::with(|ext| { ext.keystore() .expect("No `keystore` associated for the current context!") .write() - .ed25519_generate_new(id, None) + .ed25519_generate_new(id, seed) .expect("`ed25519_generate` failed") }).expect("`ed25519_generate` cannot be called outside of an Externalities-provided environment.") } @@ -237,12 +237,12 @@ impl CryptoApi for () { ed25519::Pair::verify_weak(sig, msg, pubkey) } - fn sr25519_generate(id: KeyTypeId) -> [u8; 32] { + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { ext::with(|ext| { ext.keystore() .expect("No `keystore` associated for the current context!") .write() - .sr25519_generate_new(id, None) + .sr25519_generate_new(id, seed) .expect("`sr25519_generate` failed") }).expect("`sr25519_generate` cannot be called outside of an Externalities-provided environment.") } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 84a4b30f3f5db..993c445b05c33 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -363,7 +363,7 @@ pub mod ext { /// Generate an `ed25519` key pair for the given key type id and store the public key /// in `out`. - fn ext_ed25519_generate(id: *const u8, out: *mut u8); + fn ext_ed25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8); /// Sign the given `msg` with the `ed25519` key pair that corresponds to then given key /// type id and public key. The raw signature is stored in `out`. @@ -390,7 +390,7 @@ pub mod ext { /// Generate an `sr25519` key pair for the given key type id and store the public /// key in `out`. - fn ext_sr25519_generate(id: *const u8, out: *mut u8); + fn ext_sr25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8); /// Sign the given `msg` with the `sr25519` key pair that corresponds to then given key /// type id and public key. The raw signature is stored in `out`. @@ -912,9 +912,12 @@ impl HashingApi for () { } impl CryptoApi for () { - fn ed25519_generate(id: KeyTypeId) -> [u8; 32] { + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { let mut res = [0u8; 32]; - unsafe { ext_ed25519_generate.get()(id.0.as_ptr(), res.as_mut_ptr()) }; + let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]); + unsafe { + ext_ed25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr()) + }; res } @@ -952,9 +955,12 @@ impl CryptoApi for () { } } - fn sr25519_generate(id: KeyTypeId) -> [u8; 32] { + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { let mut res = [0u8;32]; - unsafe { ext_sr25519_generate.get()(id.0.as_ptr(), res.as_mut_ptr()) }; + let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]); + unsafe { + ext_sr25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr()) + }; res } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index ee26335d6609a..4e9bb58012055 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -31,6 +31,9 @@ pub use rstd; #[doc(hidden)] pub use paste; +#[doc(hidden)] +pub use app_crypto; + #[cfg(feature = "std")] pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 528919938b6b0..7e48a37ff7382 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -1199,14 +1199,14 @@ macro_rules! count { /// just the bytes of the key. /// /// ```rust -/// use sr_primitives::{impl_opaque_keys, key_types, KeyTypeId}; +/// use sr_primitives::{impl_opaque_keys, key_types, KeyTypeId, app_crypto::{sr25519, ed25519}}; /// /// impl_opaque_keys! { /// pub struct Keys { /// #[id(key_types::ED25519)] -/// pub ed25519: [u8; 32], +/// pub ed25519: ed25519::AppPublic, /// #[id(key_types::SR25519)] -/// pub sr25519: [u8; 32], +/// pub sr25519: sr25519::AppPublic, /// } /// } /// ``` @@ -1228,22 +1228,34 @@ macro_rules! impl_opaque_keys { )* } + impl $name { + /// Generate a set of keys with optionally using the given seed. + /// + /// The generated key pairs are stored in the keystore. + /// + /// Returns the concatenated SCALE encoded public keys. + pub fn generate(seed: Option<&str>) -> $crate::rstd::vec::Vec { + let mut keys = $crate::rstd::vec::Vec::new(); + $({ + let key = <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed); + $crate::codec::Encode::encode_to(&key, &mut keys); + })* + keys + } + } + impl $crate::traits::OpaqueKeys for $name { type KeyTypeIds = $crate::rstd::iter::Cloned< $crate::rstd::slice::Iter<'static, $crate::KeyTypeId> >; fn key_ids() -> Self::KeyTypeIds { - [ - $($key_id),* - ].iter().cloned() + [ $($key_id),* ].iter().cloned() } fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] { match i { - $( - i if i == $key_id => self.$field.as_ref(), - )* + $( i if i == $key_id => self.$field.as_ref(), )* _ => &[], } } diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 10ed3fc243c9f..e538c20211306 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -820,14 +820,14 @@ cfg_if! { } fn test_ed25519_crypto() -> ed25519::AppSignature { - let public = ed25519::AppPublic::generate_pair(); + let public = ed25519::AppPublic::generate_pair(None); let signature = public.sign(&"ed25519").expect("Generates a valid `ed25519` signature."); assert!(public.verify(&"ed25519", &signature)); signature } fn test_sr25519_crypto() -> sr25519::AppSignature { - let public = sr25519::AppPublic::generate_pair(); + let public = sr25519::AppPublic::generate_pair(None); let signature = public.sign(&"sr25519").expect("Generates a valid `sr25519` signature."); assert!(public.verify(&"sr25519", &signature)); signature diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index c40e6d779644c..7c2e46b03c7de 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -40,6 +40,7 @@ node-primitives = { path = "../primitives", default-features = false } rustc-hex = { version = "2.0", optional = true } serde = { version = "1.0", optional = true } substrate-keyring = { path = "../../core/keyring", optional = true } +substrate-session = { path = "../../core/session", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../core/utils/wasm-builder-runner" } @@ -83,4 +84,5 @@ std = [ "substrate-keyring", "offchain-primitives/std", "im-online/std", + "substrate-session/std", ] diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 9cfbb084296e1..4446d4f687d3c 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -548,4 +548,11 @@ impl_runtime_apis! { Babe::authorities().into_iter().map(|(a, _)| a).collect() } } + + impl substrate_session::SessionKeys for Runtime { + fn generate(seed: Option>) -> Vec { + let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); + SessionKeys::generate(seed) + } + } } From 497016a177a50c4f39edead79b8c554c54a62662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 02:25:01 +0200 Subject: [PATCH 50/80] Remove `FinalityPair` and `ConsensusPair` --- core/service/src/components.rs | 11 ----------- core/service/src/lib.rs | 7 ------- node-template/src/service.rs | 2 -- node/cli/src/service.rs | 2 -- 4 files changed, 22 deletions(-) diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 61dd35c7635ce..9640723342570 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -33,7 +33,6 @@ use sr_primitives::{ }; use crate::config::Configuration; use primitives::{Blake2Hasher, H256, traits::KeyStorePtr}; -use app_crypto::AppPair; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor}; use futures03::channel::mpsc; @@ -132,12 +131,6 @@ pub type ComponentOffchainStorage = < /// Block type for `Components` pub type ComponentBlock = <::Factory as ServiceFactory>::Block; -/// ConsensusPair type for `Components` -pub type ComponentConsensusPair = <::Factory as ServiceFactory>::ConsensusPair; - -/// FinalityPair type for `Components` -pub type ComponentFinalityPair = <::Factory as ServiceFactory>::FinalityPair; - /// Extrinsic hash type for `Components` pub type ComponentExHash = <::TransactionPoolApi as txpool::ChainApi>::Hash; @@ -291,10 +284,6 @@ pub type TaskExecutor = Arc + pub trait ServiceFactory: 'static + Sized { /// Block type. type Block: BlockT; - /// Consensus crypto type. - type ConsensusPair: AppPair; - /// Finality crypto type. - type FinalityPair: AppPair; /// The type that implements the runtime API. type RuntimeApi: Send + Sync; /// Network protocol extensions. diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 6300cc90143c0..92498350324ca 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -62,7 +62,6 @@ pub use components::{ CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock, FactoryFullConfiguration, RuntimeGenesis, FactoryGenesis, ComponentExHash, ComponentExtrinsic, FactoryExtrinsic, - ComponentConsensusPair, ComponentFinalityPair, }; use components::{StartRPC, MaintainTransactionPool, OffchainWorker}; #[doc(hidden)] @@ -917,8 +916,6 @@ impl network::TransactionPool, ComponentBlock< /// struct Factory { /// // Declare the block type /// Block = Block, -/// ConsensusPair = BabePair, -/// FinalityPair = GrandpaPair, /// RuntimeApi = RuntimeApi, /// // Declare the network protocol and give an initializer. /// NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, @@ -962,8 +959,6 @@ macro_rules! construct_service_factory { $(#[$attr:meta])* struct $name:ident { Block = $block:ty, - ConsensusPair = $consensus_pair:ty, - FinalityPair = $finality_pair:ty, RuntimeApi = $runtime_api:ty, NetworkProtocol = $protocol:ty { $( $protocol_init:tt )* }, RuntimeDispatch = $dispatch:ty, @@ -989,8 +984,6 @@ macro_rules! construct_service_factory { #[allow(unused_variables)] impl $crate::ServiceFactory for $name { type Block = $block; - type ConsensusPair = $consensus_pair; - type FinalityPair = $finality_pair; type RuntimeApi = $runtime_api; type NetworkProtocol = $protocol; type RuntimeDispatch = $dispatch; diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 7a0f2522b4373..92e0153b482c1 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -43,8 +43,6 @@ construct_simple_protocol! { construct_service_factory! { struct Factory { Block = Block, - ConsensusPair = aura_primitives::sr25519::AuthorityPair, - FinalityPair = grandpa_primitives::AuthorityPair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = Executor, diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index afc361796a11e..c2af967b99644 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -89,8 +89,6 @@ impl Default for NodeConfig where F: substrate_service::ServiceFactory { construct_service_factory! { struct Factory { Block = Block, - ConsensusPair = BabePair, - FinalityPair = GrandpaPair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = node_executor::Executor, From 4e3d51d5ec8ab9ffa4fe5d97b2d1649c8673716c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Aug 2019 10:28:06 +0200 Subject: [PATCH 51/80] Minor governance tweaks to get it inline with docs. --- node/runtime/src/lib.rs | 19 +++-- srml/democracy/src/lib.rs | 170 ++++++++++++++------------------------ 2 files changed, 77 insertions(+), 112 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 9cfbb084296e1..b96d936c37b54 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -248,7 +248,7 @@ parameter_types! { pub const EmergencyVotingPeriod: BlockNumber = 3 * 24 * 60 * MINUTES; pub const MinimumDeposit: Balance = 100 * DOLLARS; pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; - pub const CooloffPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; + pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; } impl democracy::Trait for Runtime { @@ -260,12 +260,21 @@ impl democracy::Trait for Runtime { type VotingPeriod = VotingPeriod; type EmergencyVotingPeriod = EmergencyVotingPeriod; type MinimumDeposit = MinimumDeposit; + /// A straight majority of the council can decide what their next motion is. type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilInstance>; - type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>; - type ExternalPushOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalInstance>; - type EmergencyOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilInstance>; + /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. + type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilInstance>; + /// A unanimous council can have the next scheduled referendum be a straight default-carries + /// (NTB) vote. + type ExternalDefaultOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilInstance>; + /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote + /// be tabled immediately and with a shorter voting/enactment period. + type FastTrackOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalInstance>; + // To cancel a proposal which has been passed, 2/3 of the council must agree to it. type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>; - type VetoOrigin = collective::EnsureMember; + // Any single technical committee member may veto a coming council proposal, however they can + // only do it once and it lasts only for the cooloff period. + type VetoOrigin = collective::EnsureMember; type CooloffPeriod = CooloffPeriod; } diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 8c2e0557d1fe1..a8e4728dbe2f7 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -61,6 +61,8 @@ pub enum Conviction { Locked4x, /// 5x votes, locked for 16x... Locked5x, + /// 6x votes, locked for 32x... + Locked6x, } impl Default for Conviction { @@ -78,6 +80,7 @@ impl From for u8 { Conviction::Locked3x => 3, Conviction::Locked4x => 4, Conviction::Locked5x => 5, + Conviction::Locked6x => 6, } } } @@ -92,6 +95,7 @@ impl TryFrom for Conviction { 3 => Conviction::Locked3x, 4 => Conviction::Locked4x, 5 => Conviction::Locked5x, + 6 => Conviction::Locked6x, _ => return Err(()), }) } @@ -108,6 +112,7 @@ impl Conviction { Conviction::Locked3x => 4, Conviction::Locked4x => 8, Conviction::Locked5x => 16, + Conviction::Locked6x => 32, } } @@ -134,7 +139,7 @@ impl Bounded for Conviction { } fn max_value() -> Self { - Conviction::Locked5x + Conviction::Locked6x } } @@ -205,18 +210,19 @@ pub trait Trait: system::Trait + Sized { /// a majority-carries referendum. type ExternalMajorityOrigin: EnsureOrigin; + /// Origin from which the next tabled referendum may be forced; this allows for the tabling of + /// a negative-turnout-bias (default-carries) referendum. + type ExternalDefaultOrigin: EnsureOrigin; + /// Origin from which the next referendum proposed by the external majority may be immediately /// tabled to vote asynchronously in a similar manner to the emergency origin. It remains a /// majority-carries vote. - type ExternalPushOrigin: EnsureOrigin; - - /// Origin from which emergency referenda may be scheduled. - type EmergencyOrigin: EnsureOrigin; + type FastTrackOrigin: EnsureOrigin; - /// Minimum voting period allowed for an emergency referendum. + /// Minimum voting period allowed for an fast-track/emergency referendum. type EmergencyVotingPeriod: Get; - /// Origin from which any referenda may be cancelled in an emergency. + /// Origin from which any referendum may be cancelled in an emergency. type CancellationOrigin: EnsureOrigin; /// Origin for anyone able to veto proposals. @@ -431,32 +437,6 @@ decl_module! { Self::do_vote(who, ref_index, vote) } - /// Schedule an emergency referendum. - /// - /// This will create a new referendum for the `proposal`, approved as long as counted votes - /// exceed `threshold` and, if approved, enacted after the given `delay`. - /// - /// It may be called from either the Root or the Emergency origin. - #[weight = SimpleDispatchInfo::FixedOperational(500_000)] - fn emergency_propose(origin, - proposal: Box, - threshold: VoteThreshold, - voting_period: T::BlockNumber, - delay: T::BlockNumber - ) { - T::EmergencyOrigin::try_origin(origin) - .map(|_| ()) - .or_else(|origin| ensure_root(origin))?; - let now = >::block_number(); - // We don't consider it an error if `vote_period` is too low, but we do enforce the - // minimum. This is primarily due to practicality. If it's an emergency, we don't want - // to introduce more delays than is strictly needed by requiring a potentially costly - // resubmission in the case of a mistakenly low `vote_period`; better to just let the - // referendum take place with the lowest valid value. - let period = voting_period.max(T::EmergencyVotingPeriod::get()); - Self::inject_referendum(now + period, *proposal, threshold, delay).map(|_| ())?; - } - /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same /// referendum. #[weight = SimpleDispatchInfo::FixedOperational(500_000)] @@ -486,17 +466,26 @@ decl_module! { /// Schedule a majority-carries referendum to be tabled next once it is legal to schedule /// an external referendum. + /// + /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a + /// pre-scheduled `external_propose` call. #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] fn external_propose_majority(origin, proposal: Box) { T::ExternalMajorityOrigin::ensure_origin(origin)?; - ensure!(!>::exists(), "proposal already made"); - let proposal_hash = T::Hashing::hash_of(&proposal); - if let Some((until, _)) = >::get(proposal_hash) { - ensure!(>::block_number() >= until, "proposal still blacklisted"); - } >::put((*proposal, VoteThreshold::SimpleMajority)); } + /// Schedule a negative-turnout-bias referendum to be tabled next once it is legal to + /// schedule an external referendum. + /// + /// Unlike `external_propose`, blacklisting has no effect on this and it may replace a + /// pre-scheduled `external_propose` call. + #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] + fn external_propose_default(origin, proposal: Box) { + T::ExternalDefaultOrigin::ensure_origin(origin)?; + >::put((*proposal, VoteThreshold::SuperMajorityAgainst)); + } + /// Schedule the currently externally-proposed majority-carries referendum to be tabled /// immediately. If there is no externally-proposed referendum currently, or if there is one /// but it is not a majority-carries referendum then it fails. @@ -506,14 +495,14 @@ decl_module! { /// - `delay`: The number of block after voting has ended in approval and this should be /// enacted. Increased to `EmergencyVotingPeriod` if too low. #[weight = SimpleDispatchInfo::FixedNormal(200_000)] - fn external_push(origin, + fn fast_track(origin, proposal_hash: T::Hash, voting_period: T::BlockNumber, delay: T::BlockNumber ) { - T::ExternalPushOrigin::ensure_origin(origin)?; + T::FastTrackOrigin::ensure_origin(origin)?; let (proposal, threshold) = >::get().ok_or("no proposal made")?; - ensure!(threshold == VoteThreshold::SimpleMajority, "next external proposal not simple majority"); + ensure!(threshold != VoteThreshold::SuperMajorityApprove, "next external proposal not simple majority"); ensure!(proposal_hash == T::Hashing::hash_of(&proposal), "invalid hash"); >::kill(); @@ -1088,10 +1077,10 @@ mod tests { type VotingPeriod = VotingPeriod; type EmergencyVotingPeriod = EmergencyVotingPeriod; type MinimumDeposit = MinimumDeposit; - type EmergencyOrigin = EnsureSignedBy; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; - type ExternalPushOrigin = EnsureSignedBy; + type ExternalDefaultOrigin = EnsureSignedBy; + type FastTrackOrigin = EnsureSignedBy; type CancellationOrigin = EnsureSignedBy; type VetoOrigin = EnsureSignedBy; type CooloffPeriod = CooloffPeriod; @@ -1345,64 +1334,6 @@ mod tests { }); } - #[test] - fn emergency_referendum_works() { - with_externalities(&mut new_test_ext(), || { - System::set_block_number(0); - assert_noop!(Democracy::emergency_propose( - Origin::signed(6), // invalid - Box::new(set_balance_proposal(2)), - VoteThreshold::SuperMajorityAgainst, - 0, - 0, - ), "bad origin: expected to be a root origin"); - assert_ok!(Democracy::emergency_propose( - Origin::signed(1), - Box::new(set_balance_proposal(2)), - VoteThreshold::SuperMajorityAgainst, - 0, - 0, - )); - assert_eq!( - Democracy::referendum_info(0), - Some(ReferendumInfo { - end: 1, - proposal: set_balance_proposal(2), - threshold: VoteThreshold::SuperMajorityAgainst, - delay: 0 - }) - ); - - assert_ok!(Democracy::vote(Origin::signed(1), 0, AYE)); - fast_forward_to(1); - assert_eq!(Balances::free_balance(&42), 0); - fast_forward_to(2); - assert_eq!(Balances::free_balance(&42), 2); - - assert_ok!(Democracy::emergency_propose( - Origin::signed(1), - Box::new(set_balance_proposal(4)), - VoteThreshold::SuperMajorityAgainst, - 3, - 3 - )); - assert_eq!( - Democracy::referendum_info(1), - Some(ReferendumInfo { - end: 5, - proposal: set_balance_proposal(4), - threshold: VoteThreshold::SuperMajorityAgainst, - delay: 3 - }) - ); - assert_ok!(Democracy::vote(Origin::signed(1), 1, AYE)); - fast_forward_to(8); - assert_eq!(Balances::free_balance(&42), 2); - fast_forward_to(9); - assert_eq!(Balances::free_balance(&42), 4); - }); - } - #[test] fn external_referendum_works() { with_externalities(&mut new_test_ext(), || { @@ -1458,17 +1389,42 @@ mod tests { } #[test] - fn external_push_referendum_works() { + fn external_default_referendum_works() { + with_externalities(&mut new_test_ext(), || { + System::set_block_number(0); + assert_noop!(Democracy::external_propose_default( + Origin::signed(3), + Box::new(set_balance_proposal(2)) + ), "Invalid origin"); + assert_ok!(Democracy::external_propose_default( + Origin::signed(1), + Box::new(set_balance_proposal(2)) + )); + fast_forward_to(1); + assert_eq!( + Democracy::referendum_info(0), + Some(ReferendumInfo { + end: 2, + proposal: set_balance_proposal(2), + threshold: VoteThreshold::SuperMajorityAgainst, + delay: 2, + }) + ); + }); + } + + #[test] + fn fast_track_referendum_works() { with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); - assert_noop!(Democracy::external_push(Origin::signed(5), h, 3, 2), "no proposal made"); + assert_noop!(Democracy::fast_track(Origin::signed(5), h, 3, 2), "no proposal made"); assert_ok!(Democracy::external_propose_majority( Origin::signed(3), Box::new(set_balance_proposal(2)) )); - assert_noop!(Democracy::external_push(Origin::signed(1), h, 3, 2), "Invalid origin"); - assert_ok!(Democracy::external_push(Origin::signed(5), h, 0, 0)); + assert_noop!(Democracy::fast_track(Origin::signed(1), h, 3, 2), "Invalid origin"); + assert_ok!(Democracy::fast_track(Origin::signed(5), h, 0, 0)); assert_eq!( Democracy::referendum_info(0), Some(ReferendumInfo { @@ -1482,7 +1438,7 @@ mod tests { } #[test] - fn external_push_referendum_fails_when_no_simple_majority() { + fn fast_track_referendum_fails_when_no_simple_majority() { with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); @@ -1491,7 +1447,7 @@ mod tests { Box::new(set_balance_proposal(2)) )); assert_noop!( - Democracy::external_push(Origin::signed(5), h, 3, 2), + Democracy::fast_track(Origin::signed(5), h, 3, 2), "next external proposal not simple majority" ); }); From 7d909d924775223089c1a3a66b04ef0d393da92c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Aug 2019 15:46:24 +0200 Subject: [PATCH 52/80] Make the governance be up to date with the docs. --- Cargo.lock | 15 ++ Cargo.toml | 1 + node/runtime/Cargo.toml | 2 + srml/collective/src/lib.rs | 56 ++---- srml/elections/src/lib.rs | 6 +- srml/membership/Cargo.toml | 29 ++++ srml/membership/src/lib.rs | 344 +++++++++++++++++++++++++++++++++++++ srml/support/src/traits.rs | 59 ++++++- 8 files changed, 463 insertions(+), 49 deletions(-) create mode 100644 srml/membership/Cargo.toml create mode 100644 srml/membership/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 25cea8d4179ca..2711e1856fd64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2384,6 +2384,7 @@ dependencies = [ "srml-grandpa 2.0.0", "srml-im-online 0.1.0", "srml-indices 2.0.0", + "srml-membership 2.0.0", "srml-session 2.0.0", "srml-staking 2.0.0", "srml-sudo 2.0.0", @@ -3961,6 +3962,20 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-membership" +version = "2.0.0" +dependencies = [ + "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-metadata" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 38ca09247bc14..298882e9a694a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ members = [ "srml/grandpa", "srml/im-online", "srml/indices", + "srml/membership", "srml/metadata", "srml/session", "srml/staking", diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 7c2e46b03c7de..baf119d409a48 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -29,6 +29,7 @@ executive = { package = "srml-executive", path = "../../srml/executive", default finality-tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false } indices = { package = "srml-indices", path = "../../srml/indices", default-features = false } +membership = { package = "srml-membership", path = "../../srml/membership", default-features = false } session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] } staking = { package = "srml-staking", path = "../../srml/staking", default-features = false } system = { package = "srml-system", path = "../../srml/system", default-features = false } @@ -69,6 +70,7 @@ std = [ "finality-tracker/std", "grandpa/std", "indices/std", + "membership/std", "session/std", "staking/std", "system/std", diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 713bf77147c24..8c4820715bd25 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -16,6 +16,9 @@ //! Collective system: Members of a set of account IDs can make their collective feelings known //! through dispatched calls from one of two specialised origins. +//! +//! The membership can be provided in one of two ways: either directly, using the Root-dispatchable +//! function `set_members`, or indirectly, through implementing the `ChangeMembers` #![cfg_attr(not(feature = "std"), no_std)] #![recursion_limit="128"] @@ -119,7 +122,7 @@ decl_event!( } ); -// Note: this module is not benchmarked. The weights are obtained based on the similarity fo the +// Note: this module is not benchmarked. The weights are obtained based on the similarity of the // executed logic with other democracy function. Note that councillor operations are assigned to the // operational class. decl_module! { @@ -133,41 +136,12 @@ decl_module! { #[weight = SimpleDispatchInfo::FixedOperational(100_000)] fn set_members(origin, new_members: Vec) { ensure_root(origin)?; - - // stable sorting since they will generally be provided sorted. - let mut old_members = >::get(); - old_members.sort(); let mut new_members = new_members; new_members.sort(); - let mut old_iter = old_members.iter(); - let mut new_iter = new_members.iter(); - let mut incoming = vec![]; - let mut outgoing = vec![]; - let mut old_i = old_iter.next(); - let mut new_i = new_iter.next(); - loop { - match (old_i, new_i) { - (None, None) => break, - (Some(old), Some(new)) if old == new => { - old_i = old_iter.next(); - new_i = new_iter.next(); - } - (Some(old), Some(new)) if old < new => { - outgoing.push(old.clone()); - old_i = old_iter.next(); - } - (Some(old), None) => { - outgoing.push(old.clone()); - old_i = old_iter.next(); - } - (_, Some(new)) => { - incoming.push(new.clone()); - new_i = new_iter.next(); - } - } - } - - Self::change_members(&incoming, &outgoing, &new_members); + >::mutate(|m| { + >::set_members_sorted(&new_members[..], m); + *m = new_members; + }); } /// Dispatch a proposal from a member using the `Member` origin. @@ -287,18 +261,18 @@ impl, I: Instance> Module { } impl, I: Instance> ChangeMembers for Module { - fn change_members(_incoming: &[T::AccountId], outgoing: &[T::AccountId], new: &[T::AccountId]) { + fn change_members_sorted(_incoming: &[T::AccountId], outgoing: &[T::AccountId], new: &[T::AccountId]) { // remove accounts from all current voting in motions. - let mut old = outgoing.to_vec(); - old.sort_unstable(); + let mut outgoing = outgoing.to_vec(); + outgoing.sort_unstable(); for h in Self::proposals().into_iter() { >::mutate(h, |v| if let Some(mut votes) = v.take() { votes.ayes = votes.ayes.into_iter() - .filter(|i| old.binary_search(i).is_err()) + .filter(|i| outgoing.binary_search(i).is_err()) .collect(); votes.nays = votes.nays.into_iter() - .filter(|i| old.binary_search(i).is_err()) + .filter(|i| outgoing.binary_search(i).is_err()) .collect(); *v = Some(votes); } @@ -487,7 +461,7 @@ mod tests { Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![] }) ); - Collective::change_members(&[4], &[1], &[2, 3, 4]); + Collective::change_members_sorted(&[4], &[1], &[2, 3, 4]); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![] }) @@ -501,7 +475,7 @@ mod tests { Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3] }) ); - Collective::change_members(&[], &[3], &[2, 4]); + Collective::change_members_sorted(&[], &[3], &[2, 4]); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![] }) diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index e6aefb5da2c31..03dcb800d9241 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -593,7 +593,7 @@ decl_module! { .collect(); >::put(&new_set); let new_set = new_set.into_iter().map(|x| x.0).collect::>(); - T::ChangeMembers::change_members(&[], &[who], &new_set[..]); + T::ChangeMembers::change_members(&[], &[who], new_set); } /// Set the presentation duration. If there is currently a vote being presented for, will @@ -876,7 +876,7 @@ impl Module { >::put(&new_set); let new_set = new_set.into_iter().map(|x| x.0).collect::>(); - T::ChangeMembers::change_members(&incoming, &outgoing, &new_set[..]); + T::ChangeMembers::change_members(&incoming, &outgoing, new_set); // clear all except runners-up from candidate list. let candidates = Self::candidates(); @@ -1204,7 +1204,7 @@ mod tests { pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { - fn change_members(incoming: &[u64], outgoing: &[u64], new: &[u64]) { + fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); old_plus_incoming.extend_from_slice(incoming); old_plus_incoming.sort(); diff --git a/srml/membership/Cargo.toml b/srml/membership/Cargo.toml new file mode 100644 index 0000000000000..e38f2bcdac7dc --- /dev/null +++ b/srml/membership/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "srml-membership" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0", optional = true } +parity-codec = { version = "4.1.1", default-features = false } +sr-std = { path = "../../core/sr-std", default-features = false } +sr-io = { path = "../../core/sr-io", default-features = false } +srml-support = { path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", path = "../../core/primitives" } + +[features] +default = ["std"] +std = [ + "serde", + "parity-codec/std", + "sr-primitives/std", + "sr-std/std", + "sr-io/std", + "srml-support/std", + "system/std", +] diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs new file mode 100644 index 0000000000000..71890156506b8 --- /dev/null +++ b/srml/membership/src/lib.rs @@ -0,0 +1,344 @@ +// Copyright 2017-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 . + +//! # Membership Module +//! +//! Allows control of membership of a set of `AccountId`s, useful for managing membership of of a +//! collective. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use sr_std as rstd; +use sr_io::with_storage; +use srml_support::{ + StorageValue, decl_module, decl_storage, decl_event, + traits::{ChangeMembers} +}; +use system::ensure_root; +use sr_primitives::{traits::EnsureOrigin, weights::SimpleDispatchInfo}; + +pub trait Trait: system::Trait { + /// The overarching event type. + type Event: From + Into<::Event>; + + /// Required origin for adding a member (though can always be Root). + type AddOrigin: EnsureOrigin; + + /// Required origin for removing a member (though can always be Root). + type RemoveOrigin: EnsureOrigin; + + /// Required origin for adding and removing a member in a single action. + type SwapOrigin: EnsureOrigin; + + /// Required origin for resetting membership. + type ResetOrigin: EnsureOrigin; + + /// The receiver of the signal for when the membership has been initialized. This happens pre- + /// genesis and will usually be the same as `MembershipChanged`. If you need to do something + /// different on initialization, then you can change this accordingly. + type MembershipInitialized: ChangeMembers; + + /// The receiver of the signal for when the membership has changed. + type MembershipChanged: ChangeMembers; +} + +decl_storage! { + trait Store for Module, I: Instance=DefaultInstance> as Membership { + /// The current membership, stored as an ordered Vec. + Members get(members): Vec; + } + add_extra_genesis { + config(members): Vec; + config(phantom): rstd::marker::PhantomData; + build(| + storage: &mut sr_primitives::StorageOverlay, + _: &mut sr_primitives::ChildrenStorageOverlay, + config: &GenesisConfig + | { + with_storage(storage, || { + let mut members = config.members.clone(); + members.sort(); + T::MembershipInitialized::set_members_sorted(&members[..], &[]); + >::put(members); + }); + }) + } +} + +decl_event!( + pub enum Event { + /// The given member was added; see the transaction for who. + MemberAdded, + /// The given member was removed; see the transaction for who. + MemberRemoved, + /// Two members were swapped; see the transaction for who. + MembersSwapped, + /// The membership was reset; see the transaction for who the new set is. + MembersReset, + } +); + +decl_module! { + pub struct Module, I: Instance=DefaultInstance> + for enum Call + where origin: T::Origin + { + fn deposit_event() = default; + + /// Add a member `who` to the set. + /// + /// May only be called from `AddOrigin` or root. + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn add_member(origin, who: T::AccountId) { + T::AddOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + let mut members = >::get(); + let location = members.binary_search(&who).err().ok_or("already a member")?; + members.insert(location, who.clone()); + >::put(&members); + + T::MembershipChanged::change_members_sorted(&[who], &[], &members[..]); + + Self::deposit_event(Event::MemberAdded); + } + + /// Remove a member `who` from the set. + /// + /// May only be called from `RemoveOrigin` or root. + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn remove_member(origin, who: T::AccountId) { + T::RemoveOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + let mut members = >::get(); + let location = members.binary_search(&who).ok().ok_or("not a member")?; + members.remove(location); + >::put(&members); + + T::MembershipChanged::change_members_sorted(&[], &[who], &members[..]); + + Self::deposit_event(Event::MemberRemoved); + } + + /// Swap out one member `remove` for another `add`. + /// + /// May only be called from `SwapOrigin` or root. + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn swap_member(origin, remove: T::AccountId, add: T::AccountId) { + T::SwapOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + if remove == add { return Ok(()) } + + let mut members = >::get(); + let location = members.binary_search(&remove).ok().ok_or("not a member")?; + members[location] = add.clone(); + let _location = members.binary_search(&add).err().ok_or("already a member")?; + members.sort(); + >::put(&members); + + T::MembershipChanged::change_members_sorted( + &[add], + &[remove], + &members[..], + ); + + Self::deposit_event(Event::MembersSwapped); + } + + /// Change the membership to a new set, disregarding the existing membership. Be nice and + /// pass `members` pre-sorted. + /// + /// May only be called from `ResetOrigin` or root. + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn reset_members(origin, members: Vec) { + T::ResetOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + let mut members = members; + members.sort(); + >::mutate(|m| { + T::MembershipChanged::set_members_sorted(&members[..], m); + *m = members; + }); + + Self::deposit_event(Event::MembersReset); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::cell::RefCell; + use srml_support::{assert_ok, assert_noop, impl_outer_origin, parameter_types}; + use sr_io::with_externalities; + use primitives::{H256, Blake2Hasher}; + // The testing primitives are very useful for avoiding having to work with signatures + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. + use sr_primitives::{ + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header + }; + use system::EnsureSignedBy; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = (); + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type WeightMultiplierUpdate = (); + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + } + parameter_types! { + pub const One: u64 = 1; + pub const Two: u64 = 2; + pub const Three: u64 = 3; + pub const Four: u64 = 4; + pub const Five: u64 = 5; + } + + thread_local! { + static MEMBERS: RefCell> = RefCell::new(vec![]); + } + + pub struct TestChangeMembers; + impl ChangeMembers for TestChangeMembers { + fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { + let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); + old_plus_incoming.extend_from_slice(incoming); + old_plus_incoming.sort(); + let mut new_plus_outgoing = new.to_vec(); + new_plus_outgoing.extend_from_slice(outgoing); + new_plus_outgoing.sort(); + assert_eq!(old_plus_incoming, new_plus_outgoing); + + MEMBERS.with(|m| *m.borrow_mut() = new.to_vec()); + } + } + + impl Trait for Test { + type Event = (); + type AddOrigin = EnsureSignedBy; + type RemoveOrigin = EnsureSignedBy; + type SwapOrigin = EnsureSignedBy; + type ResetOrigin = EnsureSignedBy; + type MembershipInitialized = TestChangeMembers; + type MembershipChanged = TestChangeMembers; + } + + type Membership = Module; + + // This function basically just builds a genesis storage key/value store according to + // our desired mockup. + fn new_test_ext() -> sr_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + // We use default for brevity, but you can configure as desired if needed. + t.extend(GenesisConfig::{ + members: vec![10, 20, 30], + .. Default::default() + }.build_storage().unwrap().0); + t.into() + } + + #[test] + fn query_membership_works() { + with_externalities(&mut new_test_ext(), || { + assert_eq!(Membership::members(), vec![10, 20, 30]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![10, 20, 30]); + }); + } + + #[test] + fn add_member_works() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Membership::add_member(Origin::signed(5), 15), "bad origin"); + assert_noop!(Membership::add_member(Origin::signed(1), 10), "already a member"); + assert_ok!(Membership::add_member(Origin::signed(1), 15)); + assert_eq!(Membership::members(), vec![10, 15, 20, 30]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + }); + } + + #[test] + fn remove_member_works() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Membership::remove_member(Origin::signed(5), 20), "bad origin"); + assert_noop!(Membership::remove_member(Origin::signed(2), 15), "not a member"); + assert_ok!(Membership::remove_member(Origin::signed(2), 20)); + assert_eq!(Membership::members(), vec![10, 30]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + }); + } + + #[test] + fn swap_member_works() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Membership::swap_member(Origin::signed(5), 10, 25), "bad origin"); + assert_noop!(Membership::swap_member(Origin::signed(3), 15, 25), "not a member"); + assert_noop!(Membership::swap_member(Origin::signed(3), 10, 30), "already a member"); + assert_ok!(Membership::swap_member(Origin::signed(3), 20, 20)); + assert_eq!(Membership::members(), vec![10, 20, 30]); + assert_ok!(Membership::swap_member(Origin::signed(3), 10, 25)); + assert_eq!(Membership::members(), vec![20, 25, 30]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + }); + } + + #[test] + fn reset_members_works() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Membership::reset_members(Origin::signed(1), vec![20, 40, 30]), "bad origin"); + assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); + assert_eq!(Membership::members(), vec![20, 30, 40]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + }); + } +} diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 5f1d7c32ef40e..08486363ced6a 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -631,12 +631,61 @@ impl WithdrawReasons { } /// Trait for type that can handle incremental changes to a set of account IDs. -pub trait ChangeMembers { +pub trait ChangeMembers { + /// A number of members `incoming` just joined the set and replaced some `outgoing` ones. The + /// new set is given by `new`, and need not be sorted. + fn change_members(incoming: &[AccountId], outgoing: &[AccountId], mut new: Vec) { + new.sort_unstable(); + Self::change_members_sorted(incoming, outgoing, &new[..]); + } + /// A number of members `_incoming` just joined the set and replaced some `_outgoing` ones. The - /// new set is thus given by `_new`. - fn change_members(_incoming: &[AccountId], _outgoing: &[AccountId], _new: &[AccountId]); + /// new set is thus given by `sorted_new` and **must be sorted**. + /// + /// NOTE: This is the only function that needs to be implemented in `ChangeMembers`. + fn change_members_sorted( + incoming: &[AccountId], + outgoing: &[AccountId], + sorted_new: &[AccountId], + ); + + /// Set the new members; they **must already be sorted**. This will compute the diff and use it to + /// call `change_members_sorted`. + fn set_members_sorted(new_members: &[AccountId], old_members: &[AccountId]) { + let mut old_iter = old_members.iter(); + let mut new_iter = new_members.iter(); + let mut incoming = vec![]; + let mut outgoing = vec![]; + let mut old_i = old_iter.next(); + let mut new_i = new_iter.next(); + loop { + match (old_i, new_i) { + (None, None) => break, + (Some(old), Some(new)) if old == new => { + old_i = old_iter.next(); + new_i = new_iter.next(); + } + (Some(old), Some(new)) if old < new => { + outgoing.push(old.clone()); + old_i = old_iter.next(); + } + (Some(old), None) => { + outgoing.push(old.clone()); + old_i = old_iter.next(); + } + (_, Some(new)) => { + incoming.push(new.clone()); + new_i = new_iter.next(); + } + } + } + + Self::change_members_sorted(&incoming[..], &outgoing[..], &new_members); + } } -impl ChangeMembers for () { - fn change_members(_incoming: &[T], _outgoing: &[T], _new_set: &[T]) {} +impl ChangeMembers for () { + fn change_members(_: &[T], _: &[T], _: Vec) {} + fn change_members_sorted(_: &[T], _: &[T], _: &[T]) {} + fn set_members_sorted(_: &[T], _: &[T]) {} } From 63e93b5ed77f827f31136e0d8e7cb22851cc0c41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Aug 2019 16:08:57 +0200 Subject: [PATCH 53/80] Build fixes. --- node/runtime/src/lib.rs | 35 +++++++++++++++++++++++------------ srml/membership/src/lib.rs | 25 ++++++++++++++----------- srml/support/src/traits.rs | 6 +++--- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index e0aed036c2521..d0fad910bb0e0 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -261,25 +261,25 @@ impl democracy::Trait for Runtime { type EmergencyVotingPeriod = EmergencyVotingPeriod; type MinimumDeposit = MinimumDeposit; /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilInstance>; + type ExternalOrigin = collective::EnsureProportionAtLeast<_1, _2, AccountId, CouncilCollective>; /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilInstance>; + type ExternalMajorityOrigin = collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective>; /// A unanimous council can have the next scheduled referendum be a straight default-carries /// (NTB) vote. - type ExternalDefaultOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilInstance>; + type ExternalDefaultOrigin = collective::EnsureProportionAtLeast<_1, _1, AccountId, CouncilCollective>; /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// be tabled immediately and with a shorter voting/enactment period. - type FastTrackOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalInstance>; + type FastTrackOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, TechnicalCollective>; // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilInstance>; + type CancellationOrigin = collective::EnsureProportionAtLeast<_2, _3, AccountId, CouncilCollective>; // Any single technical committee member may veto a coming council proposal, however they can // only do it once and it lasts only for the cooloff period. - type VetoOrigin = collective::EnsureMember; + type VetoOrigin = collective::EnsureMember; type CooloffPeriod = CooloffPeriod; } -type CouncilInstance = collective::Instance1; -impl collective::Trait for Runtime { +type CouncilCollective = collective::Instance1; +impl collective::Trait for Runtime { type Origin = Origin; type Proposal = Call; type Event = Event; @@ -315,13 +315,23 @@ impl elections::Trait for Runtime { type DecayRatio = DecayRatio; } -type TechnicalInstance = collective::Instance2; -impl collective::Trait for Runtime { +type TechnicalCollective = collective::Instance2; +impl collective::Trait for Runtime { type Origin = Origin; type Proposal = Call; type Event = Event; } +impl membership::Trait for Runtime { + type Event = Event; + type AddOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type RemoveOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type SwapOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type ResetOrigin = collective::EnsureProportionMoreThan<_1, _2, AccountId, CouncilCollective>; + type MembershipInitialized = TechnicalCommittee; + type MembershipChanged = TechnicalCommittee; +} + parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const ProposalBondMinimum: Balance = 1 * DOLLARS; @@ -331,8 +341,8 @@ parameter_types! { impl treasury::Trait for Runtime { type Currency = Balances; - type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilInstance>; - type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilInstance>; + type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilCollective>; + type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilCollective>; type Event = Event; type MintedForSpending = (); type ProposalRejection = (); @@ -420,6 +430,7 @@ construct_runtime!( Council: collective::::{Module, Call, Storage, Origin, Event, Config}, TechnicalCommittee: collective::::{Module, Call, Storage, Origin, Event, Config}, Elections: elections::{Module, Call, Storage, Event, Config}, + TechnicalMembership: membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, Treasury: treasury::{Module, Call, Storage, Event}, diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index 71890156506b8..e80e0c61f4dd5 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -22,8 +22,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use sr_std as rstd; -use sr_io::with_storage; +use sr_std::prelude::*; use srml_support::{ StorageValue, decl_module, decl_storage, decl_event, traits::{ChangeMembers} @@ -33,7 +32,7 @@ use sr_primitives::{traits::EnsureOrigin, weights::SimpleDispatchInfo}; pub trait Trait: system::Trait { /// The overarching event type. - type Event: From + Into<::Event>; + type Event: From> + Into<::Event>; /// Required origin for adding a member (though can always be Root). type AddOrigin: EnsureOrigin; @@ -63,13 +62,13 @@ decl_storage! { } add_extra_genesis { config(members): Vec; - config(phantom): rstd::marker::PhantomData; + config(phantom): sr_std::marker::PhantomData; build(| storage: &mut sr_primitives::StorageOverlay, _: &mut sr_primitives::ChildrenStorageOverlay, config: &GenesisConfig | { - with_storage(storage, || { + sr_io::with_storage(storage, || { let mut members = config.members.clone(); members.sort(); T::MembershipInitialized::set_members_sorted(&members[..], &[]); @@ -80,7 +79,9 @@ decl_storage! { } decl_event!( - pub enum Event { + pub enum Event where + ::AccountId, + { /// The given member was added; see the transaction for who. MemberAdded, /// The given member was removed; see the transaction for who. @@ -89,6 +90,8 @@ decl_event!( MembersSwapped, /// The membership was reset; see the transaction for who the new set is. MembersReset, + /// Phantom member, never used. + Dummy(sr_std::marker::PhantomData<(AccountId, I)>), } ); @@ -97,7 +100,7 @@ decl_module! { for enum Call where origin: T::Origin { - fn deposit_event() = default; + fn deposit_event() = default; /// Add a member `who` to the set. /// @@ -116,7 +119,7 @@ decl_module! { T::MembershipChanged::change_members_sorted(&[who], &[], &members[..]); - Self::deposit_event(Event::MemberAdded); + Self::deposit_event(RawEvent::MemberAdded); } /// Remove a member `who` from the set. @@ -136,7 +139,7 @@ decl_module! { T::MembershipChanged::change_members_sorted(&[], &[who], &members[..]); - Self::deposit_event(Event::MemberRemoved); + Self::deposit_event(RawEvent::MemberRemoved); } /// Swap out one member `remove` for another `add`. @@ -164,7 +167,7 @@ decl_module! { &members[..], ); - Self::deposit_event(Event::MembersSwapped); + Self::deposit_event(RawEvent::MembersSwapped); } /// Change the membership to a new set, disregarding the existing membership. Be nice and @@ -185,7 +188,7 @@ decl_module! { *m = members; }); - Self::deposit_event(Event::MembersReset); + Self::deposit_event(RawEvent::MembersReset); } } } diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 08486363ced6a..2766ba0a98767 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -18,7 +18,7 @@ //! //! NOTE: If you're looking for `parameter_types`, it has moved in to the top-level module. -use crate::rstd::{result, marker::PhantomData, ops::Div}; +use crate::rstd::{prelude::*, result, marker::PhantomData, ops::Div}; use crate::codec::{Codec, Encode, Decode}; use primitives::u32_trait::Value as U32; use crate::sr_primitives::traits::{MaybeSerializeDebug, SimpleArithmetic, Saturating}; @@ -654,8 +654,8 @@ pub trait ChangeMembers { fn set_members_sorted(new_members: &[AccountId], old_members: &[AccountId]) { let mut old_iter = old_members.iter(); let mut new_iter = new_members.iter(); - let mut incoming = vec![]; - let mut outgoing = vec![]; + let mut incoming = Vec::new(); + let mut outgoing = Vec::new(); let mut old_i = old_iter.next(); let mut new_i = new_iter.next(); loop { From fa1f28aeeac5a90be5d6d7349be2e45efbbff4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 10:50:57 +0200 Subject: [PATCH 54/80] Generate the inital session keys --- Cargo.lock | 3 +++ core/service/Cargo.toml | 1 + core/service/src/components.rs | 23 ++++++++++++++++++++ core/service/src/lib.rs | 17 +++++++-------- core/session/Cargo.toml | 4 +++- core/session/src/lib.rs | 38 +++++++++++++++++++++++++++++++++- node/cli/src/service.rs | 1 - node/runtime/src/lib.rs | 2 +- 8 files changed, 76 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2711e1856fd64..51aabd6ffdae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4890,6 +4890,7 @@ dependencies = [ "substrate-offchain 2.0.0", "substrate-primitives 2.0.0", "substrate-rpc-servers 2.0.0", + "substrate-session 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", @@ -4921,8 +4922,10 @@ dependencies = [ name = "substrate-session" version = "2.0.0" dependencies = [ + "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", + "substrate-primitives 2.0.0", ] [[package]] diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index b991aa2de447a..c088a74f6a1eb 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -24,6 +24,7 @@ sr-io = { path = "../../core/sr-io" } sr-primitives = { path = "../../core/sr-primitives" } primitives = { package = "substrate-primitives", path = "../primitives" } 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/core/service/src/components.rs b/core/service/src/components.rs index 9640723342570..c4f3b8e0261b8 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -144,6 +144,27 @@ pub type PoolApi = ::TransactionPoolApi; pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {} impl RuntimeGenesis for T {} +/// Something that can create initial session keys from given seeds. +pub trait InitialSessionKeys { + /// Generate the initial session keys for the given seeds. + fn generate_intial_session_keys( + client: Arc>, + seeds: Vec, + ) -> error::Result<()>; +} + +impl InitialSessionKeys for C where + ComponentClient: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: substrate_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) + } +} + /// Something that can start the RPC service. pub trait StartRPC { fn start_rpc( @@ -267,6 +288,7 @@ pub trait ServiceTrait: + StartRPC + MaintainTransactionPool + OffchainWorker + + InitialSessionKeys {} impl ServiceTrait for T where T: Deref> @@ -275,6 +297,7 @@ impl ServiceTrait for T where + StartRPC + MaintainTransactionPool + OffchainWorker + + InitialSessionKeys {} /// Alias for a an implementation of `futures::future::Executor`. diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 92498350324ca..52d9beb0e21dc 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -61,7 +61,7 @@ pub use components::{ ComponentBlock, FullClient, LightClient, FullComponents, LightComponents, CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock, FactoryFullConfiguration, RuntimeGenesis, FactoryGenesis, - ComponentExHash, ComponentExtrinsic, FactoryExtrinsic, + ComponentExHash, ComponentExtrinsic, FactoryExtrinsic, InitialSessionKeys, }; use components::{StartRPC, MaintainTransactionPool, OffchainWorker}; #[doc(hidden)] @@ -171,13 +171,7 @@ impl Service { let keystore: Option = if let Some(keystore_path) = config.keystore_path.as_ref() { match Keystore::open(keystore_path.clone(), config.keystore_password.clone()) { - Ok(mut ks) => { - if let Some(ref seed) = config.dev_key_seed { - //TODO: Make sure we generate for all types and apps - ks.generate_from_seed::(&seed)?; - ks.generate_from_seed::(&seed)?; - } - + Ok(ks) => { Some(Arc::new(parking_lot::RwLock::new(ks))) }, Err(err) => { @@ -200,6 +194,11 @@ impl Service { let finality_proof_provider = Components::build_finality_proof_provider(client.clone())?; let chain_info = client.info().chain; + Components::RuntimeServices::generate_intial_session_keys( + client.clone(), + config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(), + )?; + let version = config.full_version(); info!("Highest known block at #{}", chain_info.best_number); telemetry!( @@ -217,7 +216,7 @@ impl Service { imports_external_transactions: !config.roles.is_light(), pool: transaction_pool.clone(), client: client.clone(), - }); + }); let protocol_id = { let protocol_id_full = match config.chain_spec.protocol_id() { diff --git a/core/session/Cargo.toml b/core/session/Cargo.toml index 5fc45f0cb837b..2c996ef9246d2 100644 --- a/core/session/Cargo.toml +++ b/core/session/Cargo.toml @@ -7,7 +7,9 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../client", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } +sr-primitives = { path = "../sr-primitives", optional = true } +primitives = { package = "substrate-primitives", path = "../primitives", optional = true } [features] default = [ "std" ] -std = [ "client/std", "rstd/std" ] \ No newline at end of file +std = [ "client/std", "rstd/std", "sr-primitives", "primitives" ] \ No newline at end of file diff --git a/core/session/src/lib.rs b/core/session/src/lib.rs index a78674283baef..a3803efc7b4bb 100644 --- a/core/session/src/lib.rs +++ b/core/session/src/lib.rs @@ -20,6 +20,11 @@ use rstd::vec::Vec; +#[cfg(feature = "std")] +use sr_primitives::traits::{ProvideRuntimeApi, Block as BlockT}; +#[cfg(feature = "std")] +use primitives::{H256, Blake2Hasher}; + client::decl_runtime_apis! { /// Session keys runtime api. pub trait SessionKeys { @@ -28,6 +33,37 @@ client::decl_runtime_apis! { /// The seed needs to be a valid `utf8` string. /// /// Returns the concatenated SCALE encoded public keys. - fn generate(seed: Option>) -> Vec; + fn generate_session_keys(seed: Option>) -> Vec; + } +} + +/// Generate the initial session keys with the given seeds. +#[cfg(feature = "std")] +pub fn generate_initial_session_keys( + client: std::sync::Arc>, + seeds: Vec, +) -> Result<(), client::error::Error> +where + B: client::backend::Backend, + E: client::CallExecutor, + Block: BlockT, + client::Client: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: SessionKeys, +{ + let info = client.info().chain; + let runtime_api = client.runtime_api(); + + for seed in seeds { + let seed = seed.as_bytes(); + + // We need to generate the keys for the best block + the last finalized block. + for number in &[info.best_number, info.finalized_number] { + runtime_api.generate_session_keys( + &sr_primitives::generic::BlockId::Number(*number), + Some(seed.to_vec()), + )?; + } } + + Ok(()) } \ No newline at end of file diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index c2af967b99644..86469ff44d6e2 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -23,7 +23,6 @@ use std::time::Duration; use babe::{import_queue, start_babe, BabeImportQueue, Config}; use babe_primitives::AuthorityPair as BabePair; -use grandpa_primitives::AuthorityPair as GrandpaPair; use client::{self, LongestChain}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use node_executor; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d0fad910bb0e0..9a6b45f8968a4 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -570,7 +570,7 @@ impl_runtime_apis! { } impl substrate_session::SessionKeys for Runtime { - fn generate(seed: Option>) -> Vec { + fn generate_session_keys(seed: Option>) -> Vec { let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); SessionKeys::generate(seed) } From c2ad6e2b855eb5aa82c0308ff74f824689c4771a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 11:38:37 +0200 Subject: [PATCH 55/80] Failing keystore is a hard error --- core/cli/src/lib.rs | 4 +++- core/service/src/config.rs | 2 +- core/service/src/lib.rs | 23 +++++++---------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index f017726f93ff2..ec003932271c7 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -418,7 +418,9 @@ where let base_path = base_path(&cli.shared_params, version); - config.keystore_path = cli.keystore_path.or_else(|| Some(keystore_path(&base_path, config.chain_spec.id()))); + config.keystore_path = cli.keystore_path.unwrap_or_else( + || keystore_path(&base_path, config.chain_spec.id()) + ); config.database_path = db_path(&base_path, config.chain_spec.id()); config.database_cache_size = cli.database_cache_size; diff --git a/core/service/src/config.rs b/core/service/src/config.rs index c5f1869aee972..b5019c82637a9 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -45,7 +45,7 @@ pub struct Configuration { /// Network configuration. pub network: NetworkConfiguration, /// Path to key files. - pub keystore_path: Option, + pub keystore_path: PathBuf, /// Path to the database. pub database_path: PathBuf, /// Cache Size for internal database in MiB diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 52d9beb0e21dc..cccc1976db3b6 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -42,7 +42,6 @@ use log::{log, info, warn, debug, error, Level}; use parity_codec::{Encode, Decode}; use sr_primitives::generic::BlockId; use sr_primitives::traits::{Header, NumberFor, SaturatedConversion}; -use primitives::traits::KeyStorePtr; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -169,21 +168,13 @@ impl Service { // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let keystore: Option = if let Some(keystore_path) = config.keystore_path.as_ref() { - match Keystore::open(keystore_path.clone(), config.keystore_password.clone()) { - Ok(ks) => { - Some(Arc::new(parking_lot::RwLock::new(ks))) - }, - Err(err) => { - error!("Failed to initialize keystore: {}", err); - None - } - } - } else { - None - }; + let keystore = Arc::new( + parking_lot::RwLock::new( + Keystore::open(config.keystore_path.clone( ), config.keystore_password.clone())? + ) + ); - let (client, on_demand) = Components::build_client(&config, executor, keystore.clone())?; + let (client, on_demand) = Components::build_client(&config, executor, Some(keystore.clone()))?; let select_chain = Components::build_select_chain(&mut config, client.clone())?; let (import_queue, finality_proof_request_builder) = Components::build_import_queue( &mut config, @@ -256,7 +247,7 @@ impl Service { Some(Arc::new(offchain::OffchainWorkers::new( client.clone(), db, - keystore.clone(), + Some(keystore.clone()), ))) }, (true, None) => { From 86d28114e61dfd4d55d72ef5154da9bac2800888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 14:29:23 +0200 Subject: [PATCH 56/80] Make babe work again --- Cargo.lock | 3 +- core/consensus/babe/src/lib.rs | 142 ++++++--------------------------- core/keystore/Cargo.toml | 1 + core/keystore/src/lib.rs | 13 ++- core/service/src/lib.rs | 15 ++-- node/cli/src/service.rs | 55 ++++++------- srml/babe/Cargo.toml | 4 +- 7 files changed, 73 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51aabd6ffdae3..36b50ff795b9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3747,7 +3747,7 @@ dependencies = [ "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4652,6 +4652,7 @@ version = "2.0.0" dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-application-crypto 2.0.0", diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 3538458ed3c7d..ff4f95d028c0e 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -18,7 +18,7 @@ //! //! BABE (Blind Assignment for Blockchain Extension) consensus in Substrate. -#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)] +#![forbid(unsafe_code, missing_docs)] pub use babe_primitives::*; pub use consensus_common::SyncOracle; use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}}; @@ -33,7 +33,7 @@ use sr_primitives::traits::{ Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi, SimpleBitOps, Zero, }; -use substrate_keystore::Store; +use substrate_keystore::KeyStorePtr; use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; use parking_lot::{Mutex, MutexGuard}; @@ -65,11 +65,8 @@ use consensus_common::{SelectChain, well_known_cache_keys}; use consensus_common::import_queue::{Verifier, BasicQueue}; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, - blockchain::{self, HeaderBackend, ProvideCache}, - BlockchainEvents, BlockOf, CallExecutor, Client, - runtime_api::ApiExt, - error::Result as ClientResult, - backend::{AuxStore, Backend}, + blockchain::{self, HeaderBackend, ProvideCache}, BlockchainEvents, CallExecutor, Client, + runtime_api::ApiExt, error::Result as ClientResult, backend::{AuxStore, Backend}, utils::is_descendent_of, }; use fork_tree::ForkTree; @@ -136,13 +133,12 @@ impl SlotCompatible for BabeLink { /// Parameters for BABE. pub struct BabeParams { - /// The configuration for BABE. Includes the slot duration, threshold, and /// other parameters. pub config: Config, - /// The key of the node we are running on. - pub local_key: Arc, + /// The keystore that manages the keys of the node. + pub keystore: KeyStorePtr, /// The client to use pub client: Arc, @@ -172,8 +168,8 @@ pub struct BabeParams { /// Start the babe worker. The returned future should be run in a tokio runtime. pub fn start_babe(BabeParams { config, - local_key, client, + keystore, select_chain, block_import, env, @@ -201,10 +197,10 @@ pub fn start_babe(BabeParams { client: client.clone(), block_import: Arc::new(Mutex::new(block_import)), env, - local_key, sync_oracle: sync_oracle.clone(), force_authoring, c: config.c(), + keystore, }; register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?; Ok(slots::start_slot_worker( @@ -221,10 +217,10 @@ struct BabeWorker { client: Arc, block_import: Arc>, env: E, - local_key: Arc, sync_oracle: SO, force_authoring: bool, c: (u64, u64), + keystore: KeyStorePtr, } impl SlotWorker for BabeWorker where @@ -249,7 +245,6 @@ impl SlotWorker for BabeWorker w chain_head: B::Header, slot_info: SlotInfo, ) -> Self::OnSlot { - let pair = self.local_key.clone(); let ref client = self.client; let block_import = self.block_import.clone(); @@ -289,10 +284,10 @@ impl SlotWorker for BabeWorker w let proposal_work = if let Some(claim) = claim_slot( slot_info.number, epoch, - &pair, self.c, + &self.keystore, ) { - let ((inout, vrf_proof, _batchable_proof), authority_index) = claim; + let ((inout, vrf_proof, _batchable_proof), authority_index, key) = claim; debug!( target: "babe", "Starting authorship at slot {}; timestamp = {}", @@ -341,7 +336,7 @@ impl SlotWorker for BabeWorker w Delay::new(remaining_duration) .map_err(|err| consensus_common::Error::FaultyTimer(err).into()) ).map(|v| match v { - futures::future::Either::Left((v, _)) => v, + futures::future::Either::Left((v, _)) => v.map(|v| (v, key)), futures::future::Either::Right((Ok(_), _)) => Err(consensus_common::Error::ClientImport("Timeout in the BaBe proposer".into())), futures::future::Either::Right((Err(err), _)) => Err(err), @@ -350,7 +345,7 @@ impl SlotWorker for BabeWorker w return Box::pin(future::ready(Ok(()))); }; - Box::pin(proposal_work.map_ok(move |b| { + Box::pin(proposal_work.map_ok(move |(b, key)| { // minor hack since we don't have access to the timestamp // that is actually set by the proposer. let slot_after_building = SignedDuration::default().slot_now(slot_duration); @@ -373,7 +368,7 @@ impl SlotWorker for BabeWorker w // sign the pre-sealed hash of the block and then // add it to a digest item. let header_hash = header.hash(); - let signature = pair.sign(header_hash.as_ref()); + let signature = key.sign(header_hash.as_ref()); let signature_digest_item = DigestItemFor::::babe_seal(signature); let import_block = BlockImportParams:: { @@ -825,11 +820,15 @@ fn calculate_threshold( fn claim_slot( slot_number: u64, Epoch { ref authorities, ref randomness, epoch_index, .. }: Epoch, - key: &AuthorityPair, c: (u64, u64), -) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> { - let public = &key.public(); - let authority_index = authorities.iter().position(|s| &s.0 == public)?; + keystore: &KeyStorePtr, +) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize, AuthorityPair)> { + let keystore = keystore.read(); + let (key_pair, authority_index) = authorities.iter() + .enumerate() + .find_map(|(i, a)| { + keystore.key_pair::(&a.0).ok().map(|kp| (kp, i)) + })?; let transcript = make_transcript(randomness, slot_number, epoch_index); // Compute the threshold we will use. @@ -838,9 +837,9 @@ fn claim_slot( // be empty. Therefore, this division in `calculate_threshold` is safe. let threshold = calculate_threshold(c, authorities, authority_index); - get_keypair(key) + get_keypair(&key_pair) .vrf_sign_n_check(transcript, |inout| check(inout, threshold)) - .map(|s|(s, authority_index)) + .map(|s|(s, authority_index, key_pair)) } fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusError> where @@ -1192,44 +1191,6 @@ pub fn import_queue, I, RA, PRA>( Ok((queue, timestamp_core, block_import, pruning_task)) } -/// Provide a list of authority keys that is current as of a given block. -#[allow(deprecated)] -fn authorities_at(client: &C, at: &BlockId<::Type>) - -> Result, ConsensusError> -where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, - C::Api: BabeApi<::Type> -{ - client - .cache() - .and_then(|cache| cache - .get_at(&well_known_cache_keys::AUTHORITIES, at) - .and_then(|v| Decode::decode(&mut &v[..])) - ) - .or_else(|| BabeApi::epoch(&*client.runtime_api(), at).ok() - .map(|epoch| epoch.authorities.into_iter().map(|x| x.0).collect()) - ) - .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) -} - -/// Provide the authority key, if any, that is controlled by this node as of the given block. -fn authority(client: &C, keystore: Arc) -> Option where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - C::Api: BabeApi<::Type> -{ - let owned = keystore.public_keys::().ok()?; - let at = BlockId::Number(client.info().best_number); - // The list of authority keys that is current. By default this will just use the state of - // the best block, but you might want it to use some other block's state instead if it's - // more sophisticated. Grandpa, for example, will probably want to use the state of the last - // finalised block. - let authorities = authorities_at::(client, &at).ok()?; - let maybe_pub = owned.into_iter() - .find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) -} - /// Type of source for block sealing. Different consensus algorithms have different sealing /// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. pub trait SealingSource { @@ -1248,61 +1209,6 @@ impl SealingSource for T { fn format(&self) -> String { use primitives::crypto::Ss58Codec; self.to_ss58check() } } -/// A runtime service for a consensus worker. -/// -/// This is administered by the client service to help it spin up everything necessary. It can -/// provide API hooks for handling user-level/RPC events. It can return information regarding -/// the status of the service. -pub trait Service<'a>: 'a { - /// Instance of the source of sealing. Different consensus algorithms have different sealing - /// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. - type Sealer: SealingSource; - - /// The Client type. Different services can make different constraints on this. - type Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>; - - /// Initialize the consensus service. - fn initialize(client: &'a Self::Client, keystore: Arc) -> Self; - - /// Return status of the authoring/sealing instance. For PoA/PoS consensus mechanisms, this - /// will just be a public key. For PoW mechanisms, this could be the miner instance. - fn sealer(&self) -> Option; -} - -/// The Babe consensus service struct. This can be passed in to the main service as (one of) the -/// consensus modules if your chain uses Babe block production. -pub struct BabeService<'a, Client> where - Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - Client::Api: BabeApi<::Type>, -{ - /// The main client that lets us interact with the chain/state. - client: &'a Client, - /// The keystore. - keystore: Arc, -} - -impl<'a, Client> Service<'a> for BabeService<'a, Client> where - Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - Client::Api: BabeApi<::Type> -{ - type Sealer = AuthorityId; - type Client = Client; - - fn initialize(client: &'a Self::Client, keystore: Arc) -> Self { - // TODO: Put in any default/test keys into the keystore. - // TODO: Actually initialise the babe worker. - Self { client, keystore } - } - - fn sealer(&self) -> Option { - authority(self.client, self.keystore.clone()) - .map(|p| p.public()) - } -} - /// BABE test helpers. Utility methods for manually authoring blocks. #[cfg(feature = "test-helpers")] pub mod test_helpers { diff --git a/core/keystore/Cargo.toml b/core/keystore/Cargo.toml index 2e40e5953fffa..c56b9ba67dcbd 100644 --- a/core/keystore/Cargo.toml +++ b/core/keystore/Cargo.toml @@ -12,6 +12,7 @@ hex = "0.3" rand = "0.6" serde_json = "1.0" subtle = "2.0" +parking_lot = "0.9.0" [dev-dependencies] tempdir = "0.3" diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index eabdcf9cac086..4c9a55e3c02c2 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -18,7 +18,7 @@ #![warn(missing_docs)] -use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}}; +use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}, sync::Arc}; use primitives::{ crypto::{KeyTypeId, Pair as PairT, Public, IsWrappedBy, Protected}, traits::KeyStore, @@ -26,6 +26,11 @@ use primitives::{ use app_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519}; +use parking_lot::RwLock; + +/// Keystore pointer +pub type KeyStorePtr = Arc>; + /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] pub enum Error { @@ -72,10 +77,12 @@ impl Store { /// Open the store at the given path. /// /// Optionally takes a password that will be used to encrypt/decrypt the keys. - pub fn open>(path: T, password: Option>) -> Result { + pub fn open>(path: T, password: Option>) -> Result { let path = path.into(); fs::create_dir_all(&path)?; - Ok(Self { path, additional: HashMap::new(), password }) + + let instance = Self { path, additional: HashMap::new(), password }; + Ok(Arc::new(RwLock::new(instance))) } /// Get the public/private key pair for the given public key and key type. diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index cccc1976db3b6..7d76e692dc573 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -103,6 +103,7 @@ pub struct Service { ComponentOffchainStorage, ComponentBlock> >>, + keystore: keystore::KeyStorePtr, } /// Creates bare client without any networking. @@ -168,11 +169,7 @@ impl Service { // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let keystore = Arc::new( - parking_lot::RwLock::new( - Keystore::open(config.keystore_path.clone( ), config.keystore_password.clone())? - ) - ); + let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; let (client, on_demand) = Components::build_client(&config, executor, Some(keystore.clone()))?; let select_chain = Components::build_select_chain(&mut config, client.clone())?; @@ -462,14 +459,20 @@ impl Service { _telemetry: telemetry, _offchain_workers: offchain_workers, _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), + keystore, }) } - /// return a shared instance of Telemetry (if enabled) + /// Return a shared instance of Telemetry (if enabled) pub fn telemetry(&self) -> Option { self._telemetry.as_ref().map(|t| t.clone()) } + /// Returns the keystore instance. + pub fn keystore(&self) -> keystore::KeyStorePtr { + self.keystore.clone() + } + /// Spawns a task in the background that runs the future passed as parameter. pub fn spawn_task(&self, task: impl Future + Send + 'static) { let _ = self.to_spawn_tx.unbounded_send(Box::new(task)); diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 86469ff44d6e2..7d5c8c33caacb 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -118,38 +118,33 @@ construct_service_factory! { // TODO: key used should be automated and both of these should be plugins. - let maybe_babe_key: Option = None;//service.authority_key(); let maybe_grandpa_key = None;//service.fg_authority_key(); - if let Some(babe_key) = maybe_babe_key { - info!("Using BABE key {}", babe_key.public()); - - let proposer = substrate_basic_authorship::ProposerFactory { - client: service.client(), - transaction_pool: service.transaction_pool(), - }; - - let client = service.client(); - let select_chain = service.select_chain() - .ok_or(ServiceError::SelectChainRequired)?; - - let babe_config = babe::BabeParams { - config: Config::get_or_compute(&*client)?, - local_key: Arc::new(babe_key), - client, - select_chain, - block_import, - env: proposer, - sync_oracle: service.network(), - inherent_data_providers: service.config.custom.inherent_data_providers.clone(), - force_authoring: service.config.force_authoring, - time_source: babe_link, - }; - - let babe = start_babe(babe_config)?; - let select = babe.select(service.on_exit()).then(|_| Ok(())); - service.spawn_task(Box::new(select)); - } + let proposer = substrate_basic_authorship::ProposerFactory { + client: service.client(), + transaction_pool: service.transaction_pool(), + }; + + let client = service.client(); + let select_chain = service.select_chain() + .ok_or(ServiceError::SelectChainRequired)?; + + let babe_config = babe::BabeParams { + config: Config::get_or_compute(&*client)?, + keystore: service.keystore(), + client, + select_chain, + block_import, + env: proposer, + sync_oracle: service.network(), + inherent_data_providers: service.config.custom.inherent_data_providers.clone(), + force_authoring: service.config.force_authoring, + time_source: babe_link, + }; + + let babe = start_babe(babe_config)?; + let select = babe.select(service.on_exit()).then(|_| Ok(())); + service.spawn_task(Box::new(select)); let maybe_grandpa_key = if service.config.disable_grandpa { None diff --git a/srml/babe/Cargo.toml b/srml/babe/Cargo.toml index ba47d8e278f41..bbc759c967937 100644 --- a/srml/babe/Cargo.toml +++ b/srml/babe/Cargo.toml @@ -17,11 +17,11 @@ system = { package = "srml-system", path = "../system", default-features = false timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } session = { package = "srml-session", path = "../session", default-features = false } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false } -runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false, features = [ "wasm-nice-panic-message" ] } [dev-dependencies] lazy_static = "1.3.0" -parking_lot = "0.8.0" +parking_lot = "0.9.0" primitives = { package = "substrate-primitives", path = "../../core/primitives" } [features] From 2de90fb6939b1d71df0f596b6af58db743e90c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 16:39:18 +0200 Subject: [PATCH 57/80] Fix grandpa --- core/finality-grandpa/Cargo.toml | 2 +- .../finality-grandpa/src/communication/mod.rs | 4 +- core/finality-grandpa/src/environment.rs | 38 +++---- core/finality-grandpa/src/lib.rs | 98 ++++--------------- core/finality-grandpa/src/observer.rs | 2 +- core/network/src/config.rs | 5 + node/cli/src/service.rs | 64 +++++------- 7 files changed, 71 insertions(+), 142 deletions(-) diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 3b0d7391ce9d1..e1402602364cb 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -18,7 +18,7 @@ sr-primitives = { path = "../sr-primitives" } consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } primitives = { package = "substrate-primitives", path = "../primitives" } substrate-telemetry = { path = "../telemetry" } -substrate-keystore = { path = "../keystore" } +keystore = { package = "substrate-keystore", path = "../keystore" } serde_json = "1.0" client = { package = "substrate-client", path = "../client" } inherents = { package = "substrate-inherents", path = "../../core/inherents" } diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index c54be8fcee39e..9452a9b34201b 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -341,7 +341,7 @@ impl> NetworkBridge { round: Round, set_id: SetId, voters: Arc>, - local_key: Option>, + local_key: Option, has_voted: HasVoted, ) -> ( impl Stream,Error=Error>, @@ -652,7 +652,7 @@ pub(crate) fn check_message_sig( struct OutgoingMessages> { round: u64, set_id: u64, - locals: Option<(Arc, AuthorityId)>, + locals: Option<(AuthorityPair, AuthorityId)>, sender: mpsc::UnboundedSender>, network: N, has_voted: HasVoted, diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index 423691c279427..28f7f0f97f15d 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -498,15 +498,25 @@ where let prevote_timer = Delay::new(now + self.config.gossip_duration * 2); let precommit_timer = Delay::new(now + self.config.gossip_duration * 4); - let local_key = self.config.local_key.as_ref() - .filter(|pair| self.voters.contains_key(&pair.public().into())); + let local_key = crate::is_voter(&self.voters, &self.config.keystore); + + let has_voted = match self.voter_set_state.has_voted() { + HasVoted::Yes(id, vote) => { + if local_key.as_ref().map(|k| k.public() == id).unwrap_or(false) { + HasVoted::Yes(id, vote) + } else { + HasVoted::No + } + }, + HasVoted::No => HasVoted::No, + }; let (incoming, outgoing) = self.network.round_communication( crate::communication::Round(round), crate::communication::SetId(self.set_id), self.voters.clone(), - local_key.cloned(), - self.voter_set_state.has_voted(), + local_key.clone(), + has_voted, ); // schedule incoming messages from the network to be held until @@ -521,7 +531,7 @@ where let outgoing = Box::new(outgoing.sink_map_err(Into::into)); voter::RoundData { - voter_id: self.config.local_key.as_ref().map(|pair| pair.public().clone()), + voter_id: local_key.map(|pair| pair.public()), prevote_timer: Box::new(prevote_timer.map_err(|e| Error::Timer(e).into())), precommit_timer: Box::new(precommit_timer.map_err(|e| Error::Timer(e).into())), incoming, @@ -530,12 +540,10 @@ where } fn proposed(&self, _round: u64, propose: PrimaryPropose) -> Result<(), Self::Error> { - let local_id = self.config.local_key.as_ref() - .map(|pair| pair.public().into()) - .filter(|id| self.voters.contains_key(&id)); + let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { - Some(id) => id, + Some(id) => id.public(), None => return Ok(()), }; @@ -569,12 +577,10 @@ where } fn prevoted(&self, _round: u64, prevote: Prevote) -> Result<(), Self::Error> { - let local_id = self.config.local_key.as_ref() - .map(|pair| pair.public().into()) - .filter(|id| self.voters.contains_key(&id)); + let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { - Some(id) => id, + Some(id) => id.public(), None => return Ok(()), }; @@ -611,12 +617,10 @@ where } fn precommitted(&self, _round: u64, precommit: Precommit) -> Result<(), Self::Error> { - let local_id = self.config.local_key.as_ref() - .map(|pair| pair.public().into()) - .filter(|id| self.voters.contains_key(&id)); + let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { - Some(id) => id, + Some(id) => id.public(), None => return Ok(()), }; diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 50f1dc84ce88e..98c58c4dc5d7f 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -56,20 +56,19 @@ use futures::prelude::*; use log::{debug, info, warn}; use futures::sync::mpsc; use client::{ - BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError, BlockOf, - blockchain::ProvideCache + BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError, }; use client::blockchain::HeaderBackend; -use parity_codec::{Encode, Decode}; +use parity_codec::Encode; use sr_primitives::generic::BlockId; use sr_primitives::traits::{ NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi }; use fg_primitives::{GrandpaApi, AuthorityPair}; -use substrate_keystore::Store; +use keystore::KeyStorePtr; use inherents::InherentDataProviders; -use consensus_common::{SelectChain, well_known_cache_keys, Error as ConsensusError}; -use primitives::{H256, Pair, Blake2Hasher}; +use consensus_common::SelectChain; +use primitives::{H256, Blake2Hasher}; use substrate_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG, CONSENSUS_WARN}; use serde_json; @@ -202,10 +201,10 @@ pub struct Config { /// at least every justification_period blocks. There are some other events which might cause /// justification generation. pub justification_period: u32, - /// The local signing key. - pub local_key: Option>, /// Some local identifier of the voter. pub name: Option, + /// The keystore that manages the keys of this node. + pub keystore: keystore::KeyStorePtr, } impl Config { @@ -400,11 +399,11 @@ where } fn global_communication, B, E, N, RA>( - local_key: Option<&Arc>, set_id: u64, voters: &Arc>, client: &Arc>, network: &NetworkBridge, + keystore: &KeyStorePtr, ) -> ( impl Stream< Item = CommunicationInH, @@ -421,10 +420,7 @@ fn global_communication, B, E, N, RA>( RA: Send + Sync, NumberFor: BlockNumberOps, { - - let is_voter = local_key - .map(|pair| voters.contains_key(&pair.public().into())) - .unwrap_or(false); + let is_voter = is_voter(voters, keystore).is_some(); // verification stream let (global_in, global_out) = network.global_communication( @@ -495,7 +491,7 @@ pub struct GrandpaParams, N, RA, SC, X> { /// block import worker that has already been instantiated with `block_import`. pub fn run_grandpa_voter, N, RA, SC, X>( grandpa_params: GrandpaParams, -) -> ::client::error::Result + Send + 'static> where +) -> client::error::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, E: CallExecutor + Send + Sync + 'static, @@ -572,31 +568,6 @@ pub fn run_grandpa_voter, N, RA, SC, X>( voter_set_state: set_state.clone(), }); - initial_environment.update_voter_set_state(|voter_set_state| { - match voter_set_state { - VoterSetState::Live { current_round: HasVoted::Yes(id, _), completed_rounds } => { - let local_id = config.local_key.clone().map(|pair| pair.public()); - let has_voted = match local_id { - Some(local_id) => if *id == local_id { - // keep the previous votes - return Ok(None); - } else { - HasVoted::No - }, - _ => HasVoted::No, - }; - - // NOTE: only updated on disk when the voter first - // proposes/prevotes/precommits or completes a round. - Ok(Some(VoterSetState::Live { - current_round: has_voted, - completed_rounds: completed_rounds.clone(), - })) - }, - _ => Ok(None), - } - }).expect("operation inside closure cannot fail; qed"); - let initial_state = (initial_environment, voter_commands_rx.into_future()); let voter_work = future::loop_fn(initial_state, move |params| { let (env, voter_commands_rx) = params; @@ -615,20 +586,18 @@ pub fn run_grandpa_voter, N, RA, SC, X>( ); let global_comms = global_communication( - config.local_key.as_ref(), env.set_id, &env.voters, &client, &network, + &config.keystore, ); - let voters = (*env.voters).clone(); - let last_completed_round = completed_rounds.last(); Some(voter::Voter::new( env.clone(), - voters, + (*env.voters).clone(), global_comms, last_completed_round.number, last_completed_round.state.clone(), @@ -782,40 +751,9 @@ pub fn run_grandpa, N, RA, SC, X>( run_grandpa_voter(grandpa_params) } -/// Provide a list of authority keys that is current as of a given block. -#[allow(deprecated)] -fn authorities_at(client: &C, at: &BlockId<::Type>) - -> Result, ConsensusError> -where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, - C::Api: GrandpaApi<::Type> -{ - client - .cache() - .and_then(|cache| cache - .get_at(&well_known_cache_keys::AUTHORITIES, at) - .and_then(|v| Decode::decode(&mut &v[..])) - ) - .or_else(|| GrandpaApi::grandpa_authorities(&*client.runtime_api(), at).ok() - .map(|authorities| authorities.into_iter().map(|x| x.0).collect()) - ) - .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) -} - -/// Provide the authority key, if any, that is controlled by this node as of the given block. -fn authority(client: &C, keystore: Arc) -> Option where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - C::Api: GrandpaApi<::Type> -{ - let owned = keystore.public_keys::().ok()?; - let at = BlockId::Number(client.info().finalized_number); - // The list of authority keys that is current. By default this will just use the state of - // the best block, but you might want it to use some other block's state instead if it's - // more sophisticated. Grandpa, for example, will probably want to use the state of the last - // finalised block. - let authorities = authorities_at::(client, &at).ok()?; - let maybe_pub = owned.into_iter() - .find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) -} +/// Checks if this node is a voter in the given voter set. +/// +/// Returns the key pair of the node that is being used in the current voter set or `None`. +fn is_voter(voters: &Arc>, keystore: &KeyStorePtr) -> Option { + voters.voters().iter().find_map(|(p, _)| keystore.read().key_pair::(&p).ok()) +} \ No newline at end of file diff --git a/core/finality-grandpa/src/observer.rs b/core/finality-grandpa/src/observer.rs index 1301a6656bba7..f347b678b6cef 100644 --- a/core/finality-grandpa/src/observer.rs +++ b/core/finality-grandpa/src/observer.rs @@ -185,11 +185,11 @@ pub fn run_grandpa_observer, N, RA, SC>( // start global communication stream for the current set let (global_in, _) = global_communication( - None, set_id, &voters, &client, &network, + &config.keystore, ); let last_finalized_number = client.info().chain.finalized_number; diff --git a/core/network/src/config.rs b/core/network/src/config.rs index 13e9a0d3a5a23..8c08934b8a5f9 100644 --- a/core/network/src/config.rs +++ b/core/network/src/config.rs @@ -103,6 +103,11 @@ impl Roles { self.intersects(Roles::FULL | Roles::AUTHORITY) } + /// Does this role represents a client that does not participates in the consensus? + pub fn is_authority(&self) -> bool { + *self == Roles::AUTHORITY + } + /// Does this role represents a client that does not hold full chain data locally? pub fn is_light(&self) -> bool { !self.is_full() diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 7d5c8c33caacb..737584cde211b 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -22,11 +22,9 @@ use std::sync::Arc; use std::time::Duration; use babe::{import_queue, start_babe, BabeImportQueue, Config}; -use babe_primitives::AuthorityPair as BabePair; use client::{self, LongestChain}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use node_executor; -use primitives::Pair; use futures::prelude::*; use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; @@ -39,7 +37,6 @@ use transaction_pool::{self, txpool::{Pool as TransactionPool}}; use inherents::InherentDataProviders; use network::construct_simple_protocol; use substrate_service::construct_service_factory; -use log::info; use substrate_service::TelemetryOnConnect; construct_simple_protocol! { @@ -116,18 +113,13 @@ construct_service_factory! { } } - // TODO: key used should be automated and both of these should be plugins. - - let maybe_grandpa_key = None;//service.fg_authority_key(); - let proposer = substrate_basic_authorship::ProposerFactory { client: service.client(), transaction_pool: service.transaction_pool(), }; let client = service.client(); - let select_chain = service.select_chain() - .ok_or(ServiceError::SelectChainRequired)?; + let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?; let babe_config = babe::BabeParams { config: Config::get_or_compute(&*client)?, @@ -146,44 +138,34 @@ construct_service_factory! { let select = babe.select(service.on_exit()).then(|_| Ok(())); service.spawn_task(Box::new(select)); - let maybe_grandpa_key = if service.config.disable_grandpa { - None - } else { - maybe_grandpa_key - }; - let config = grandpa::Config { - local_key: maybe_grandpa_key.map(Arc::new), // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 4096, - name: Some(service.config.name.clone()) + name: Some(service.config.name.clone()), + keystore: service.keystore(), }; - match config.local_key { - None if !service.config.grandpa_voter => { - service.spawn_task(Box::new(grandpa::run_grandpa_observer( - config, - link_half, - service.network(), - service.on_exit(), - )?)); - }, - // Either config.local_key is set, or user forced voter service via `--grandpa-voter` flag. - _ => { - let telemetry_on_connect = TelemetryOnConnect { - telemetry_connection_sinks: service.telemetry_on_connect_stream(), - }; - let grandpa_config = grandpa::GrandpaParams { - config: config, - link: link_half, - network: service.network(), - inherent_data_providers: service.config.custom.inherent_data_providers.clone(), - on_exit: service.on_exit(), - telemetry_on_connect: Some(telemetry_on_connect), - }; - service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); - }, + if service.config.roles.is_authority() { + let telemetry_on_connect = TelemetryOnConnect { + telemetry_connection_sinks: service.telemetry_on_connect_stream(), + }; + let grandpa_config = grandpa::GrandpaParams { + config: config, + link: link_half, + network: service.network(), + inherent_data_providers: service.config.custom.inherent_data_providers.clone(), + on_exit: service.on_exit(), + telemetry_on_connect: Some(telemetry_on_connect), + }; + service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); + } else if !service.config.grandpa_voter { + service.spawn_task(Box::new(grandpa::run_grandpa_observer( + config, + link_half, + service.network(), + service.on_exit(), + )?)); } Ok(service) From 67aa751737abab6d1fcd58e1a92c310f551a472c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 19:57:47 +0200 Subject: [PATCH 58/80] Fix tests --- Cargo.lock | 4 ++ core/consensus/babe/Cargo.toml | 3 +- core/consensus/babe/src/lib.rs | 8 +-- core/consensus/babe/src/tests.rs | 30 +++++--- core/finality-grandpa/Cargo.toml | 1 + .../src/communication/gossip.rs | 2 +- .../src/communication/tests.rs | 2 +- core/finality-grandpa/src/lib.rs | 15 ++-- core/finality-grandpa/src/tests.rs | 71 +++++++++++++++---- core/keyring/src/ed25519.rs | 4 ++ core/keyring/src/sr25519.rs | 4 ++ core/keystore/src/lib.rs | 31 ++++---- core/service/test/src/lib.rs | 2 +- node-template/runtime/Cargo.toml | 2 + node-template/runtime/src/lib.rs | 24 +++++-- node/cli/Cargo.toml | 3 +- node/cli/src/chain_spec.rs | 2 + node/cli/src/service.rs | 12 ++-- node/executor/src/lib.rs | 1 + 19 files changed, 159 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36b50ff795b9d..af1f0239ecfb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2300,6 +2300,7 @@ dependencies = [ "substrate-service-test 2.0.0", "substrate-telemetry 2.0.0", "substrate-transaction-pool 2.0.0", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-factory 0.0.1", ] @@ -2455,6 +2456,7 @@ dependencies = [ "substrate-consensus-aura-primitives 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", + "substrate-session 2.0.0", "substrate-wasm-builder-runner 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4465,6 +4467,7 @@ dependencies = [ "substrate-service 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4608,6 +4611,7 @@ dependencies = [ "substrate-service 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index 0d48e65810e8e..c76ddef46ba46 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -18,7 +18,7 @@ runtime-version = { package = "sr-version", path = "../../sr-version" } runtime-io = { package = "sr-io", path = "../../sr-io" } inherents = { package = "substrate-inherents", path = "../../inherents" } substrate-telemetry = { path = "../../telemetry" } -substrate-keystore = { path = "../../keystore" } +keystore = { package = "substrate-keystore", path = "../../keystore" } srml-babe = { path = "../../../srml/babe" } client = { package = "substrate-client", path = "../../client" } consensus-common = { package = "substrate-consensus-common", path = "../common" } @@ -42,6 +42,7 @@ service = { package = "substrate-service", path = "../../service" } test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" } tokio = "0.1.18" env_logger = "0.6.1" +tempfile = "3.1" [features] test-helpers = [] diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index ff4f95d028c0e..8ca345299289e 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -33,7 +33,7 @@ use sr_primitives::traits::{ Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi, SimpleBitOps, Zero, }; -use substrate_keystore::KeyStorePtr; +use keystore::KeyStorePtr; use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; use parking_lot::{Mutex, MutexGuard}; @@ -1220,8 +1220,8 @@ pub mod test_helpers { client: &C, at: &BlockId, slot_number: u64, - key: &AuthorityPair, c: (u64, u64), + keystore: &KeyStorePtr, ) -> Option where B: BlockT, C: ProvideRuntimeApi + ProvideCache, @@ -1232,9 +1232,9 @@ pub mod test_helpers { super::claim_slot( slot_number, epoch, - key, c, - ).map(|((inout, vrf_proof, _), authority_index)| { + keystore, + ).map(|((inout, vrf_proof, _), authority_index, _)| { BabePreDigest { vrf_proof, vrf_output: inout.to_output(), diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index 445bf77bcfb61..06761c9dee055 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -190,15 +190,21 @@ fn run_one_test() { let net = BabeTestNet::new(3); let peers = &[ - (0, Keyring::Alice), - (1, Keyring::Bob), - (2, Keyring::Charlie), + (0, "//Alice"), + (1, "//Bob"), + (2, "//Charlie"), ]; let net = Arc::new(Mutex::new(net)); let mut import_notifications = Vec::new(); let mut runtime = current_thread::Runtime::new().unwrap(); - for (peer_id, key) in peers { + let mut keystore_paths = Vec::new(); + for (peer_id, seed) in peers { + let keystore_path = tempfile::tempdir().expect("Creates keystore path"); + let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); + keystore.write().generate_from_seed::(seed).expect("Generates authority key"); + keystore_paths.push(keystore_path); + let client = net.lock().peer(*peer_id).client().as_full().unwrap(); let environ = DummyFactory(client.clone()); import_notifications.push( @@ -207,21 +213,18 @@ fn run_one_test() { .for_each(move |_| future::ready(())) ); - let config = Config::get_or_compute(&*client) - .expect("slot duration available"); + let config = Config::get_or_compute(&*client).expect("slot duration available"); let inherent_data_providers = InherentDataProviders::new(); register_babe_inherent_data_provider( &inherent_data_providers, config.get() ).expect("Registers babe inherent data provider"); - #[allow(deprecated)] let select_chain = LongestChain::new(client.backend().clone()); runtime.spawn(start_babe(BabeParams { config, - local_key: Arc::new(key.clone().pair().into()), block_import: client.clone(), select_chain, client, @@ -230,6 +233,7 @@ fn run_one_test() { inherent_data_providers, force_authoring: false, time_source: Default::default(), + keystore, }).expect("Starts babe")); } @@ -312,7 +316,11 @@ fn sig_is_not_pre_digest() { #[test] fn can_author_block() { let _ = env_logger::try_init(); - let (pair, _) = AuthorityPair::generate(); + let keystore_path = tempfile::tempdir().expect("Creates keystore path"); + let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); + let pair = keystore.write().generate_from_seed::("//Alice") + .expect("Generates authority pair"); + let mut i = 0; let epoch = Epoch { start_slot: 0, @@ -322,10 +330,10 @@ fn can_author_block() { duration: 100, }; loop { - match claim_slot(i, epoch.clone(), &pair, (3, 10)) { + match claim_slot(i, epoch.clone(), (3, 10), &keystore) { None => i += 1, Some(s) => { - debug!(target: "babe", "Authored block {:?}", s); + debug!(target: "babe", "Authored block {:?}", s.0); break } } diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index e1402602364cb..080d1f8302db6 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -36,6 +36,7 @@ test-client = { package = "substrate-test-runtime-client", path = "../test-runti babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } env_logger = "0.6" tokio = "0.1.17" +tempfile = "3.1" [features] default = ["service-integration"] diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index df4c41c8958ac..1f1fd5588567c 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -1240,7 +1240,7 @@ mod tests { crate::Config { gossip_duration: Duration::from_millis(10), justification_period: 256, - local_key: None, + keystore: None, name: None, } } diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index 20eba1a414d99..302b2d410311c 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -133,7 +133,7 @@ fn config() -> crate::Config { crate::Config { gossip_duration: std::time::Duration::from_millis(10), justification_period: 256, - local_key: None, + keystore: None, name: None, } } diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 98c58c4dc5d7f..bdb579e3d5271 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -204,7 +204,7 @@ pub struct Config { /// Some local identifier of the voter. pub name: Option, /// The keystore that manages the keys of this node. - pub keystore: keystore::KeyStorePtr, + pub keystore: Option, } impl Config { @@ -403,7 +403,7 @@ fn global_communication, B, E, N, RA>( voters: &Arc>, client: &Arc>, network: &NetworkBridge, - keystore: &KeyStorePtr, + keystore: &Option, ) -> ( impl Stream< Item = CommunicationInH, @@ -754,6 +754,13 @@ pub fn run_grandpa, N, RA, SC, X>( /// Checks if this node is a voter in the given voter set. /// /// Returns the key pair of the node that is being used in the current voter set or `None`. -fn is_voter(voters: &Arc>, keystore: &KeyStorePtr) -> Option { - voters.voters().iter().find_map(|(p, _)| keystore.read().key_pair::(&p).ok()) +fn is_voter( + voters: &Arc>, + keystore: &Option, +) -> Option { + match keystore { + Some(keystore) => voters.voters().iter() + .find_map(|(p, _)| keystore.read().key_pair::(&p).ok()), + None => None, + } } \ No newline at end of file diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 4689e1f23820a..b9a98e6a983b7 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -346,6 +346,15 @@ fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() } +fn create_keystore(authority: Ed25519Keyring) -> (KeyStorePtr, tempfile::TempDir) { + let keystore_path = tempfile::tempdir().expect("Creates keystore path"); + let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); + keystore.write().generate_from_seed::(&authority.to_seed()) + .expect("Creates authority key"); + + (keystore, keystore_path) +} + // run the voters to completion. provide a closure to be invoked after // the voters are spawned but before blocking on them. fn run_to_completion_with( @@ -367,7 +376,11 @@ fn run_to_completion_with( wait_for.push(f); }; + let mut keystore_paths = Vec::new(); for (peer_id, key) in peers.iter().enumerate() { + let (keystore, keystore_path) = create_keystore(*key); + keystore_paths.push(keystore_path); + let highest_finalized = highest_finalized.clone(); let (client, net_service, link) = { let net = net.lock(); @@ -402,7 +415,7 @@ fn run_to_completion_with( config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(key.clone().pair().into())), + keystore: Some(keystore), name: Some(format!("peer#{}", peer_id)), }, link: link, @@ -459,8 +472,10 @@ fn finalize_3_voters_no_observers() { run_to_completion(&mut runtime, 20, net.clone(), peers); // normally there's no justification for finalized blocks - assert!(net.lock().peer(0).client().justification(&BlockId::Number(20)).unwrap().is_none(), - "Extra justification for block#1"); + assert!( + net.lock().peer(0).client().justification(&BlockId::Number(20)).unwrap().is_none(), + "Extra justification for block#1", + ); } #[test] @@ -479,8 +494,10 @@ fn finalize_3_voters_1_full_observer() { let all_peers = peers.iter() .cloned() - .map(|key| Some(Arc::new(key.pair().into()))) - .chain(::std::iter::once(None)); + .map(Some) + .chain(std::iter::once(None)); + + let mut keystore_paths = Vec::new(); for (peer_id, local_key) in all_peers.enumerate() { let (client, net_service, link) = { @@ -499,11 +516,19 @@ fn finalize_3_voters_1_full_observer() { .for_each(move |_| Ok(())) ); + let keystore = if let Some(local_key) = local_key { + let (keystore, keystore_path) = create_keystore(local_key); + keystore_paths.push(keystore_path); + Some(keystore) + } else { + None + }; + let grandpa_params = GrandpaParams { config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key, + keystore, name: Some(format!("peer#{}", peer_id)), }, link: link, @@ -637,10 +662,13 @@ fn transition_3_voters_twice_1_full_observer() { .cloned() .collect::>() // deduplicate .into_iter() - .map(|key| Some(Arc::new(key.pair().into()))) .enumerate(); + let mut keystore_paths = Vec::new(); for (peer_id, local_key) in all_peers { + let (keystore, keystore_path) = create_keystore(local_key); + keystore_paths.push(keystore_path); + let (client, net_service, link) = { let net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); @@ -671,7 +699,7 @@ fn transition_3_voters_twice_1_full_observer() { config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key, + keystore: Some(keystore), name: Some(format!("peer#{}", peer_id)), }, link: link, @@ -1077,6 +1105,8 @@ fn voter_persists_its_votes() { let (voter_tx, voter_rx) = mpsc::unbounded::<()>(); + let mut keystore_paths = Vec::new(); + // startup a grandpa voter for alice but also listen for messages on a // channel. whenever a message is received the voter is restarted. when the // sender is dropped the voter is stopped. @@ -1084,6 +1114,9 @@ fn voter_persists_its_votes() { let net = net.clone(); let client = client.clone(); + let (keystore, keystore_path) = create_keystore(peers[0]); + keystore_paths.push(keystore_path); + let voter = future::loop_fn(voter_rx, move |rx| { let (_block_import, _, _, _, link) = net.lock().make_block_import(client.clone()); let link = link.lock().take().unwrap(); @@ -1092,7 +1125,7 @@ fn voter_persists_its_votes() { config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(peers[0].clone().pair().into())), + keystore: Some(keystore.clone()), name: Some(format!("peer#{}", 0)), }, link, @@ -1141,10 +1174,13 @@ fn voter_persists_its_votes() { // voter. instead we'll listen for the prevote that alice casts // and cast our own manually { + let (keystore, keystore_path) = create_keystore(peers[1]); + keystore_paths.push(keystore_path); + let config = Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: Some(Arc::new(peers[1].clone().pair().into())), + keystore: Some(keystore), name: Some(format!("peer#{}", 1)), }; @@ -1167,7 +1203,7 @@ fn voter_persists_its_votes() { communication::Round(1), communication::SetId(0), Arc::new(VoterSet::from_iter(voters)), - Some(config.local_key.unwrap()), + Some(peers[1].pair().into()), HasVoted::No, ); @@ -1293,7 +1329,7 @@ fn finalize_3_voters_1_light_observer() { Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key: None, + keystore: None, name: Some("observer".to_string()), }, link, @@ -1414,12 +1450,12 @@ fn voter_catches_up_to_latest_round_when_behind() { let net = Arc::new(Mutex::new(net)); let mut finality_notifications = Vec::new(); - let voter = |local_key, peer_id, link, net: Arc>| -> Box + Send> { + let voter = |keystore, peer_id, link, net: Arc>| -> Box + Send> { let grandpa_params = GrandpaParams { config: Config { gossip_duration: TEST_GOSSIP_DURATION, justification_period: 32, - local_key, + keystore, name: Some(format!("peer#{}", peer_id)), }, link, @@ -1432,6 +1468,8 @@ fn voter_catches_up_to_latest_round_when_behind() { Box::new(run_grandpa_voter(grandpa_params).expect("all in order with client and network")) }; + let mut keystore_paths = Vec::new(); + // spawn authorities for (peer_id, key) in peers.iter().enumerate() { let (client, link) = { @@ -1450,7 +1488,10 @@ fn voter_catches_up_to_latest_round_when_behind() { .for_each(move |_| Ok(())) ); - let voter = voter(Some(Arc::new(key.pair().into())), peer_id, link, net.clone()); + let (keystore, keystore_path) = create_keystore(*key); + keystore_paths.push(keystore_path); + + let voter = voter(Some(keystore), peer_id, link, net.clone()); runtime.spawn(voter); } diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index 48917eef64c34..f4d4ec5993432 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -76,6 +76,10 @@ impl Keyring { pub fn public(self) -> Public { self.pair().public() } + + pub fn to_seed(self) -> String { + format!("//{}", self) + } } impl From for &'static str { diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index 3e201ab8ae96e..21f0f1bb7d274 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -77,6 +77,10 @@ impl Keyring { pub fn public(self) -> Public { self.pair().public() } + + pub fn to_seed(self) -> String { + format!("//{}", self) + } } impl From for &'static str { diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 4c9a55e3c02c2..c66e245113e2c 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -272,22 +272,23 @@ mod tests { let temp_dir = TempDir::new("keystore").unwrap(); let store = Store::open(temp_dir.path(), None).unwrap(); - assert!(store.public_keys::().unwrap().is_empty()); + assert!(store.read().public_keys::().unwrap().is_empty()); - let key: ed25519::AppPair = store.generate().unwrap(); - let key2: ed25519::AppPair = store.key_pair(&key.public()).unwrap(); + let key: ed25519::AppPair = store.write().generate().unwrap(); + let key2: ed25519::AppPair = store.read().key_pair(&key.public()).unwrap(); assert_eq!(key.public(), key2.public()); - assert_eq!(store.public_keys::().unwrap()[0], key.public()); + assert_eq!(store.read().public_keys::().unwrap()[0], key.public()); } #[test] fn test_generate_from_seed() { let temp_dir = TempDir::new("keystore").unwrap(); - let mut store = Store::open(temp_dir.path(), None).unwrap(); + let store = Store::open(temp_dir.path(), None).unwrap(); let pair: ed25519::AppPair = store + .write() .generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc") .unwrap(); assert_eq!( @@ -298,7 +299,7 @@ mod tests { drop(store); let store = Store::open(temp_dir.path(), None).unwrap(); // Keys generated from seed should not be persisted! - assert!(store.key_pair::(&pair.public()).is_err()); + assert!(store.read().key_pair::(&pair.public()).is_err()); } #[test] @@ -307,41 +308,41 @@ mod tests { let temp_dir = TempDir::new("keystore").unwrap(); let store = Store::open(temp_dir.path(), Some(password.clone().into())).unwrap(); - let pair: ed25519::AppPair = store.generate().unwrap(); + let pair: ed25519::AppPair = store.write().generate().unwrap(); assert_eq!( pair.public(), - store.key_pair::(&pair.public()).unwrap().public(), + store.read().key_pair::(&pair.public()).unwrap().public(), ); // Without the password the key should not be retrievable let store = Store::open(temp_dir.path(), None).unwrap(); - assert!(store.key_pair::(&pair.public()).is_err()); + assert!(store.read().key_pair::(&pair.public()).is_err()); let store = Store::open(temp_dir.path(), Some(password.into())).unwrap(); assert_eq!( pair.public(), - store.key_pair::(&pair.public()).unwrap().public(), + store.read().key_pair::(&pair.public()).unwrap().public(), ); } #[test] fn public_keys_are_returned() { let temp_dir = TempDir::new("keystore").unwrap(); - let mut store = Store::open(temp_dir.path(), None).unwrap(); + let store = Store::open(temp_dir.path(), None).unwrap(); let mut public_keys = Vec::new(); for i in 0..10 { - public_keys.push(store.generate::().unwrap().public()); - public_keys.push(store.generate_from_seed::( + public_keys.push(store.write().generate::().unwrap().public()); + public_keys.push(store.write().generate_from_seed::( &format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i), ).unwrap().public()); } // Generate a key of a different type - store.generate::().unwrap(); + store.write().generate::().unwrap(); public_keys.sort(); - let mut store_pubs = store.public_keys::().unwrap(); + let mut store_pubs = store.read().public_keys::().unwrap(); store_pubs.sort(); assert_eq!(public_keys, store_pubs); diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 46a6ac13ff932..43ea7a1c010f2 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -173,7 +173,7 @@ fn node_config ( roles: role, transaction_pool: Default::default(), network: network_config, - keystore_path: Some(root.join("key")), + keystore_path: root.join("key"), keystore_password: None, database_path: root.join("db"), database_cache_size: None, diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 1bde2479304a6..234dac8d85c37 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -13,6 +13,7 @@ runtime-io = { package = "sr-io", path = "../../core/sr-io", default_features = version = { package = "sr-version", path = "../../core/sr-version", default_features = false } support = { package = "srml-support", path = "../../srml/support", default_features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default_features = false } +substrate-session = { path = "../../core/session", default-features = false } balances = { package = "srml-balances", path = "../../srml/balances", default_features = false } aura = { package = "srml-aura", path = "../../srml/aura", default_features = false } executive = { package = "srml-executive", path = "../../srml/executive", default_features = false } @@ -50,5 +51,6 @@ std = [ "safe-mix/std", "consensus-aura/std", "offchain-primitives/std", + "substrate-session/std", ] no_std = [] diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 50b4d18b417a1..2b9220c6e585b 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -9,8 +9,11 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use rstd::prelude::*; -use primitives::{sr25519, OpaqueMetadata}; -use sr_primitives::{ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str}; +use primitives::{sr25519, OpaqueMetadata, crypto::key_types}; +use sr_primitives::{ + ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, + impl_opaque_keys, +}; use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; use client::{ @@ -71,8 +74,13 @@ pub mod opaque { pub type Block = generic::Block; /// Opaque block identifier type. pub type BlockId = generic::BlockId; - /// Opaque session key type. - pub type SessionKey = AuraId; + + impl_opaque_keys! { + pub struct SessionKeys { + #[id(key_types::AURA)] + pub aura: AuraId, + } + } } /// This runtime version. @@ -154,6 +162,7 @@ impl indices::Trait for Runtime { parameter_types! { pub const MinimumPeriod: u64 = 5000; } + impl timestamp::Trait for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; @@ -301,4 +310,11 @@ impl_runtime_apis! { Executive::offchain_worker(n) } } + + impl substrate_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); + opaque::SessionKeys::generate(seed) + } + } } diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 5ca4109990506..4d33d010cd208 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -30,7 +30,6 @@ grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality- grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" } sr-primitives = { path = "../../core/sr-primitives" } node-executor = { path = "../executor" } -substrate-keystore = { path = "../../core/keystore" } substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" } structopt = "0.2" transaction-factory = { path = "../../test-utils/transaction-factory" } @@ -46,10 +45,12 @@ support = { package = "srml-support", path = "../../srml/support", default-featu im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } [dev-dependencies] +keystore = { package = "substrate-keystore", path = "../../core/keystore" } babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe", features = ["test-helpers"] } consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" } service-test = { package = "substrate-service-test", path = "../../core/service/test" } futures03 = { package = "futures-preview", version = "0.3.0-alpha.17" } +tempfile = "3.1" [build-dependencies] cli = { package = "substrate-cli", path = "../../core/cli" } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 5eeddea8257a0..1d59882407e2f 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -176,6 +176,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), + membership_Instance1: Some(Default::default()), } } @@ -307,6 +308,7 @@ pub fn testnet_genesis( grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), + membership_Instance1: Some(Default::default()), } } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 737584cde211b..dfa8d86e8a209 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -143,7 +143,7 @@ construct_service_factory! { gossip_duration: Duration::from_millis(333), justification_period: 4096, name: Some(service.config.name.clone()), - keystore: service.keystore(), + keystore: Some(service.keystore()), }; if service.config.roles.is_authority() { @@ -252,7 +252,7 @@ mod tests { use sr_primitives::{generic::{BlockId, Era, Digest}, traits::Block, OpaqueExtrinsic}; use timestamp; use finality_tracker; - use keyring::{AccountKeyring, Sr25519Keyring}; + use keyring::AccountKeyring; use substrate_service::ServiceFactory; use service_test::SyncService; use crate::service::Factory; @@ -318,9 +318,13 @@ mod tests { #[test] #[ignore] fn test_sync() { + let keystore_path = tempfile::tempdir().expect("Creates keystore path"); + let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); + let alice = keystore.write().generate_from_seed::("//Alice") + .expect("Creates authority pair"); + let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); - let alice = Sr25519Keyring::Alice.pair(); let mut slot_num = 1u64; let block_factory = |service: &SyncService<::FullService>| { let service = service.get(); @@ -349,8 +353,8 @@ mod tests { &*service.client(), &parent_id, slot_num, - &alice.clone().into(), (278, 1000), + &keystore, ) { break babe_pre_digest; } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 36ac834f2400d..27cc3dfb4931c 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -383,6 +383,7 @@ mod tests { democracy: Some(Default::default()), collective_Instance1: Some(Default::default()), collective_Instance2: Some(Default::default()), + membership_Instance1: Some(Default::default()), elections: Some(Default::default()), contracts: Some(ContractsConfig { current_schedule: Default::default(), From eb080c4e05c3c1ec0bbe1234c2f83ebd1e3972b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 6 Aug 2019 22:54:35 +0200 Subject: [PATCH 59/80] Disable `keystore` in consensus critical stuff --- core/client/src/call_executor.rs | 12 ++++++++++-- core/client/src/client.rs | 6 +++++- core/client/src/light/call_executor.rs | 24 ++++++++++++++++++++---- core/offchain/src/lib.rs | 2 +- core/primitives/src/lib.rs | 12 +++++++++++- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 643cbaecabb26..b7edccae3c923 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -83,6 +83,7 @@ where native_call: Option, side_effects_handler: Option<&mut O>, proof_recorder: &Option>>>, + enable_keystore: bool, ) -> error::Result> where ExecutionManager: Clone; /// Extract RuntimeVersion of given block @@ -237,6 +238,7 @@ where native_call: Option, side_effects_handler: Option<&mut O>, recorder: &Option>>>, + enable_keystore: bool, ) -> Result, error::Error> where ExecutionManager: Clone { match initialize_block { InitializeBlock::Do(ref init_block) @@ -247,6 +249,12 @@ where _ => {}, } + let keystore = if enable_keystore { + self.keystore.clone() + } else { + None + }; + let mut state = self.backend.state_at(*at)?; match recorder { @@ -270,7 +278,7 @@ where &self.executor, method, call_data, - self.keystore.clone(), + keystore, ) .execute_using_consensus_failure_handler( execution_manager, @@ -288,7 +296,7 @@ where &self.executor, method, call_data, - self.keystore.clone(), + keystore, ) .execute_using_consensus_failure_handler( execution_manager, diff --git a/core/client/src/client.rs b/core/client/src/client.rs index b5c60cea22358..19961cdb41cc2 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -371,7 +371,8 @@ impl Client where pub fn storage(&self, id: &BlockId, key: &StorageKey) -> error::Result> { Ok(self.state_at(id)? .storage(&key.0).map_err(|e| error::Error::from_state(Box::new(e)))? - .map(StorageData)) + .map(StorageData) + ) } /// Given a `BlockId` and a key, return the value under the hash in that block. @@ -1423,6 +1424,8 @@ impl CallRuntimeAt for Client where context: ExecutionContext, recorder: &Option>>>, ) -> error::Result> { + let enable_keystore = context.enable_keystore(); + let manager = match context { ExecutionContext::BlockConstruction => self.execution_strategies.block_construction.get_manager(), @@ -1452,6 +1455,7 @@ impl CallRuntimeAt for Client where native_call, offchain_extensions.as_mut(), recorder, + enable_keystore, ) } diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index cf5aaadcb0770..36b84b0d39b99 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -94,8 +94,8 @@ where call_data: &[u8], _strategy: ExecutionStrategy, _side_effects_handler: Option<&mut O>, - ) - -> ClientResult> { + ) -> ClientResult> + { let block_hash = self.blockchain.expect_block_hash_from_id(id)?; let block_header = self.blockchain.expect_header(id.clone())?; @@ -130,6 +130,7 @@ where _native_call: Option, side_effects_handler: Option<&mut O>, _recorder: &Option>>>, + _enable_keystore: bool, ) -> ClientResult> where ExecutionManager: Clone { let block_initialized = match initialize_block { InitializeBlock::Do(ref init_block) => { @@ -143,11 +144,23 @@ where return Err(ClientError::NotAvailableOnLightClient.into()); } - self.call(at, method, call_data, (&execution_manager).into(), side_effects_handler).map(NativeOrEncoded::Encoded) + self.call( + at, + method, + call_data, + (&execution_manager).into(), + side_effects_handler, + ).map(NativeOrEncoded::Encoded) } fn runtime_version(&self, id: &BlockId) -> ClientResult { - let call_result = self.call(id, "Core_version", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new())?; + let call_result = self.call( + id, + "Core_version", + &[], + ExecutionStrategy::NativeElseWasm, + NeverOffchainExt::new() + )?; RuntimeVersion::decode(&mut call_result.as_slice()) .ok_or_else(|| ClientError::VersionInvalid.into()) } @@ -270,6 +283,7 @@ impl CallExecutor for native_call: Option, side_effects_handler: Option<&mut O>, recorder: &Option>>>, + enable_keystore: bool, ) -> ClientResult> where ExecutionManager: Clone { // there's no actual way/need to specify native/wasm execution strategy on light node // => we can safely ignore passed values @@ -296,6 +310,7 @@ impl CallExecutor for native_call, side_effects_handler, recorder, + enable_keystore, ).map_err(|e| ClientError::Execution(Box::new(e.to_string()))), false => CallExecutor::contextual_call::< _, @@ -318,6 +333,7 @@ impl CallExecutor for native_call, side_effects_handler, recorder, + enable_keystore, ).map_err(|e| ClientError::Execution(Box::new(e.to_string()))), } } diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index d683127120293..b1e3b4d77a425 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -134,7 +134,7 @@ impl OffchainWorkers< let run = runtime.offchain_worker_with_context( &at, ExecutionContext::OffchainWorker(api), - number + number, ); if let Err(e) = run { log::error!("Error running offchain workers at {:?}: {:?}", at, e); diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 5a7fa8e5219a7..91837741fd3d8 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -81,7 +81,6 @@ pub use hash_db::Hasher; pub use self::hasher::blake2::Blake2Hasher; /// Context for executing a call into the runtime. -#[repr(u8)] pub enum ExecutionContext { /// Context for general importing (including own blocks). Importing, @@ -95,6 +94,17 @@ pub enum ExecutionContext { Other, } +impl ExecutionContext { + /// Returns if the keystore should be enabled for the current context. + pub fn enable_keystore(&self) -> bool { + use ExecutionContext::*; + match self { + Importing | Syncing | BlockConstruction => false, + OffchainWorker(_) | Other => true, + } + } +} + /// Hex-serialized shim for `Vec`. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord))] From 20bddb98fce40fa934fbc2a3eb0e42f0ea0422da Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 10:00:13 +0200 Subject: [PATCH 60/80] Build fix. --- node/executor/src/lib.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 36ac834f2400d..605ffd8f0a19c 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -329,13 +329,12 @@ mod tests { fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { let mut ext = TestExternalities::new_with_code_with_children(code, GenesisConfig { - babe: Some(Default::default()), system: Some(SystemConfig { changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { digest_interval: 2, digest_levels: 2, }) } else { None }, - ..Default::default() + .. Default::default() }), indices: Some(IndicesConfig { ids: vec![alice(), bob(), charlie(), dave(), eve(), ferdie()], @@ -369,7 +368,7 @@ mod tests { }), staking: Some(StakingConfig { current_era: 0, - stakers: vec![ + stakers: vec![® (dave(), alice(), 111 * DOLLARS, staking::StakerStatus::Validator), (eve(), bob(), 100 * DOLLARS, staking::StakerStatus::Validator), (ferdie(), charlie(), 100 * DOLLARS, staking::StakerStatus::Validator) @@ -380,19 +379,14 @@ mod tests { offline_slash_grace: 0, invulnerables: vec![alice(), bob(), charlie()], }), - democracy: Some(Default::default()), - collective_Instance1: Some(Default::default()), - collective_Instance2: Some(Default::default()), - elections: Some(Default::default()), contracts: Some(ContractsConfig { current_schedule: Default::default(), gas_price: 1 * MILLICENTS, }), - sudo: Some(Default::default()), - im_online: Some(Default::default()), grandpa: Some(GrandpaConfig { authorities: vec![], }), + .. Some(Default::default()) }.build_storage().unwrap()); ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); ext From 296c16a81f37535f717e72ac68c6b51bc58d1a8d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 10:46:44 +0200 Subject: [PATCH 61/80] ImOnline supports multiple authorities at once. --- node/executor/src/lib.rs | 9 ++++++++- srml/im-online/src/lib.rs | 23 +++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 38c928d0a75a5..d012d35778693 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -383,10 +383,17 @@ mod tests { current_schedule: Default::default(), gas_price: 1 * MILLICENTS, }), + babe: Some(Default::default()), grandpa: Some(GrandpaConfig { authorities: vec![], }), - .. Some(Default::default()) + im_online: Some(Default::default()), + democracy: Some(Default::default()), + collective_Instance1: Some(Default::default()), + collective_Instance2: Some(Default::default()), + membership_Instance1: Some(Default::default()), + elections: Some(Default::default()), + sudo: Some(Default::default()), }.build_storage().unwrap()); ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); ext diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index fb5189e38cf34..2483425c0999e 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -267,21 +267,20 @@ impl Module { // we run only when a local authority key is configured let key_type = KeyTypeId(*b"imon"); let authorities = Keys::get(); - let local_keys = sr_io::public_keys(AuthorityId::KIND, key_type) + let mut local_keys = sr_io::public_keys(AuthorityId::KIND, key_type) .map_err(|_| OffchainErr::NoKeys)?; - let maybe_key = authorities.into_iter() + local_keys.sort_by(|a, b| a.public.cmp(&b.public)); + for (authority_index, key) in authorities.into_iter() .enumerate() - .filter_map(|(index, id)| { - let id = app::crypto::Public::from(id); - let id_slice: &[u8] = id.as_ref(); - - local_keys - .iter() - .find(|k| &*k.public == id_slice) - .map(|key| (index as u32, key.clone())) + .filter_map(|(index, authority)| { + let authority = app::crypto::Public::from(authority); + let authority: &[u8] = authority.as_ref(); + + local_keys.binary_search_by(|probe| probe.public[..].cmp(authority)) + .ok() + .map(|location| (index as u32, local_keys[location].clone())) }) - .next(); - if let Some((authority_index, key)) = maybe_key { + { let network_state = sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; let heartbeat_data = Heartbeat { From a27d58c9d7486e7278d66ee79d7fb06f463178fb Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 7 Aug 2019 11:48:01 +0200 Subject: [PATCH 62/80] Update core/application-crypto/src/ed25519.rs --- core/application-crypto/src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index b50424a91e12f..8461366f242ae 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Sr25519 crypto types. +//! Ed25519 crypto types. use crate::{RuntimePublic, KeyTypeId}; @@ -72,4 +72,4 @@ mod tests { assert!(AppPair::verify(&signature, "ed25519", key_pair.public())); } -} \ No newline at end of file +} From 24a9693b30ee5ad7a1622d1fd71a8bdc82c234d2 Mon Sep 17 00:00:00 2001 From: Fredrik Date: Wed, 7 Aug 2019 13:29:24 +0200 Subject: [PATCH 63/80] Merge branch 'master' into gav-in-progress --- Cargo.lock | 25 +- core/consensus/babe/Cargo.toml | 2 +- core/consensus/babe/primitives/Cargo.toml | 2 +- core/consensus/babe/primitives/src/digest.rs | 13 +- core/consensus/babe/src/lib.rs | 2 +- core/network/src/on_demand_layer.rs | 2 +- core/network/src/protocol.rs | 42 +-- .../{on_demand.rs => light_dispatch.rs} | 324 ++++++++++-------- core/network/src/service.rs | 16 +- core/primitives/Cargo.toml | 4 +- core/primitives/src/sr25519.rs | 77 +++-- node/runtime/src/lib.rs | 2 +- srml/support/procedural/src/storage/impls.rs | 21 ++ srml/support/src/storage/hashed/generator.rs | 2 +- srml/support/test/tests/instance.rs | 32 +- subkey/Cargo.toml | 3 +- 16 files changed, 327 insertions(+), 242 deletions(-) rename core/network/src/protocol/{on_demand.rs => light_dispatch.rs} (70%) diff --git a/Cargo.lock b/Cargo.lock index e49ebdd3d3975..ce037ef45c747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3331,19 +3331,17 @@ dependencies = [ [[package]] name = "schnorrkel" -version = "0.1.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "merlin 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4236,11 +4234,10 @@ dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "srml-balances 2.0.0", "srml-system 2.0.0", - "substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4287,12 +4284,12 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4447,7 +4444,7 @@ dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-version 2.0.0", @@ -4476,7 +4473,7 @@ name = "substrate-consensus-babe-primitives" version = "2.0.0" dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", @@ -4786,11 +4783,11 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", - "substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-serializer 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6403,7 +6400,7 @@ dependencies = [ "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339" -"checksum schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5eff518f9bed3d803a0d002af0ab96339b0ebbedde3bec98a684986134b7a39" +"checksum schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "77e8d6a92f49a53f21b71c090a5559bf45c469071ebe556aebaf2dca3abc5cb5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" @@ -6443,7 +6440,7 @@ dependencies = [ "checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f" "checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e" -"checksum substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d69ace596e9ca97837cc41f8edcfc4e0a997f227d5fc153d1010b60a0fe9acda" +"checksum substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3be511be555a3633e71739a79e4ddff6a6aaa6579fa6114182a51d72c3eb93c5" "checksum substrate-wasm-builder-runner 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f52ecbff6cc3d6e5c6401828e15937b680f459d6803ce238f01fe615bc40d071" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829" diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index bdafcc903f566..b4bb9c96de75a 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -30,7 +30,7 @@ futures01 = { package = "futures", version = "0.1" } futures-timer = "0.2.1" parking_lot = "0.8.0" log = "0.4.6" -schnorrkel = "0.1.1" +schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"] } rand = "0.6.5" merlin = "1.0.3" diff --git a/core/consensus/babe/primitives/Cargo.toml b/core/consensus/babe/primitives/Cargo.toml index e380300a53323..5f7fbe4fd8129 100644 --- a/core/consensus/babe/primitives/Cargo.toml +++ b/core/consensus/babe/primitives/Cargo.toml @@ -11,8 +11,8 @@ rstd = { package = "sr-std", path = "../../../sr-std", default-features = false sr-primitives = { path = "../../../sr-primitives", default-features = false } app-crypto = { package = "substrate-application-crypto", path = "../../../application-crypto", default-features = false } slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true } +schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"], optional = true } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } -schnorrkel = { version = "0.1.1", optional = true } [features] default = ["std"] diff --git a/core/consensus/babe/primitives/src/digest.rs b/core/consensus/babe/primitives/src/digest.rs index 8cf56d3227f2a..3b6e3221bd8a8 100644 --- a/core/consensus/babe/primitives/src/digest.rs +++ b/core/consensus/babe/primitives/src/digest.rs @@ -153,6 +153,7 @@ fn convert_error(e: SignatureError) -> codec::Error { EquationFalse => "Signature error: `EquationFalse`".into(), PointDecompressionError => "Signature error: `PointDecompressionError`".into(), ScalarFormatError => "Signature error: `ScalarFormatError`".into(), + NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(), BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(), MuSigAbsent { musig_stage: Commitment } => "Signature error: `MuSigAbsent` at stage `Commitment`".into(), @@ -161,16 +162,16 @@ fn convert_error(e: SignatureError) -> codec::Error { MuSigAbsent { musig_stage: Cosignature } => "Signature error: `MuSigAbsent` at stage `Commitment`".into(), MuSigInconsistent { musig_stage: Commitment, duplicate: true } => - "Signature error: `MuSigInconsistent` at strage `Commitment` on duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(), MuSigInconsistent { musig_stage: Commitment, duplicate: false } => - "Signature error: `MuSigInconsistent` at strage `Commitment` on not duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(), MuSigInconsistent { musig_stage: Reveal, duplicate: true } => - "Signature error: `MuSigInconsistent` at strage `Reveal` on duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(), MuSigInconsistent { musig_stage: Reveal, duplicate: false } => - "Signature error: `MuSigInconsistent` at strage `Reveal` on not duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(), MuSigInconsistent { musig_stage: Cosignature, duplicate: true } => - "Signature error: `MuSigInconsistent` at strage `Cosignature` on duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(), MuSigInconsistent { musig_stage: Cosignature, duplicate: false } => - "Signature error: `MuSigInconsistent` at strage `Cosignature` on not duplicate".into(), + "Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(), } } diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index a19ae4b798f0c..3b87e3fe1f549 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -838,7 +838,7 @@ fn claim_slot( let threshold = calculate_threshold(c, authorities, authority_index); get_keypair(&key_pair) - .vrf_sign_n_check(transcript, |inout| check(inout, threshold)) + .vrf_sign_after_check(transcript, |inout| check(inout, threshold)) .map(|s|(s, authority_index, key_pair)) } diff --git a/core/network/src/on_demand_layer.rs b/core/network/src/on_demand_layer.rs index 1cbb5387d6416..818230eea54b8 100644 --- a/core/network/src/on_demand_layer.rs +++ b/core/network/src/on_demand_layer.rs @@ -16,7 +16,7 @@ //! On-demand requests service. -use crate::protocol::on_demand::RequestData; +use crate::protocol::light_dispatch::RequestData; use std::sync::Arc; use futures::{prelude::*, sync::mpsc, sync::oneshot}; use futures03::compat::{Compat01As03, Future01CompatExt as _}; diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index e23ec1e099745..9d4a537ed208d 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -34,7 +34,7 @@ use message::{BlockAttributes, Direction, FromBlock, Message, RequestId}; use message::generic::{Message as GenericMessage, ConsensusMessage}; use event::Event; use consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; -use on_demand::{OnDemandCore, OnDemandNetwork, RequestData}; +use light_dispatch::{LightDispatch, LightDispatchNetwork, RequestData}; use specialization::NetworkSpecialization; use sync::{ChainSync, SyncState}; use crate::service::{TransactionPool, ExHashT}; @@ -53,7 +53,7 @@ mod util; pub mod consensus_gossip; pub mod message; pub mod event; -pub mod on_demand; +pub mod light_dispatch; pub mod specialization; pub mod sync; @@ -96,8 +96,8 @@ pub struct Protocol, H: ExHashT> { /// Interval at which we call `propagate_extrinsics`. propagate_timeout: Box + Send>, config: ProtocolConfig, - /// Handler for on-demand requests. - on_demand_core: OnDemandCore, + /// Handler for light client requests. + light_dispatch: LightDispatch, genesis_hash: B::Hash, sync: ChainSync, specialization: S, @@ -149,12 +149,12 @@ pub struct PeerInfo { pub best_number: ::Number, } -struct OnDemandIn<'a, B: BlockT> { +struct LightDispatchIn<'a, B: BlockT> { behaviour: &'a mut CustomProto>, peerset: peerset::PeersetHandle, } -impl<'a, B: BlockT> OnDemandNetwork for OnDemandIn<'a, B> { +impl<'a, B: BlockT> LightDispatchNetwork for LightDispatchIn<'a, B> { fn report_peer(&mut self, who: &PeerId, reputation: i32) { self.peerset.report_peer(who.clone(), reputation) } @@ -373,7 +373,7 @@ impl, H: ExHashT> Protocol { peers: HashMap::new(), chain, }, - on_demand_core: OnDemandCore::new(checker), + light_dispatch: LightDispatch::new(checker), genesis_hash: info.chain.genesis_hash, sync, specialization: specialization, @@ -445,15 +445,15 @@ impl, H: ExHashT> Protocol { /// Starts a new data demand request. /// /// The parameter contains a `Sender` where the result, once received, must be sent. - pub(crate) fn add_on_demand_request(&mut self, rq: RequestData) { - self.on_demand_core.add_request(OnDemandIn { + pub(crate) fn add_light_client_request(&mut self, rq: RequestData) { + self.light_dispatch.add_request(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, rq); } - fn is_on_demand_response(&self, who: &PeerId, response_id: message::RequestId) -> bool { - self.on_demand_core.is_on_demand_response(&who, response_id) + fn is_light_response(&self, who: &PeerId, response_id: message::RequestId) -> bool { + self.light_dispatch.is_light_response(&who, response_id) } fn handle_response( @@ -506,7 +506,7 @@ impl, H: ExHashT> Protocol { GenericMessage::BlockRequest(r) => self.on_block_request(who, r), GenericMessage::BlockResponse(r) => { // Note, this is safe because only `ordinary bodies` and `remote bodies` are received in this matter. - if self.is_on_demand_response(&who, r.id) { + if self.is_light_response(&who, r.id) { self.on_remote_body_response(who, r); } else { if let Some(request) = self.handle_response(who.clone(), &r) { @@ -629,7 +629,7 @@ impl, H: ExHashT> Protocol { } self.sync.peer_disconnected(peer.clone()); self.specialization.on_disconnect(&mut context, peer.clone()); - self.on_demand_core.on_disconnect(OnDemandIn { + self.light_dispatch.on_disconnect(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, peer); @@ -793,7 +793,7 @@ impl, H: ExHashT> Protocol { &mut ProtocolContext::new(&mut self.context_data, &mut self.behaviour, &self.peerset_handle) ); self.maintain_peers(); - self.on_demand_core.maintain_peers(OnDemandIn { + self.light_dispatch.maintain_peers(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }); @@ -914,7 +914,7 @@ impl, H: ExHashT> Protocol { }; let info = self.context_data.peers.get(&who).expect("We just inserted above; QED").info.clone(); - self.on_demand_core.on_connect(OnDemandIn { + self.light_dispatch.on_connect(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who.clone(), status.roles, status.best_number); @@ -1053,7 +1053,7 @@ impl, H: ExHashT> Protocol { peer.known_blocks.insert(hash.clone()); } } - self.on_demand_core.on_block_announce(OnDemandIn { + self.light_dispatch.update_best_number(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who.clone(), *header.number()); @@ -1253,7 +1253,7 @@ impl, H: ExHashT> Protocol { response: message::RemoteCallResponse ) { trace!(target: "sync", "Remote call response {} from {}", response.id, who); - self.on_demand_core.on_remote_call_response(OnDemandIn { + self.light_dispatch.on_remote_call_response(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who, response); @@ -1294,7 +1294,7 @@ impl, H: ExHashT> Protocol { response: message::RemoteReadResponse ) { trace!(target: "sync", "Remote read response {} from {}", response.id, who); - self.on_demand_core.on_remote_read_response(OnDemandIn { + self.light_dispatch.on_remote_read_response(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who, response); @@ -1335,7 +1335,7 @@ impl, H: ExHashT> Protocol { response: message::RemoteHeaderResponse, ) { trace!(target: "sync", "Remote header proof response {} from {}", response.id, who); - self.on_demand_core.on_remote_header_response(OnDemandIn { + self.light_dispatch.on_remote_header_response(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who, response); @@ -1401,7 +1401,7 @@ impl, H: ExHashT> Protocol { who, response.max ); - self.on_demand_core.on_remote_changes_response(OnDemandIn { + self.light_dispatch.on_remote_changes_response(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, who, response); @@ -1462,7 +1462,7 @@ impl, H: ExHashT> Protocol { peer: PeerId, response: message::BlockResponse ) { - self.on_demand_core.on_remote_body_response(OnDemandIn { + self.light_dispatch.on_remote_body_response(LightDispatchIn { behaviour: &mut self.behaviour, peerset: self.peerset_handle.clone(), }, peer, response); diff --git a/core/network/src/protocol/on_demand.rs b/core/network/src/protocol/light_dispatch.rs similarity index 70% rename from core/network/src/protocol/on_demand.rs rename to core/network/src/protocol/light_dispatch.rs index 9d35535e21deb..a7b327686af60 100644 --- a/core/network/src/protocol/on_demand.rs +++ b/core/network/src/protocol/light_dispatch.rs @@ -14,7 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! On-demand requests service. +//! Light client requests service. +//! +//! Handles requests for data coming from our local light client and that must be answered by +//! nodes on the network. use std::collections::{HashMap, VecDeque}; use std::sync::Arc; @@ -38,8 +41,8 @@ const RETRY_COUNT: usize = 1; /// Reputation change for a peer when a request timed out. const TIMEOUT_REPUTATION_CHANGE: i32 = -(1 << 8); -/// Trait used by the `OnDemandCore` service to communicate messages back to the network. -pub trait OnDemandNetwork { +/// Trait used by the `LightDispatch` service to communicate messages back to the network. +pub trait LightDispatchNetwork { /// Adjusts the reputation of the given peer. fn report_peer(&mut self, who: &PeerId, reputation_change: i32); @@ -97,19 +100,30 @@ pub trait OnDemandNetwork { ); } -/// On-demand requests service. Dispatches requests to appropriate peers. -pub struct OnDemandCore { +/// Light client requests service. Dispatches requests to appropriate peers. +pub struct LightDispatch { + /// Verifies that responses are correct. Passed at initialization. checker: Arc>, + /// Numeric ID to assign to the next outgoing request. Used to assign responses to their + /// corresponding request. next_request_id: u64, + /// Requests that we have yet to send out on the network. pending_requests: VecDeque>, + /// List of nodes to which we have sent a request and that are yet to answer. active_peers: LinkedHashMap>, + /// List of nodes that we know of that aren't doing anything and that are available for new + /// requests. idle_peers: VecDeque, + /// Best known block for each node in `active_peers` and `idle_peers`. best_blocks: HashMap>, } struct Request { id: u64, + /// When the request got created or sent out to the network. timestamp: Instant, + /// Number of remaining attempts to fulfill this request. If it reaches 0, we interrupt the + /// attempt. retry_count: usize, data: RequestData, } @@ -196,12 +210,12 @@ impl FetchChecker for AlwaysBadChecker { } } -impl OnDemandCore where +impl LightDispatch where B::Header: HeaderT, { - /// Creates new on-demand requests processer. + /// Creates new light client requests processer. pub fn new(checker: Arc>) -> Self { - OnDemandCore { + LightDispatch { checker, next_request_id: 0, pending_requests: VecDeque::new(), @@ -212,7 +226,7 @@ impl OnDemandCore where } /// Inserts a new request in the list of requests to execute. - pub(crate) fn add_request(&mut self, network: impl OnDemandNetwork, data: RequestData) { + pub(crate) fn add_request(&mut self, network: impl LightDispatchNetwork, data: RequestData) { self.insert(RETRY_COUNT, data); self.dispatch(network); } @@ -234,7 +248,7 @@ impl OnDemandCore where fn accept_response( &mut self, rtype: &str, - mut network: impl OnDemandNetwork, + mut network: impl LightDispatchNetwork, peer: PeerId, request_id: u64, try_accept: impl FnOnce(Request, &Arc>) -> Accept @@ -284,9 +298,10 @@ impl OnDemandCore where self.dispatch(network); } + /// Call this when we connect to a node on the network. pub fn on_connect( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, role: Roles, best_number: NumberFor @@ -301,17 +316,20 @@ impl OnDemandCore where self.dispatch(network); } - pub fn on_block_announce(&mut self, network: impl OnDemandNetwork, peer: PeerId, best_number: NumberFor) { + /// Sets the best seen block for the given node. + pub fn update_best_number(&mut self, network: impl LightDispatchNetwork, peer: PeerId, best_number: NumberFor) { self.best_blocks.insert(peer, best_number); self.dispatch(network); } - pub fn on_disconnect(&mut self, network: impl OnDemandNetwork, peer: PeerId) { + /// Call this when we disconnect from a node. + pub fn on_disconnect(&mut self, network: impl LightDispatchNetwork, peer: PeerId) { self.remove_peer(peer); self.dispatch(network); } - pub fn maintain_peers(&mut self, mut network: impl OnDemandNetwork) { + /// Must be called periodically in order to perform maintenance. + pub fn maintain_peers(&mut self, mut network: impl LightDispatchNetwork) { let now = Instant::now(); loop { @@ -329,9 +347,10 @@ impl OnDemandCore where self.dispatch(network); } + /// Handles a remote header response message from on the network. pub fn on_remote_header_response( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, response: message::RemoteHeaderResponse ) { @@ -352,9 +371,10 @@ impl OnDemandCore where }) } + /// Handles a remote read response message from on the network. pub fn on_remote_read_response( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, response: message::RemoteReadResponse ) { @@ -387,9 +407,10 @@ impl OnDemandCore where }) } + /// Handles a remote call response message from on the network. pub fn on_remote_call_response( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, response: message::RemoteCallResponse ) { @@ -406,9 +427,10 @@ impl OnDemandCore where }) } + /// Handles a remote changes response message from on the network. pub fn on_remote_changes_response( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, response: message::RemoteChangesResponse, B::Hash> ) { @@ -431,9 +453,10 @@ impl OnDemandCore where }) } + /// Handles a remote body response message from on the network. pub fn on_remote_body_response( &mut self, - network: impl OnDemandNetwork, + network: impl LightDispatchNetwork, peer: PeerId, response: message::BlockResponse ) { @@ -466,7 +489,7 @@ impl OnDemandCore where }) } - pub fn is_on_demand_response(&self, peer: &PeerId, request_id: message::RequestId) -> bool { + pub fn is_light_response(&self, peer: &PeerId, request_id: message::RequestId) -> bool { self.active_peers.get(&peer).map_or(false, |r| r.id == request_id) } @@ -483,7 +506,10 @@ impl OnDemandCore where } } - pub fn remove_peer(&mut self, peer: PeerId) { + /// Removes a peer from the list of known peers. + /// + /// Puts back the active request that this node was performing into `pending_requests`. + fn remove_peer(&mut self, peer: PeerId) { self.best_blocks.remove(&peer); if let Some(request) = self.active_peers.remove(&peer) { @@ -497,7 +523,7 @@ impl OnDemandCore where } /// Dispatches pending requests. - fn dispatch(&mut self, mut network: impl OnDemandNetwork) { + fn dispatch(&mut self, mut network: impl LightDispatchNetwork) { let mut last_peer = self.idle_peers.back().cloned(); let mut unhandled_requests = VecDeque::new(); @@ -551,6 +577,8 @@ impl OnDemandCore where } impl Request { + /// Returns the block that the remote needs to have in order to be able to fulfill + /// this request. fn required_block(&self) -> NumberFor { match self.data { RequestData::RemoteHeader(ref data, _) => data.block, @@ -562,7 +590,7 @@ impl Request { } } - fn send_to(&self, out: &mut impl OnDemandNetwork, peer: &PeerId) { + fn send_to(&self, out: &mut impl LightDispatchNetwork, peer: &PeerId) { match self.data { RequestData::RemoteHeader(ref data, _) => out.send_header_request( @@ -645,7 +673,7 @@ pub mod tests { use crate::config::Roles; use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; - use super::{REQUEST_TIMEOUT, OnDemandCore, OnDemandNetwork, RequestData}; + use super::{REQUEST_TIMEOUT, LightDispatch, LightDispatchNetwork, RequestData}; use test_client::runtime::{changes_trie_config, Block, Extrinsic, Header}; struct DummyFetchChecker { ok: bool } @@ -711,21 +739,21 @@ pub mod tests { } } - fn dummy(ok: bool) -> OnDemandCore { - OnDemandCore::new(Arc::new(DummyFetchChecker { ok })) + fn dummy(ok: bool) -> LightDispatch { + LightDispatch::new(Arc::new(DummyFetchChecker { ok })) } - fn total_peers(on_demand: &OnDemandCore) -> usize { - on_demand.idle_peers.len() + on_demand.active_peers.len() + fn total_peers(light_dispatch: &LightDispatch) -> usize { + light_dispatch.idle_peers.len() + light_dispatch.active_peers.len() } fn receive_call_response( - network_interface: impl OnDemandNetwork, - on_demand: &mut OnDemandCore, + network_interface: impl LightDispatchNetwork, + light_dispatch: &mut LightDispatch, peer: PeerId, id: message::RequestId ) { - on_demand.on_remote_call_response(network_interface, peer, message::RemoteCallResponse { + light_dispatch.on_remote_call_response(network_interface, peer, message::RemoteCallResponse { id: id, proof: vec![vec![2]], }); @@ -746,7 +774,7 @@ pub mod tests { disconnected_peers: HashSet, } - impl<'a, B: BlockT> OnDemandNetwork for &'a mut DummyNetwork { + impl<'a, B: BlockT> LightDispatchNetwork for &'a mut DummyNetwork { fn report_peer(&mut self, _: &PeerId, _: i32) {} fn disconnect_peer(&mut self, who: &PeerId) { self.disconnected_peers.insert(who.clone()); @@ -769,16 +797,16 @@ pub mod tests { #[test] fn knows_about_peers_roles() { let mut network_interface = DummyNetwork::default(); - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let peer0 = PeerId::random(); let peer1 = PeerId::random(); let peer2 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0, Roles::LIGHT, 1000); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 2000); - on_demand.on_connect(&mut network_interface, peer2.clone(), Roles::AUTHORITY, 3000); - assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert_eq!(on_demand.best_blocks.get(&peer1), Some(&2000)); - assert_eq!(on_demand.best_blocks.get(&peer2), Some(&3000)); + light_dispatch.on_connect(&mut network_interface, peer0, Roles::LIGHT, 1000); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 2000); + light_dispatch.on_connect(&mut network_interface, peer2.clone(), Roles::AUTHORITY, 3000); + assert_eq!(vec![peer1.clone(), peer2.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert_eq!(light_dispatch.best_blocks.get(&peer1), Some(&2000)); + assert_eq!(light_dispatch.best_blocks.get(&peer2), Some(&3000)); } #[test] @@ -786,69 +814,69 @@ pub mod tests { let peer0 = PeerId::random(); let mut network_interface = DummyNetwork::default(); - let mut on_demand = dummy(true); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 100); - assert_eq!(1, total_peers(&on_demand)); - assert!(!on_demand.best_blocks.is_empty()); - - on_demand.on_disconnect(&mut network_interface, peer0); - assert_eq!(0, total_peers(&on_demand)); - assert!(on_demand.best_blocks.is_empty()); + let mut light_dispatch = dummy(true); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 100); + assert_eq!(1, total_peers(&light_dispatch)); + assert!(!light_dispatch.best_blocks.is_empty()); + + light_dispatch.on_disconnect(&mut network_interface, peer0); + assert_eq!(0, total_peers(&light_dispatch)); + assert!(light_dispatch.best_blocks.is_empty()); } #[test] fn disconnects_from_timeouted_peer() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); let peer1 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 1000); - assert_eq!(vec![peer0.clone(), peer1.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert!(on_demand.active_peers.is_empty()); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 1000); + assert_eq!(vec![peer0.clone(), peer1.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert!(light_dispatch.active_peers.is_empty()); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), call_data: vec![], retry_count: None, }, oneshot::channel().0)); - assert_eq!(vec![peer1.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert_eq!(vec![peer0.clone()], on_demand.active_peers.keys().cloned().collect::>()); + assert_eq!(vec![peer1.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert_eq!(vec![peer0.clone()], light_dispatch.active_peers.keys().cloned().collect::>()); - on_demand.active_peers[&peer0].timestamp = Instant::now() - REQUEST_TIMEOUT - REQUEST_TIMEOUT; - on_demand.maintain_peers(&mut network_interface); - assert!(on_demand.idle_peers.is_empty()); - assert_eq!(vec![peer1.clone()], on_demand.active_peers.keys().cloned().collect::>()); + light_dispatch.active_peers[&peer0].timestamp = Instant::now() - REQUEST_TIMEOUT - REQUEST_TIMEOUT; + light_dispatch.maintain_peers(&mut network_interface); + assert!(light_dispatch.idle_peers.is_empty()); + assert_eq!(vec![peer1.clone()], light_dispatch.active_peers.keys().cloned().collect::>()); assert_disconnected_peer(&network_interface); } #[test] fn disconnects_from_peer_on_response_with_wrong_id() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let peer0 = PeerId::random(); let mut network_interface = DummyNetwork::default(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), call_data: vec![], retry_count: None, }, oneshot::channel().0)); - receive_call_response(&mut network_interface, &mut on_demand, peer0, 1); + receive_call_response(&mut network_interface, &mut light_dispatch, peer0, 1); assert_disconnected_peer(&network_interface); - assert_eq!(on_demand.pending_requests.len(), 1); + assert_eq!(light_dispatch.pending_requests.len(), 1); } #[test] fn disconnects_from_peer_on_incorrect_response() { - let mut on_demand = dummy(false); + let mut light_dispatch = dummy(false); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), @@ -856,31 +884,31 @@ pub mod tests { retry_count: Some(1), }, oneshot::channel().0)); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); - receive_call_response(&mut network_interface, &mut on_demand, peer0.clone(), 0); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + receive_call_response(&mut network_interface, &mut light_dispatch, peer0.clone(), 0); assert_disconnected_peer(&network_interface); - assert_eq!(on_demand.pending_requests.len(), 1); + assert_eq!(light_dispatch.pending_requests.len(), 1); } #[test] fn disconnects_from_peer_on_unexpected_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); - receive_call_response(&mut network_interface, &mut on_demand, peer0, 0); + receive_call_response(&mut network_interface, &mut light_dispatch, peer0, 0); assert_disconnected_peer(&network_interface); } #[test] fn disconnects_from_peer_on_wrong_response_type() { - let mut on_demand = dummy(false); + let mut light_dispatch = dummy(false); let peer0 = PeerId::random(); let mut network_interface = DummyNetwork::default(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), @@ -888,26 +916,26 @@ pub mod tests { retry_count: Some(1), }, oneshot::channel().0)); - on_demand.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { + light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, proof: vec![vec![2]], }); assert_disconnected_peer(&network_interface); - assert_eq!(on_demand.pending_requests.len(), 1); + assert_eq!(light_dispatch.pending_requests.len(), 1); } #[test] fn receives_remote_failure_after_retry_count_failures() { let retry_count = 2; let peer_ids = (0 .. retry_count + 1).map(|_| PeerId::random()).collect::>(); - let mut on_demand = dummy(false); + let mut light_dispatch = dummy(false); let mut network_interface = DummyNetwork::default(); for i in 0..retry_count+1 { - on_demand.on_connect(&mut network_interface, peer_ids[i].clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer_ids[i].clone(), Roles::FULL, 1000); } let (tx, mut response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), @@ -917,7 +945,7 @@ pub mod tests { for i in 0..retry_count { assert!(response.try_recv().unwrap().is_none()); - receive_call_response(&mut network_interface, &mut on_demand, peer_ids[i].clone(), i as u64); + receive_call_response(&mut network_interface, &mut light_dispatch, peer_ids[i].clone(), i as u64); } assert!(response.try_recv().unwrap().unwrap().is_err()); @@ -925,13 +953,13 @@ pub mod tests { #[test] fn receives_remote_call_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); let (tx, response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteCall(RemoteCallRequest { block: Default::default(), header: dummy_header(), method: "test".into(), @@ -939,26 +967,26 @@ pub mod tests { retry_count: None, }, tx)); - receive_call_response(&mut network_interface, &mut on_demand, peer0.clone(), 0); + receive_call_response(&mut network_interface, &mut light_dispatch, peer0.clone(), 0); assert_eq!(response.wait().unwrap().unwrap(), vec![42]); } #[test] fn receives_remote_read_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); let (tx, response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteRead(RemoteReadRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteRead(RemoteReadRequest { header: dummy_header(), block: Default::default(), key: b":key".to_vec(), retry_count: None, }, tx)); - on_demand.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { + light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, proof: vec![vec![2]], }); @@ -967,13 +995,13 @@ pub mod tests { #[test] fn receives_remote_read_child_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); let (tx, response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteReadChild(RemoteReadChildRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteReadChild(RemoteReadChildRequest { header: dummy_header(), block: Default::default(), storage_key: b":child_storage:sub".to_vec(), @@ -981,7 +1009,7 @@ pub mod tests { retry_count: None, }, tx)); - on_demand.on_remote_read_response(&mut network_interface, + light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, proof: vec![vec![2]], @@ -991,19 +1019,19 @@ pub mod tests { #[test] fn receives_remote_header_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); let (tx, response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 1, retry_count: None, }, tx)); - on_demand.on_remote_header_response(&mut network_interface, peer0.clone(), message::RemoteHeaderResponse { + light_dispatch.on_remote_header_response(&mut network_interface, peer0.clone(), message::RemoteHeaderResponse { id: 0, header: Some(Header { parent_hash: Default::default(), @@ -1022,13 +1050,13 @@ pub mod tests { #[test] fn receives_remote_changes_response() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer0 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); + light_dispatch.on_connect(&mut network_interface, peer0.clone(), Roles::FULL, 1000); let (tx, response) = oneshot::channel(); - on_demand.add_request(&mut network_interface, RequestData::RemoteChanges(RemoteChangesRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteChanges(RemoteChangesRequest { changes_trie_config: changes_trie_config(), first_block: (1, Default::default()), last_block: (100, Default::default()), @@ -1038,7 +1066,7 @@ pub mod tests { retry_count: None, }, tx)); - on_demand.on_remote_changes_response(&mut network_interface, peer0.clone(), message::RemoteChangesResponse { + light_dispatch.on_remote_changes_response(&mut network_interface, peer0.clone(), message::RemoteChangesResponse { id: 0, max: 1000, proof: vec![vec![2]], @@ -1050,52 +1078,52 @@ pub mod tests { #[test] fn does_not_sends_request_to_peer_who_has_no_required_block() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer1 = PeerId::random(); let peer2 = PeerId::random(); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 100); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 100); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 200, retry_count: None, }, oneshot::channel().0)); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 250, retry_count: None, }, oneshot::channel().0)); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 250, retry_count: None, }, oneshot::channel().0)); - on_demand.on_connect(&mut network_interface, peer2.clone(), Roles::FULL, 150); + light_dispatch.on_connect(&mut network_interface, peer2.clone(), Roles::FULL, 150); - assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert_eq!(on_demand.pending_requests.len(), 3); + assert_eq!(vec![peer1.clone(), peer2.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert_eq!(light_dispatch.pending_requests.len(), 3); - on_demand.on_block_announce(&mut network_interface, peer1.clone(), 250); + light_dispatch.update_best_number(&mut network_interface, peer1.clone(), 250); - assert_eq!(vec![peer2.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert_eq!(on_demand.pending_requests.len(), 2); + assert_eq!(vec![peer2.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert_eq!(light_dispatch.pending_requests.len(), 2); - on_demand.on_block_announce(&mut network_interface, peer2.clone(), 250); + light_dispatch.update_best_number(&mut network_interface, peer2.clone(), 250); - assert!(!on_demand.idle_peers.iter().any(|_| true)); - assert_eq!(on_demand.pending_requests.len(), 1); + assert!(!light_dispatch.idle_peers.iter().any(|_| true)); + assert_eq!(light_dispatch.pending_requests.len(), 1); - on_demand.on_remote_header_response(&mut network_interface, peer1.clone(), message::RemoteHeaderResponse { + light_dispatch.on_remote_header_response(&mut network_interface, peer1.clone(), message::RemoteHeaderResponse { id: 0, header: Some(dummy_header()), proof: vec![], }); - assert!(!on_demand.idle_peers.iter().any(|_| true)); - assert_eq!(on_demand.pending_requests.len(), 0); + assert!(!light_dispatch.idle_peers.iter().any(|_| true)); + assert_eq!(light_dispatch.pending_requests.len(), 0); } #[test] @@ -1103,70 +1131,70 @@ pub mod tests { // this test is a regression for a bug where the dispatch function would // loop forever after dispatching a request to the last peer, since the // last peer was not updated - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer1 = PeerId::random(); let peer2 = PeerId::random(); let peer3 = PeerId::random(); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 250, retry_count: None, }, oneshot::channel().0)); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 250, retry_count: None, }, oneshot::channel().0)); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 200); - on_demand.on_connect(&mut network_interface, peer2.clone(), Roles::FULL, 200); - on_demand.on_connect(&mut network_interface, peer3.clone(), Roles::FULL, 250); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 200); + light_dispatch.on_connect(&mut network_interface, peer2.clone(), Roles::FULL, 200); + light_dispatch.on_connect(&mut network_interface, peer3.clone(), Roles::FULL, 250); - assert_eq!(vec![peer1.clone(), peer2.clone()], on_demand.idle_peers.iter().cloned().collect::>()); - assert_eq!(on_demand.pending_requests.len(), 1); + assert_eq!(vec![peer1.clone(), peer2.clone()], light_dispatch.idle_peers.iter().cloned().collect::>()); + assert_eq!(light_dispatch.pending_requests.len(), 1); } #[test] fn tries_to_send_all_pending_requests() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer1 = PeerId::random(); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 300, retry_count: None, }, oneshot::channel().0)); - on_demand.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteHeader(RemoteHeaderRequest { cht_root: Default::default(), block: 250, retry_count: None, }, oneshot::channel().0)); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); - assert!(on_demand.idle_peers.iter().cloned().collect::>().is_empty()); - assert_eq!(on_demand.pending_requests.len(), 1); + assert!(light_dispatch.idle_peers.iter().cloned().collect::>().is_empty()); + assert_eq!(light_dispatch.pending_requests.len(), 1); } #[test] fn remote_body_with_one_block_body_should_succeed() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer1 = PeerId::random(); let header = dummy_header(); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); - on_demand.add_request(&mut network_interface, RequestData::RemoteBody(RemoteBodyRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteBody(RemoteBodyRequest { header: header.clone(), retry_count: None, }, oneshot::channel().0)); - assert!(on_demand.pending_requests.is_empty()); - assert_eq!(on_demand.active_peers.len(), 1); + assert!(light_dispatch.pending_requests.is_empty()); + assert_eq!(light_dispatch.active_peers.len(), 1); let block = message::BlockData:: { hash: primitives::H256::random(), @@ -1182,28 +1210,28 @@ pub mod tests { blocks: vec![block], }; - on_demand.on_remote_body_response(&mut network_interface, peer1.clone(), response); + light_dispatch.on_remote_body_response(&mut network_interface, peer1.clone(), response); - assert!(on_demand.active_peers.is_empty()); - assert_eq!(on_demand.idle_peers.len(), 1); + assert!(light_dispatch.active_peers.is_empty()); + assert_eq!(light_dispatch.idle_peers.len(), 1); } #[test] fn remote_body_with_three_bodies_should_fail() { - let mut on_demand = dummy(true); + let mut light_dispatch = dummy(true); let mut network_interface = DummyNetwork::default(); let peer1 = PeerId::random(); let header = dummy_header(); - on_demand.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); + light_dispatch.on_connect(&mut network_interface, peer1.clone(), Roles::FULL, 250); - on_demand.add_request(&mut network_interface, RequestData::RemoteBody(RemoteBodyRequest { + light_dispatch.add_request(&mut network_interface, RequestData::RemoteBody(RemoteBodyRequest { header: header.clone(), retry_count: None, }, oneshot::channel().0)); - assert!(on_demand.pending_requests.is_empty()); - assert_eq!(on_demand.active_peers.len(), 1); + assert!(light_dispatch.pending_requests.is_empty()); + assert_eq!(light_dispatch.active_peers.len(), 1); let response = { let blocks: Vec<_> = (0..3).map(|_| message::BlockData:: { @@ -1221,8 +1249,8 @@ pub mod tests { } }; - on_demand.on_remote_body_response(&mut network_interface, peer1.clone(), response); - assert!(on_demand.active_peers.is_empty()); - assert!(on_demand.idle_peers.is_empty(), "peer should be disconnected after bad response"); + light_dispatch.on_remote_body_response(&mut network_interface, peer1.clone(), response); + assert!(light_dispatch.active_peers.is_empty()); + assert!(light_dispatch.idle_peers.is_empty(), "peer should be disconnected after bad response"); } } diff --git a/core/network/src/service.rs b/core/network/src/service.rs index acd3bbeab7b10..ff5db5f702096 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -47,7 +47,7 @@ use crate::config::{Params, TransportConfig}; use crate::error::Error; use crate::protocol::{self, Protocol, Context, CustomMessageOutcome, PeerInfo}; use crate::protocol::consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; -use crate::protocol::{event::Event, on_demand::{AlwaysBadChecker, RequestData}}; +use crate::protocol::{event::Event, light_dispatch::{AlwaysBadChecker, RequestData}}; use crate::protocol::specialization::NetworkSpecialization; use crate::protocol::sync::SyncState; @@ -241,7 +241,7 @@ impl, H: ExHashT> NetworkWorker service, import_queue: params.import_queue, from_worker, - on_demand_in: params.on_demand.and_then(|od| od.extract_receiver()), + light_client_rqs: params.on_demand.and_then(|od| od.extract_receiver()), }) } @@ -585,8 +585,8 @@ pub struct NetworkWorker, H: Ex import_queue: Box>, /// Messages from the `NetworkService` and that must be processed. from_worker: mpsc::UnboundedReceiver>, - /// Receiver for queries from the on-demand that must be processed. - on_demand_in: Option>>, + /// Receiver for queries from the light client that must be processed. + light_client_rqs: Option>>, } impl, H: ExHashT> Future for NetworkWorker { @@ -602,10 +602,10 @@ impl, H: ExHashT> Future for Ne std::task::Poll::Pending::> }).compat().poll(); - // Check for new incoming on-demand requests. - if let Some(on_demand_in) = self.on_demand_in.as_mut() { - while let Ok(Async::Ready(Some(rq))) = on_demand_in.poll() { - self.network_service.user_protocol_mut().add_on_demand_request(rq); + // Check for new incoming light client requests. + if let Some(light_client_rqs) = self.light_client_rqs.as_mut() { + while let Ok(Async::Ready(Some(rq))) = light_client_rqs.poll() { + self.network_service.user_protocol_mut().add_light_client_request(rq); } } diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 46e710d2a3ba9..085b7f52c1dff 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -19,10 +19,10 @@ hash256-std-hasher = { version = "0.15.0", default-features = false } ed25519-dalek = { version = "1.0.0-pre.1", optional = true } base58 = { version = "0.1", optional = true } blake2-rfc = { version = "0.2.18", optional = true } -schnorrkel = { version = "0.1.1", optional = true } +schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"], optional = true } rand = { version = "0.6", optional = true } sha2 = { version = "0.8", optional = true } -substrate-bip39 = { version = "0.2.2", optional = true } +substrate-bip39 = { version = "0.3.1", optional = true } tiny-bip39 = { version = "0.6.1", optional = true } hex = { version = "0.3", optional = true } regex = { version = "1.1", optional = true } diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 56e719672e85e..a6ed4d72ceb58 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -22,7 +22,7 @@ // end::description[] #[cfg(feature = "std")] -use schnorrkel::{signing_context, Keypair, SecretKey, MiniSecretKey, PublicKey, +use schnorrkel::{signing_context, ExpansionMode, Keypair, SecretKey, MiniSecretKey, PublicKey, derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH} }; #[cfg(feature = "std")] @@ -335,7 +335,7 @@ impl TraitPublic for Public { #[cfg(feature = "std")] impl From for Pair { fn from(sec: MiniSecretKey) -> Pair { - Pair(sec.expand_to_keypair()) + Pair(sec.expand_to_keypair(ExpansionMode::Ed25519)) } } @@ -370,7 +370,7 @@ impl AsRef for Pair { /// Derive a single hard junction. #[cfg(feature = "std")] fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> SecretKey { - secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand() + secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand(ExpansionMode::Ed25519) } /// The raw secret seed, which can be used to recreate the `Pair`. @@ -411,7 +411,7 @@ impl TraitPair for Pair { Ok(Pair( MiniSecretKey::from_bytes(seed) .map_err(|_| SecretStringError::InvalidSeed)? - .expand_to_keypair() + .expand_to_keypair(ExpansionMode::Ed25519) )) } SECRET_KEY_LENGTH => { @@ -470,28 +470,23 @@ impl TraitPair for Pair { /// Verify a signature on a message. Returns true if the signature is good. fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool { - let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig.as_ref()) { - Ok(some_signature) => some_signature, - Err(_) => return false - }; + // Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets + // that have not been upgraded and those that have. To swap to 0.8.0 only, + // create `schnorrkel::Signature` and pass that into `verify_simple` match PublicKey::from_bytes(pubkey.as_ref().as_slice()) { - Ok(pk) => pk.verify( - signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature - ), + Ok(pk) => pk.verify_simple_preaudit_deprecated( + SIGNING_CTX, message.as_ref(), &sig.as_ref(), + ).is_ok(), Err(_) => false, } } /// Verify a signature on a message. Returns true if the signature is good. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(sig) { - Ok(some_signature) => some_signature, - Err(_) => return false - }; match PublicKey::from_bytes(pubkey.as_ref()) { - Ok(pk) => pk.verify( - signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature - ), + Ok(pk) => pk.verify_simple_preaudit_deprecated( + SIGNING_CTX, message.as_ref(), &sig, + ).is_ok(), Err(_) => false, } } @@ -512,7 +507,7 @@ impl Pair { let mini_key: MiniSecretKey = mini_secret_from_entropy(entropy, password.unwrap_or("")) .expect("32 bytes can always build a key; qed"); - let kp = mini_key.expand_to_keypair(); + let kp = mini_key.expand_to_keypair(ExpansionMode::Ed25519); (Pair(kp), mini_key.to_bytes()) } } @@ -535,6 +530,43 @@ impl CryptoType for Pair { type Pair = Pair; } +#[cfg(test)] +mod compatibility_test { + use super::*; + use crate::crypto::{DEV_PHRASE}; + use hex_literal::hex; + + // NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are + // still functional. + + #[test] + fn derive_soft_known_pair_should_work() { + let pair = Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap(); + // known address of DEV_PHRASE with 1.1 + let known = hex!("d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e"); + assert_eq!(pair.public().to_raw_vec(), known); + } + + #[test] + fn derive_hard_known_pair_should_work() { + let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap(); + // known address of DEV_PHRASE with 1.1 + let known = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + assert_eq!(pair.public().to_raw_vec(), known); + } + + #[test] + fn verify_known_message_should_work() { + let public = Public::from_raw(hex!("b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918")); + // signature generated by the 1.1 version with the same ^^ public key. + let signature = Signature::from_raw(hex!( + "5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202" + )); + let message = b"Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n"; + assert!(Pair::verify(&signature, &message[..], &public)); + } +} + #[cfg(test)] mod test { use super::*; @@ -645,7 +677,6 @@ mod test { #[test] fn seeded_pair_should_work() { - let pair = Pair::from_seed(b"12345678901234567890123456789012"); let public = pair.public(); assert_eq!( @@ -678,9 +709,9 @@ mod test { &hex!("0000000000000000000000000000000000000000000000000000000000000000") ); let public = pk.public(); - let js_signature = Signature::from_raw( - hex!("28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00") - ); + let js_signature = Signature::from_raw(hex!( + "28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00" + )); assert!(Pair::verify(&js_signature, b"SUBSTRATE", public)); } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 31ded5a4cc4f9..a0fd1903fc546 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -80,7 +80,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 129, + spec_version: 130, impl_version: 130, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/support/procedural/src/storage/impls.rs b/srml/support/procedural/src/storage/impls.rs index 45d7fada9fcaf..4424aa918a345 100644 --- a/srml/support/procedural/src/storage/impls.rs +++ b/srml/support/procedural/src/storage/impls.rs @@ -615,6 +615,27 @@ impl<'a, I: Iterator> Impls<'a, I> { storage.put(key_for, &(val, linkage)) } + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + /// Store a value under this key into the provided storage instance. + fn insert_ref(key: &#kty, val: &Arg, storage: &mut S) + where + #typ: AsRef, + Arg: ?Sized + #scrate::codec::Encode, + S: #scrate::HashedStorage<#scrate::#hasher> + { + use self::#inner_module::Utils; + + let key_for = &*#as_map::key_for(key); + let linkage = match Self::read_with_linkage(storage, key_for) { + // overwrite but reuse existing linkage + Some((_data, linkage)) => linkage, + // create new linkage + None => Self::new_head_linkage(storage, key), + }; + storage.put(key_for, &(val, linkage)) + } + /// Mutate the value under a key fn mutate(key: &#kty, f: F, storage: &mut S) -> R where diff --git a/srml/support/src/storage/hashed/generator.rs b/srml/support/src/storage/hashed/generator.rs index 867f808e78366..f8b8fb5483e1e 100644 --- a/srml/support/src/storage/hashed/generator.rs +++ b/srml/support/src/storage/hashed/generator.rs @@ -263,7 +263,7 @@ pub trait StorageMap { /// Store a value under this key into the provided storage instance; this can take any reference /// type that derefs to `T` (and has `Encode` implemented). /// Store a value under this key into the provided storage instance. - fn insert_ref>( + fn insert_ref>( key: &K, val: &Arg, storage: &mut S diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index f77b4a284a7f4..55bbc73807d58 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -27,7 +27,7 @@ use srml_support::{ use inherents::{ ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError }; -use srml_support::{StorageValue, StorageMap, StorageDoubleMap}; +use srml_support::{StorageValue, StorageMap, StorageDoubleMap, EnumerableStorageMap}; use primitives::{H256, sr25519}; mod system; @@ -140,7 +140,7 @@ mod module2 { trait Store for Module, I: Instance=DefaultInstance> as Module2 { pub Value config(value): T::Amount; pub Map config(map): map u64 => u64; - pub LinkedMap config(linked_map): linked_map u64 => u64; + pub LinkedMap config(linked_map): linked_map u64 => Vec; pub DoubleMap config(double_map): double_map u64, blake2_256(u64) => u64; } } @@ -288,13 +288,13 @@ fn new_test_ext() -> runtime_io::TestExternalities { module2: Some(module2::GenesisConfig { value: 4, map: vec![(0, 0)], - linked_map: vec![(0, 0)], + linked_map: vec![(0, vec![0])], double_map: vec![(0, 0, 0)], }), module2_Instance1: Some(module2::GenesisConfig { value: 4, map: vec![(0, 0)], - linked_map: vec![(0, 0)], + linked_map: vec![(0, vec![0])], double_map: vec![(0, 0, 0)], }), module2_Instance2: None, @@ -388,15 +388,23 @@ fn storage_with_instance_basic_operation() { assert_eq!(LinkedMap::exists(0), true); assert_eq!(LinkedMap::exists(key), false); - LinkedMap::insert(key, 1); - assert_eq!(LinkedMap::get(key), 1); - assert_eq!(LinkedMap::take(key), 1); - assert_eq!(LinkedMap::get(key), 0); - LinkedMap::mutate(key, |a| *a=2); - assert_eq!(LinkedMap::get(key), 2); + LinkedMap::insert(key, vec![1]); + assert_eq!(LinkedMap::enumerate().count(), 2); + assert_eq!(LinkedMap::get(key), vec![1]); + assert_eq!(LinkedMap::take(key), vec![1]); + assert_eq!(LinkedMap::enumerate().count(), 1); + assert_eq!(LinkedMap::get(key), vec![]); + LinkedMap::mutate(key, |a| *a=vec![2]); + assert_eq!(LinkedMap::enumerate().count(), 2); + assert_eq!(LinkedMap::get(key), vec![2]); LinkedMap::remove(key); + assert_eq!(LinkedMap::enumerate().count(), 1); assert_eq!(LinkedMap::exists(key), false); - assert_eq!(LinkedMap::get(key), 0); + assert_eq!(LinkedMap::get(key), vec![]); + assert_eq!(LinkedMap::exists(key), false); + assert_eq!(LinkedMap::enumerate().count(), 1); + LinkedMap::insert_ref(key, &vec![1]); + assert_eq!(LinkedMap::enumerate().count(), 2); let key1 = 1; let key2 = 1; @@ -454,7 +462,7 @@ const EXPECTED_METADATA: StorageMetadata = StorageMetadata { ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_256, key: DecodeDifferent::Encode("u64"), - value: DecodeDifferent::Encode("u64"), + value: DecodeDifferent::Encode("Vec"), is_linked: true, }, default: DecodeDifferent::Encode( diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index da97ace38edd4..9e7112a029c20 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -13,8 +13,7 @@ rand = "0.6" clap = { version = "~2.32", features = ["yaml"] } tiny-bip39 = "0.6.0" rustc-hex = "2.0" -substrate-bip39 = "0.2.2" -schnorrkel = "0.1.1" +substrate-bip39 = "0.3.1" hex = "0.3" hex-literal = "0.2" codec = { package = "parity-scale-codec", version = "1.0.0" } From ef4c1009e0c89b19a3b0989363e27dc313542938 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 13:36:36 +0200 Subject: [PATCH 64/80] Remove unneeded code for now. --- core/consensus/aura/src/lib.rs | 62 ---------------------------------- core/consensus/babe/src/lib.rs | 18 ---------- 2 files changed, 80 deletions(-) diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index a4f9f80b9b0af..0fa2b147bd52d 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -660,68 +660,6 @@ fn authorities(client: &C, at: &BlockId) -> Result, Consensus .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) } -/// Means of determining a list of authority keys, generally used to determine if we are an -/// authority by cross-referencing this list against the keys in the store and finding one that -/// appears in both. -/// -/// This is implemented directly on the `AppPair` key type. -pub trait AuthorityProvider: AppPair { - /// Provide a list of authority keys that is current as of a given block. - fn authorities_at(client: &C, at: &BlockId<::Type>) - -> Result::Public>, ConsensusError> - where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, - C::Api: AuraApi<::Type, ::Public>; - - /// Provide a list of authority keys that is current. By default this will just use the state of - /// the best block, but you might want it to use some other block's state instead if it's - /// more sophisticated. Grandpa, for example, will probably want to use the state of the last - /// finalised block. - fn authorities(client: &C) -> Result::Public>, ConsensusError> where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - C::Api: AuraApi<::Type, ::Public> - { - Self::authorities_at::(client, &BlockId::Number(client.info().best_number)) - } - - /// Provide the authority key, if any, that is controlled by this node as of the given block. - fn authority(client: &C, keystore: Arc) -> Option where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> - + HeaderBackend<::Type>, - C::Api: AuraApi<::Type, ::Public> - { - let owned = keystore.public_keys::<::Public>().ok()?; - let authorities = Self::authorities(client).ok()?; - let maybe_pub = owned.into_iter().find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) - } -} - -impl AuthorityProvider for aura_primitives::ed25519::AuthorityPair { - /// Provide a list of authority keys that is current as of a given block. - fn authorities_at(client: &C, at: &BlockId<::Type>) - -> Result::Public>, ConsensusError> - where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, - C::Api: AuraApi<::Type, ::Public>, - { - authorities::(client, at) - } -} - -impl AuthorityProvider for aura_primitives::sr25519::AuthorityPair { - /// Provide a list of authority keys that is current as of a given block. - fn authorities_at(client: &C, at: &BlockId<::Type>) - -> Result::Public>, ConsensusError> - where - C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, - C::Api: AuraApi<::Type, ::Public>, - { - authorities::(client, at) - } -} - /// The Aura import queue type. pub type AuraImportQueue = BasicQueue; diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index a19ae4b798f0c..6e048f8be2081 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -1191,24 +1191,6 @@ pub fn import_queue, I, RA, PRA>( Ok((queue, timestamp_core, block_import, pruning_task)) } -/// Type of source for block sealing. Different consensus algorithms have different sealing -/// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. -pub trait SealingSource { - /// Human-readable description of this general class. - /// - /// e.g. `"ProgPoW"`, `"S/R 25519 Key"`. - const SEALER_TYPE: &'static str; - /// Human-readable description of this specific instance. - /// - /// e.g. `"OpenCL GPU Radeon 8970 @ slot 1"`, `"5Gav1mbbo348grBREHTYgevvf4Gfe5GFE4"`. - fn format(&self) -> String; -} - -impl SealingSource for T { - const SEALER_TYPE: &'static str = "Key"; - fn format(&self) -> String { use primitives::crypto::Ss58Codec; self.to_ss58check() } -} - /// BABE test helpers. Utility methods for manually authoring blocks. #[cfg(feature = "test-helpers")] pub mod test_helpers { From 9806232ed51b485f9d5e37c126aee19fc8900491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 10:34:58 +0200 Subject: [PATCH 65/80] Some `session` testing --- Cargo.lock | 2 ++ core/sr-primitives/Cargo.toml | 2 ++ core/sr-primitives/src/testing.rs | 45 ++++++++++++++++++++++++++ core/sr-primitives/src/traits.rs | 12 +++---- srml/session/Cargo.toml | 1 + srml/session/src/historical.rs | 2 +- srml/session/src/lib.rs | 54 +++++++++++++++++++------------ srml/session/src/mock.rs | 21 +++++++++--- 8 files changed, 108 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce037ef45c747..3a7ddfe87787a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3652,6 +3652,7 @@ dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", @@ -4000,6 +4001,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "substrate-application-crypto 2.0.0", "substrate-primitives 2.0.0", "substrate-trie 2.0.0", ] diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 20f2892a6c02e..d3510e6baa834 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -15,6 +15,7 @@ rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4", optional = true } paste = { version = "0.1"} +rand = { version = "0.7.0", optional = true } [dev-dependencies] serde_json = "1.0" @@ -31,4 +32,5 @@ std = [ "codec/std", "primitives/std", "app-crypto/std", + "rand", ] diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 00af0c8eef987..403c662f8fdbb 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -46,6 +46,51 @@ impl CryptoType for UintAuthorityId { type Pair = Dummy; } +impl AsRef<[u8]> for UintAuthorityId { + fn as_ref(&self) -> &[u8] { + unsafe { + std::slice::from_raw_parts(&self.0 as *const u64 as *const _, std::mem::size_of::()) + } + } +} + +impl app_crypto::RuntimeAppPublic for UintAuthorityId { + type Signature = u64; + + #[cfg(feature = "std")] + fn generate_pair(_: Option<&str>) -> Self { + use rand::RngCore; + UintAuthorityId(rand::thread_rng().next_u64()) + } + + #[cfg(not(feature = "std"))] + fn generate_pair(_: Option<&str>) -> Self { + unimplemented!("`generate_pair` not implemented for `UIntAuthorityId` on `no_std`.") + } + + fn sign>(&self, msg: &M) -> Option { + let mut signature = [0u8; 8]; + msg.as_ref().iter() + .chain(rstd::iter::repeat(&42u8)) + .take(8) + .enumerate() + .for_each(|(i, v)| { signature[i] = *v; }); + + Some(u64::from_le_bytes(signature)) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + let mut msg_signature = [0u8; 8]; + msg.as_ref().iter() + .chain(rstd::iter::repeat(&42)) + .take(8) + .enumerate() + .for_each(|(i, v)| { msg_signature[i] = *v; }); + + u64::from_le_bytes(msg_signature) == *signature + } +} + impl OpaqueKeys for UintAuthorityId { type KeyTypeIds = std::iter::Cloned>; diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 77f6b3fc584a7..c93e034a94322 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -1260,12 +1260,12 @@ macro_rules! impl_opaque_keys { /// /// Returns the concatenated SCALE encoded public keys. pub fn generate(seed: Option<&str>) -> $crate::rstd::vec::Vec { - let mut keys = $crate::rstd::vec::Vec::new(); - $({ - let key = <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed); - $crate::codec::Encode::encode_to(&key, &mut keys); - })* - keys + let keys = Self{ + $( + $field: <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed), + )* + }; + $crate::codec::Encode::encode(&keys) } } diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml index 66d47f4c3585f..d084ab4261b3c 100644 --- a/srml/session/Cargo.toml +++ b/srml/session/Cargo.toml @@ -18,6 +18,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = [dev-dependencies] primitives = { package = "substrate-primitives", path = "../../core/primitives" } +app-crypto = { package = "substrate-application-crypto", path = "../../core/application-crypto" } lazy_static = "1.0" [features] diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index d92a5fdad25de..815d782cf902d 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -326,7 +326,7 @@ mod tests { let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; let (storage, _child_storage) = crate::GenesisConfig:: { keys: NEXT_VALIDATORS.with(|l| - l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i))).collect() + l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i).into())).collect() ), }.build_storage().unwrap(); t.extend(storage); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 2c65a5d1eef67..3aded46ea0223 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -579,7 +579,7 @@ mod tests { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig:: { keys: NEXT_VALIDATORS.with(|l| - l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i))).collect() + l.borrow().iter().cloned().map(|i| (i, UintAuthorityId(i).into())).collect() ), }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); runtime_io::TestExternalities::new_with_children(t) @@ -602,8 +602,8 @@ mod tests { #[test] fn put_get_keys() { with_externalities(&mut new_test_ext(), || { - Session::put_keys(&10, &UintAuthorityId(10)); - assert_eq!(Session::load_keys(&10), Some(UintAuthorityId(10))); + Session::put_keys(&10, &UintAuthorityId(10).into()); + assert_eq!(Session::load_keys(&10), Some(UintAuthorityId(10).into())); }) } @@ -612,7 +612,7 @@ mod tests { let mut ext = new_test_ext(); with_externalities(&mut ext, || { assert_eq!(Session::validators(), vec![1, 2, 3]); - assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1))); + assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1).into())); let id = DUMMY; assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); @@ -632,8 +632,8 @@ mod tests { force_new_session(); initialize_block(1); assert_eq!(Session::queued_keys(), vec![ - (1, UintAuthorityId(1)), - (2, UintAuthorityId(2)), + (1, UintAuthorityId(1).into()), + (2, UintAuthorityId(2).into()), ]); assert_eq!(Session::validators(), vec![1, 2, 3]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); @@ -641,20 +641,20 @@ mod tests { force_new_session(); initialize_block(2); assert_eq!(Session::queued_keys(), vec![ - (1, UintAuthorityId(1)), - (2, UintAuthorityId(2)), + (1, UintAuthorityId(1).into()), + (2, UintAuthorityId(2).into()), ]); assert_eq!(Session::validators(), vec![1, 2]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); set_next_validators(vec![1, 2, 4]); - assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(4), vec![])); + assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(4).into(), vec![])); force_new_session(); initialize_block(3); assert_eq!(Session::queued_keys(), vec![ - (1, UintAuthorityId(1)), - (2, UintAuthorityId(2)), - (4, UintAuthorityId(4)), + (1, UintAuthorityId(1).into()), + (2, UintAuthorityId(2).into()), + (4, UintAuthorityId(4).into()), ]); assert_eq!(Session::validators(), vec![1, 2]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2)]); @@ -662,9 +662,9 @@ mod tests { force_new_session(); initialize_block(4); assert_eq!(Session::queued_keys(), vec![ - (1, UintAuthorityId(1)), - (2, UintAuthorityId(2)), - (4, UintAuthorityId(4)), + (1, UintAuthorityId(1).into()), + (2, UintAuthorityId(2).into()), + (4, UintAuthorityId(4).into()), ]); assert_eq!(Session::validators(), vec![1, 2, 4]); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(4)]); @@ -707,7 +707,7 @@ mod tests { // Block 3: Set new key for validator 2; no visible change. initialize_block(3); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5), vec![])); + assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); // Block 4: Session rollover; no visible change. @@ -729,11 +729,11 @@ mod tests { with_externalities(&mut new_test_ext(), || { System::set_block_number(1); Session::on_initialize(1); - assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1), vec![]).is_err()); - assert!(Session::set_keys(Origin::signed(1), UintAuthorityId(10), vec![]).is_ok()); + assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]).is_err()); + assert!(Session::set_keys(Origin::signed(1), UintAuthorityId(10).into(), vec![]).is_ok()); // is fine now that 1 has migrated off. - assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1), vec![]).is_ok()); + assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]).is_ok()); }); } @@ -763,7 +763,7 @@ mod tests { initialize_block(5); assert!(!session_changed()); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5), vec![])); + assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); force_new_session(); initialize_block(6); assert!(!session_changed()); @@ -802,4 +802,18 @@ mod tests { assert!(P::should_end_session(13)); } + + #[test] + fn session_keys_generate_output_works_as_set_keys_input() { + with_externalities(&mut new_test_ext(), || { + let new_keys = mock::MockSessionKeys::generate(None); + assert_ok!( + Session::set_keys( + Origin::signed(2), + ::Keys::decode(&mut &new_keys[..]).expect("Decode keys"), + vec![], + ) + ); + }); + } } diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 5e284902196be..66bf93032d29f 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -21,11 +21,23 @@ use std::cell::RefCell; use srml_support::{impl_outer_origin, parameter_types}; use primitives::{crypto::key_types::DUMMY, H256}; use sr_primitives::{ - Perbill, - traits::{BlakeTwo256, IdentityLookup, ConvertInto}, + Perbill, impl_opaque_keys, traits::{BlakeTwo256, IdentityLookup, ConvertInto}, testing::{Header, UintAuthorityId} }; +impl_opaque_keys! { + pub struct MockSessionKeys { + #[id(DUMMY)] + pub dummy: UintAuthorityId, + } +} + +impl From for MockSessionKeys { + fn from(dummy: UintAuthorityId) -> Self { + Self { dummy } + } +} + impl_outer_origin! { pub enum Origin for Test {} } @@ -120,6 +132,7 @@ parameter_types! { pub const MinimumPeriod: u64 = 5; pub const AvailableBlockRatio: Perbill = Perbill::one(); } + impl system::Trait for Test { type Origin = Origin; type Index = u64; @@ -137,13 +150,13 @@ impl system::Trait for Test { type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } + impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); type MinimumPeriod = MinimumPeriod; } - impl Trait for Test { type ShouldEndSession = TestShouldEndSession; #[cfg(feature = "historical")] @@ -153,7 +166,7 @@ impl Trait for Test { type SessionHandler = TestSessionHandler; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; - type Keys = UintAuthorityId; + type Keys = MockSessionKeys; type Event = (); type SelectInitialValidators = (); } From 315caea4b621edb06b32dbc2700cb5b78526b949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 13:57:11 +0200 Subject: [PATCH 66/80] Support querying the public keys --- core/application-crypto/src/ed25519.rs | 28 ++++++------ core/application-crypto/src/lib.rs | 6 ++- core/application-crypto/src/sr25519.rs | 26 +++++------ core/application-crypto/src/traits.rs | 8 +++- core/executor/runtime-test/src/lib.rs | 5 +- core/executor/src/wasm_executor.rs | 40 +++++++++++++++- core/keystore/src/lib.rs | 16 +++++-- core/primitives/src/ed25519.rs | 14 ++++++ core/primitives/src/sr25519.rs | 14 ++++++ core/primitives/src/testing.rs | 52 ++++++++++++--------- core/primitives/src/traits.rs | 16 ++++++- core/sr-io/src/lib.rs | 28 +++++++----- core/sr-io/with_std.rs | 50 ++++++++++++-------- core/sr-io/without_std.rs | 63 ++++++++++++++++++-------- core/sr-primitives/src/lib.rs | 14 ++++-- core/sr-primitives/src/testing.rs | 4 ++ core/sr-primitives/src/traits.rs | 4 +- core/test-runtime/src/lib.rs | 56 +++++++++++++++-------- srml/im-online/src/lib.rs | 9 ++-- 19 files changed, 311 insertions(+), 142 deletions(-) diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index 8461366f242ae..5cffe3c1c8005 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -33,43 +33,43 @@ pub use app::Pair as AppPair; impl RuntimePublic for Public { type Signature = Signature; + fn all(key_type: KeyTypeId) -> crate::Vec { + rio::ed25519_public_keys(key_type) + } + fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self { - Self::from_raw(rio::ed25519_generate(key_type, seed)) + rio::ed25519_generate(key_type, seed) } fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { - rio::ed25519_sign(key_type, self, msg).map(Signature::from_raw) + rio::ed25519_sign(key_type, self, msg) } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - rio::ed25519_verify(&signature.0, msg.as_ref(), self) + rio::ed25519_verify(&signature, msg.as_ref(), self) } } #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{testing::KeyStore, crypto::Pair}; + use primitives::{testing::KeyStore, crypto::Pair, traits::KeyStore as _}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, - runtime::{TestAPI, app_crypto::ed25519::AppPair}, + runtime::{TestAPI, app_crypto::ed25519::{AppPair, AppPublic}}, }; #[test] fn ed25519_works_in_runtime() { let keystore = KeyStore::new(); let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); - let signature = test_client.runtime_api() + let (signature, public) = test_client.runtime_api() .test_ed25519_crypto(&BlockId::Number(0)) .expect("Tests `ed25519` crypto."); - let key_pair: AppPair = keystore.read() - .ed25519_pairs(crate::key_types::ED25519) - .get(0) - .expect("There should be at least one `ed25519` key in the keystore.") - .clone() - .into(); + let key_pair = keystore.read().ed25519_key_pair(crate::key_types::ED25519, &public.as_ref()) + .expect("There should be at a `ed25519` key in the keystore for the given public key."); - assert!(AppPair::verify(&signature, "ed25519", key_pair.public())); + assert!(AppPair::verify(&signature, "ed25519", AppPublic::from(key_pair.public()))); } -} +} \ No newline at end of file diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index 6e6be9dd89bb9..af56ccac72732 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -33,7 +33,7 @@ pub use codec; #[cfg(feature = "std")] pub use serde; #[doc(hidden)] -pub use rstd::ops::Deref; +pub use rstd::{ops::Deref, vec::Vec}; pub mod ed25519; pub mod sr25519; @@ -220,6 +220,10 @@ macro_rules! app_crypto { impl $crate::RuntimeAppPublic for Public where $public: $crate::RuntimePublic { type Signature = Signature; + fn all() -> $crate::Vec { + <$public as $crate::RuntimePublic>::all($key_type).into_iter().map(Self).collect() + } + fn generate_pair(seed: Option<&str>) -> Self { Self(<$public as $crate::RuntimePublic>::generate_pair($key_type, seed)) } diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index f57d29cf2d6a2..0e3c0c5384dde 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -33,43 +33,43 @@ pub use app::Pair as AppPair; impl RuntimePublic for Public { type Signature = Signature; + fn all(key_type: KeyTypeId) -> crate::Vec { + rio::sr25519_public_keys(key_type) + } + fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self { - Self::from_raw(rio::sr25519_generate(key_type, seed)) + rio::sr25519_generate(key_type, seed) } fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { - rio::sr25519_sign(key_type, self, msg).map(Signature::from_raw) + rio::sr25519_sign(key_type, self, msg) } fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - rio::sr25519_verify(&signature.0, msg.as_ref(), self) + rio::sr25519_verify(&signature, msg.as_ref(), self) } } #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{testing::KeyStore, crypto::Pair}; + use primitives::{testing::KeyStore, crypto::Pair, traits::KeyStore as _}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, - runtime::{TestAPI, app_crypto::sr25519::AppPair}, + runtime::{TestAPI, app_crypto::sr25519::{AppPair, AppPublic}}, }; #[test] fn sr25519_works_in_runtime() { let keystore = KeyStore::new(); let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); - let signature = test_client.runtime_api() + let (signature, public) = test_client.runtime_api() .test_sr25519_crypto(&BlockId::Number(0)) .expect("Tests `sr25519` crypto."); - let key_pair: AppPair = keystore.read() - .sr25519_pairs(crate::key_types::SR25519) - .get(0) - .expect("There should be at least one `sr25519` key in the keystore.") - .clone() - .into(); + let key_pair = keystore.read().sr25519_key_pair(crate::key_types::SR25519, public.as_ref()) + .expect("There should be at a `sr25519` key in the keystore for the given public key."); - assert!(AppPair::verify(&signature, "sr25519", key_pair.public())); + assert!(AppPair::verify(&signature, "sr25519", AppPublic::from(key_pair.public()))); } } \ No newline at end of file diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs index 4da81f0c58a23..d7f1eafe35407 100644 --- a/core/application-crypto/src/traits.rs +++ b/core/application-crypto/src/traits.rs @@ -74,6 +74,9 @@ pub trait RuntimePublic: Sized { /// The signature that will be generated when signing with the corresponding private key. type Signature; + /// Returns all public keys for the given key type in the keystore. + fn all(key_type: KeyTypeId) -> crate::Vec; + /// Generate a public/private pair for the given key type and store it in the keystore. /// /// Returns the generated public key. @@ -91,11 +94,14 @@ pub trait RuntimePublic: Sized { fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool; } -/// A runtime interface for a application's public key. +/// A runtime interface for an application's public key. pub trait RuntimeAppPublic: Sized { /// The signature that will be generated when signing with the corresponding private key. type Signature; + /// Returns all public keys for this application in the keystore. + fn all() -> crate::Vec; + /// Generate a public/private pair and store it in the keystore. /// /// Returns the generated public key. diff --git a/core/executor/runtime-test/src/lib.rs b/core/executor/runtime-test/src/lib.rs index 4c68d449f215b..49612c271e6d9 100644 --- a/core/executor/runtime-test/src/lib.rs +++ b/core/executor/runtime-test/src/lib.rs @@ -11,6 +11,7 @@ use runtime_io::{ set_storage, storage, clear_prefix, print, blake2_128, blake2_256, twox_128, twox_256, ed25519_verify, sr25519_verify, enumerated_trie_root }; +use primitives::{ed25519, sr25519}; macro_rules! impl_stubs { ( $( $new_name:ident => $invoke:expr, )* ) => { @@ -80,7 +81,7 @@ impl_stubs!( sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - [ed25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec() + [ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) as u8].to_vec() }, test_sr25519_verify => |input: &[u8]| { let mut pubkey = [0; 32]; @@ -90,7 +91,7 @@ impl_stubs!( sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - [sr25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec() + [sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) as u8].to_vec() }, test_enumerated_trie_root => |_| { enumerated_trie_root::( diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index e4bfda6b08bfe..a4544029d20b2 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -640,6 +640,24 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_keccak_256")?; Ok(()) }, + ext_ed25519_public_keys(id_data: *const u8, result_len: *mut u32) -> *mut u8 => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_ed25519_public_keys")?; + let key_type = KeyTypeId(id); + + let keys = runtime_io::ed25519_public_keys(key_type).encode(); + + let len = keys.len() as u32; + let offset = this.heap.allocate(len)? as u32; + + this.memory.set(offset, keys.as_ref()) + .map_err(|_| "Invalid attempt to set memory in ext_ed25519_public_keys")?; + this.memory.write_primitive(result_len, len) + .map_err(|_| "Invalid attempt to write result_len in ext_ed25519_public_keys")?; + + Ok(offset) + }, ext_ed25519_verify( msg_data: *const u8, msg_len: u32, @@ -706,7 +724,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let msg = this.memory.get(msg_data, msg_len as usize) .map_err(|_| "Invalid attempt to get message in ext_ed25519_sign")?; - let signature = runtime_io::ed25519_sign(key_type, &pubkey, &msg); + let signature = runtime_io::ed25519_sign(key_type, &ed25519::Public(pubkey), &msg); match signature { Some(signature) => { @@ -718,6 +736,24 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, None => Ok(1), } }, + ext_sr25519_public_keys(id_data: *const u8, result_len: *mut u32) -> *mut u8 => { + let mut id = [0u8; 4]; + this.memory.get_into(id_data, &mut id[..]) + .map_err(|_| "Invalid attempt to get id in ext_sr25519_public_keys")?; + let key_type = KeyTypeId(id); + + let keys = runtime_io::sr25519_public_keys(key_type).encode(); + + let len = keys.len() as u32; + let offset = this.heap.allocate(len)? as u32; + + this.memory.set(offset, keys.as_ref()) + .map_err(|_| "Invalid attempt to set memory in ext_sr25519_public_keys")?; + this.memory.write_primitive(result_len, len) + .map_err(|_| "Invalid attempt to write result_len in ext_sr25519_public_keys")?; + + Ok(offset) + }, ext_sr25519_verify( msg_data: *const u8, msg_len: u32, @@ -784,7 +820,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let msg = this.memory.get(msg_data, msg_len as usize) .map_err(|_| "Invalid attempt to get message in ext_sr25519_sign")?; - let signature = runtime_io::sr25519_sign(key_type, &pubkey, &msg); + let signature = runtime_io::sr25519_sign(key_type, &sr25519::Public(pubkey), &msg); match signature { Some(signature) => { diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index c66e245113e2c..f37c8ca898a52 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -226,34 +226,42 @@ impl Store { } impl KeyStore for Store { + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys_by_type::(key_type).unwrap_or_default() + } + fn sr25519_generate_new( &mut self, id: KeyTypeId, seed: Option<&str>, - ) -> std::result::Result<[u8; 32], String> { + ) -> std::result::Result { let pair = match seed { Some(seed) => self.generate_from_seed_by_type::(seed, id), None => self.generate_by_type::(id), }.map_err(|e| e.to_string())?; - Ok(pair.public().into()) + Ok(pair.public()) } fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { self.key_pair_by_type::(pub_key, id).ok() } + fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys_by_type::(key_type).unwrap_or_default() + } + fn ed25519_generate_new( &mut self, id: KeyTypeId, seed: Option<&str>, - ) -> std::result::Result<[u8; 32], String> { + ) -> std::result::Result { let pair = match seed { Some(seed) => self.generate_from_seed_by_type::(seed, id), None => self.generate_by_type::(id), }.map_err(|e| e.to_string())?; - Ok(pair.public().into()) + Ok(pair.public()) } fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 5e9c3eb54a05d..af14260a3c524 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -165,6 +165,20 @@ impl std::hash::Hash for Public { #[derive(Encode, Decode)] pub struct Signature(pub [u8; 64]); +impl rstd::convert::TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 64 { + let mut inner = [0u8; 64]; + inner.copy_from_slice(data); + Ok(Signature(inner)) + } else { + Err(()) + } + } +} + impl Clone for Signature { fn clone(&self) -> Self { let mut r = [0u8; 64]; diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index a6ed4d72ceb58..b8a0313f266cb 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -166,6 +166,20 @@ impl std::hash::Hash for Public { #[derive(Encode, Decode)] pub struct Signature(pub [u8; 64]); +impl rstd::convert::TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 64 { + let mut inner = [0u8; 64]; + inner.copy_from_slice(data); + Ok(Signature(inner)) + } else { + Err(()) + } + } +} + impl Clone for Signature { fn clone(&self) -> Self { let mut r = [0u8; 64]; diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index c852ec5f26d52..b6610db64df49 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -33,43 +33,36 @@ impl KeyStore { pub fn new() -> std::sync::Arc> { std::sync::Arc::new(parking_lot::RwLock::new(Self::default())) } +} - /// Returns all key pairs for a given key type as `sr25519` pairs. - pub fn sr25519_pairs(&self, id: KeyTypeId) -> Vec { +#[cfg(feature = "std")] +impl crate::traits::KeyStore for KeyStore { + fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { self.keys.get(&id) .map(|keys| keys.values() .map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid")) + .map(|p| p.public()) .collect() ) .unwrap_or_default() } - /// Returns all key pairs for a given key type as `ed25519` pairs. - pub fn ed25519_pairs(&self, id: KeyTypeId) -> Vec { - self.keys.get(&id) - .map(|keys| - keys.values() - .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) - .collect() - ) - .unwrap_or_default() - } -} - -#[cfg(feature = "std")] -impl crate::traits::KeyStore for KeyStore { - fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String> { + fn sr25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result { match seed { Some(seed) => { let pair = sr25519::Pair::from_string(seed, None).expect("Generates an `sr25519` pair."); self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); - Ok(pair.public().0) + Ok(pair.public()) }, None => { let (pair, _) = sr25519::Pair::generate(); self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); - Ok(pair.public().0) + Ok(pair.public()) } } } @@ -82,17 +75,32 @@ impl crate::traits::KeyStore for KeyStore { ) } - fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String> { + fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { + self.keys.get(&id) + .map(|keys| + keys.values() + .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) + .map(|p| p.public()) + .collect() + ) + .unwrap_or_default() + } + + fn ed25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result { match seed { Some(seed) => { let pair = ed25519::Pair::from_string(seed, None).expect("Generates an `ed25519` pair."); self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); - Ok(pair.public().0) + Ok(pair.public()) }, None => { let (pair, _) = ed25519::Pair::generate(); self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec()); - Ok(pair.public().0) + Ok(pair.public()) } } } diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index ff8d68e6494f6..03299aca43484 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -22,21 +22,33 @@ use crate::{crypto::KeyTypeId, ed25519, sr25519}; /// Something that generates, stores and provides access to keys. #[cfg(feature = "std")] pub trait KeyStore: Send + Sync { + /// Returns all sr25519 public keys for the given key type. + fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec; /// Generate a new sr25519 key pair for the given key type and an optional seed. /// /// If the given seed is `Some(_)`, the key pair will only be stored in memory. /// /// Returns the public key of the generated key pair. - fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String>; + fn sr25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result; /// Returns the sr25519 key pair for the given key type and public key combination. fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option; + /// Returns all ed25519 public keys for the given key type. + fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec; /// Generate a new ed25519 key pair for the given key type and an optional seed. /// /// If the given seed is `Some(_)`, the key pair will only be stored in memory. /// /// Returns the public key of the generated key pair. - fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String>; + fn ed25519_generate_new( + &mut self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result; /// Returns the ed25519 key pair for the given key type and public key combination. fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option; diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 2d69696bc4d9a..8371bafc07dd9 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -34,11 +34,11 @@ pub use codec; pub use primitives::Blake2Hasher; use primitives::{ - crypto::KeyTypeId, + crypto::KeyTypeId, ed25519, sr25519, offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, CryptoKind, CryptoKey, StorageKind, OpaqueNetworkState, - } + }, }; /// Error verifying ECDSA signature @@ -200,41 +200,45 @@ export_api! { export_api! { pub(crate) trait CryptoApi { + /// Returns all ed25519 public keys for the given key id from the keystore. + fn ed25519_public_keys(id: KeyTypeId) -> Vec; /// Generate an ed22519 key for the given key type and store it in the keystore. /// /// Returns the raw public key. - fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32]; + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public; /// Sign the given `msg` with the ed25519 key that corresponds to the given public key and /// key type in the keystore. /// /// Returns the raw signature. - fn ed25519_sign, M: AsRef<[u8]>>( + fn ed25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &ed25519::Public, msg: &M, - ) -> Option<[u8; 64]>; + ) -> Option; /// Verify an ed25519 signature. /// /// Returns `true` when the verification in successful. - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool; + fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool; + /// Returns all sr25519 public keys for the given key id from the keystore. + fn sr25519_public_keys(id: KeyTypeId) -> Vec; /// Generate an sr22519 key for the given key type and store it in the keystore. /// /// Returns the raw public key. - fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32]; + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public; /// Sign the given `msg` with the sr25519 key that corresponds to the given public key and /// key type in the keystore. /// /// Returns the raw signature. - fn sr25519_sign, M: AsRef<[u8]>>( + fn sr25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &sr25519::Public, msg: &M, - ) -> Option<[u8; 64]>; + ) -> Option; /// Verify an sr25519 signature. /// /// Returns `true` when the verification in successful. - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool; + fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool; /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 836888c1e7629..f2f7c45f33b8d 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -15,16 +15,12 @@ // along with Substrate. If not, see . use primitives::{ - blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher, - sr25519, Pair + blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher, sr25519, Pair, }; // Switch to this after PoC-3 // pub use primitives::BlakeHasher; pub use substrate_state_machine::{ - Externalities, - BasicExternalities, - TestExternalities, - ChildStorageKey + Externalities, BasicExternalities, TestExternalities, ChildStorageKey, }; use environmental::environmental; @@ -207,7 +203,16 @@ impl OtherApi for () { } impl CryptoApi for () { - fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { + fn ed25519_public_keys(id: KeyTypeId) -> Vec { + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .write() + .ed25519_public_keys(id) + }).expect("`ed25519_public_keys` cannot be called outside of an Externalities-provided environment.") + } + + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public { ext::with(|ext| { ext.keystore() .expect("No `keystore` associated for the current context!") @@ -217,11 +222,11 @@ impl CryptoApi for () { }).expect("`ed25519_generate` cannot be called outside of an Externalities-provided environment.") } - fn ed25519_sign, M: AsRef<[u8]>>( + fn ed25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &ed25519::Public, msg: &M, - ) -> Option<[u8; 64]> { + ) -> Option { let pub_key = ed25519::Public::try_from(pubkey.as_ref()).ok()?; ext::with(|ext| { @@ -233,11 +238,20 @@ impl CryptoApi for () { }).expect("`ed25519_sign` cannot be called outside of an Externalities-provided environment.") } - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { - ed25519::Pair::verify_weak(sig, msg, pubkey) + fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool { + ed25519::Pair::verify(sig, msg, pubkey) + } + + fn sr25519_public_keys(id: KeyTypeId) -> Vec { + ext::with(|ext| { + ext.keystore() + .expect("No `keystore` associated for the current context!") + .write() + .sr25519_public_keys(id) + }).expect("`sr25519_public_keys` cannot be called outside of an Externalities-provided environment.") } - fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public { ext::with(|ext| { ext.keystore() .expect("No `keystore` associated for the current context!") @@ -247,11 +261,11 @@ impl CryptoApi for () { }).expect("`sr25519_generate` cannot be called outside of an Externalities-provided environment.") } - fn sr25519_sign, M: AsRef<[u8]>>( + fn sr25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &sr25519::Public, msg: &M, - ) -> Option<[u8; 64]> { + ) -> Option { let pub_key = sr25519::Public::try_from(pubkey.as_ref()).ok()?; ext::with(|ext| { @@ -263,8 +277,8 @@ impl CryptoApi for () { }).expect("`sr25519_sign` cannot be called outside of an Externalities-provided environment.") } - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { - sr25519::Pair::verify_weak(sig, msg, pubkey) + fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool { + sr25519::Pair::verify(sig, msg, pubkey) } fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError> { diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 9a0a5d02c1e95..c6779d9bb7974 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -21,6 +21,7 @@ pub use rstd::{mem, slice}; use core::{intrinsics, panic::PanicInfo}; use rstd::{vec::Vec, cell::Cell, convert::TryInto}; use primitives::{offchain, Blake2Hasher}; +use codec::Decode; #[cfg(not(feature = "no_panic_handler"))] #[panic_handler] @@ -353,6 +354,9 @@ pub mod ext { /// Keccak256 hash fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8); + /// Returns all `ed25519` public keys for the given key type from the keystore. + fn ext_ed25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8; + /// Note: `ext_ed25519_verify` returns `0` if the signature is correct, nonzero otherwise. fn ext_ed25519_verify( msg_data: *const u8, @@ -380,6 +384,9 @@ pub mod ext { out: *mut u8, ) -> u32; + /// Returns all `sr25519` public keys for the given key type from the keystore. + fn ext_sr25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8; + /// Note: `ext_sr25519_verify` returns 0 if the signature is correct, nonzero otherwise. fn ext_sr25519_verify( msg_data: *const u8, @@ -912,25 +919,33 @@ impl HashingApi for () { } impl CryptoApi for () { - fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { + fn ed25519_public_keys(id: KeyTypeId) -> Vec { + let mut res_len = 0u32; + unsafe { + let res_ptr = ext_ed25519_public_keys.get()(id.0.as_ptr(), &mut res_len); + Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default() + } + } + + fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public { let mut res = [0u8; 32]; let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]); unsafe { ext_ed25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr()) }; - res + ed25519::Public(res) } - fn ed25519_sign, M: AsRef<[u8]>>( + fn ed25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &ed25519::Public, msg: &M, - ) -> Option<[u8; 64]> { + ) -> Option { let mut res = [0u8; 64]; let success = unsafe { ext_ed25519_sign.get()( id.0.as_ptr(), - pubkey.as_ref().as_ptr(), + pubkey.0.as_ptr(), msg.as_ref().as_ptr(), msg.as_ref().len() as u32, res.as_mut_ptr(), @@ -938,42 +953,50 @@ impl CryptoApi for () { }; if success { - Some(res) + Some(ed25519::Signature(res)) } else { None } } - fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { + fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool { unsafe { ext_ed25519_verify.get()( msg.as_ptr(), msg.len() as u32, - sig.as_ptr(), - pubkey.as_ref().as_ptr(), + sig.0.as_ptr(), + pubkey.0.as_ptr(), ) == 0 } } - fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> [u8; 32] { + fn sr25519_public_keys(id: KeyTypeId) -> Vec { + let mut res_len = 0u32; + unsafe { + let res_ptr = ext_sr25519_public_keys.get()(id.0.as_ptr(), &mut res_len); + Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default() + } + } + + fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public { let mut res = [0u8;32]; let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]); unsafe { ext_sr25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr()) }; - res + sr25519::Public(res) } - fn sr25519_sign, M: AsRef<[u8]>>( + fn sr25519_sign>( id: KeyTypeId, - pubkey: &P, + pubkey: &sr25519::Public, msg: &M, - ) -> Option<[u8; 64]> { + ) -> Option { let mut res = [0u8; 64]; let success = unsafe { ext_sr25519_sign.get()( id.0.as_ptr(), - pubkey.as_ref().as_ptr(), + pubkey.0.as_ptr(), msg.as_ref().as_ptr(), msg.as_ref().len() as u32, res.as_mut_ptr(), @@ -981,19 +1004,19 @@ impl CryptoApi for () { }; if success { - Some(res) + Some(sr25519::Signature(res)) } else { None } } - fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: &P) -> bool { + fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool { unsafe { ext_sr25519_verify.get()( msg.as_ptr(), msg.len() as u32, - sig.as_ptr(), - pubkey.as_ref().as_ptr(), + sig.0.as_ptr(), + pubkey.0.as_ptr(), ) == 0 } } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 0ec154dd9f5ac..8e41d4f13975d 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -37,7 +37,7 @@ pub use app_crypto; #[cfg(feature = "std")] pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; -use rstd::{prelude::*, ops, convert::TryInto}; +use rstd::{prelude::*, ops, convert::{TryInto, TryFrom}}; use primitives::{crypto, ed25519, sr25519, hash::{H256, H512}}; use codec::{Encode, Decode}; @@ -664,8 +664,16 @@ pub struct AnySignature(H512); impl Verify for AnySignature { type Signer = sr25519::Public; fn verify>(&self, mut msg: L, signer: &sr25519::Public) -> bool { - runtime_io::sr25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0) || - runtime_io::ed25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0) + let sr25519 = sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) + .map(|s| runtime_io::sr25519_verify(&s, msg.get(), &signer)) + .unwrap_or(false); + + let ed25519 = ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) + .and_then(|s| ed25519::Public::try_from(signer.0.as_ref()).map(|p| (s, p))) + .map(|(s, p)| runtime_io::ed25519_verify(&s, msg.get(), &p)) + .unwrap_or(false); + + sr25519 || ed25519 } } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 403c662f8fdbb..41f1278408a52 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -57,6 +57,10 @@ impl AsRef<[u8]> for UintAuthorityId { impl app_crypto::RuntimeAppPublic for UintAuthorityId { type Signature = u64; + fn all() -> Vec { + unimplemented!("`all()` not available for `UintAuthorityId`.") + } + #[cfg(feature = "std")] fn generate_pair(_: Option<&str>) -> Self { use rand::RngCore; diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index c93e034a94322..442aa9b0ac89a 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -59,14 +59,14 @@ pub trait Verify { impl Verify for primitives::ed25519::Signature { type Signer = primitives::ed25519::Public; fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - runtime_io::ed25519_verify(self.as_ref(), msg.get(), signer) + runtime_io::ed25519_verify(self, msg.get(), signer) } } impl Verify for primitives::sr25519::Signature { type Signer = primitives::sr25519::Public; fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - runtime_io::sr25519_verify(self.as_ref(), msg.get(), signer) + runtime_io::sr25519_verify(self, msg.get(), signer) } } diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 7c86176bfbb12..e2c7c278761fa 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -270,12 +270,12 @@ cfg_if! { fn without_initialize_block() -> bool; /// Test that `ed25519` crypto works in the runtime. /// - /// Returns the signature generated for the message `ed25519`. - fn test_ed25519_crypto() -> ed25519::AppSignature; + /// Returns the signature generated for the message `ed25519` and the public key. + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic); /// Test that `sr25519` crypto works in the runtime. /// /// Returns the signature generated for the message `sr25519`. - fn test_sr25519_crypto() -> sr25519::AppSignature; + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic); } } } else { @@ -311,12 +311,12 @@ cfg_if! { fn without_initialize_block() -> bool; /// Test that `ed25519` crypto works in the runtime. /// - /// Returns the signature generated for the message `ed25519`. - fn test_ed25519_crypto() -> ed25519::AppSignature; + /// Returns the signature generated for the message `ed25519` and the public key. + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic); /// Test that `sr25519` crypto works in the runtime. /// /// Returns the signature generated for the message `sr25519`. - fn test_sr25519_crypto() -> sr25519::AppSignature; + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic); } } } @@ -564,11 +564,11 @@ cfg_if! { system::take_block_number() } - fn test_ed25519_crypto() -> ed25519::AppSignature { + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { test_ed25519_crypto() } - fn test_sr25519_crypto() -> sr25519::AppSignature { + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { test_sr25519_crypto() } } @@ -768,11 +768,11 @@ cfg_if! { system::take_block_number() } - fn test_ed25519_crypto() -> ed25519::AppSignature { + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { test_ed25519_crypto() } - fn test_sr25519_crypto() -> sr25519::AppSignature { + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { test_sr25519_crypto() } } @@ -820,18 +820,34 @@ cfg_if! { } } -fn test_ed25519_crypto() -> ed25519::AppSignature { - let public = ed25519::AppPublic::generate_pair(None); - let signature = public.sign(&"ed25519").expect("Generates a valid `ed25519` signature."); - assert!(public.verify(&"ed25519", &signature)); - signature +fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { + let public0 = ed25519::AppPublic::generate_pair(None); + let public1 = ed25519::AppPublic::generate_pair(None); + let public2 = ed25519::AppPublic::generate_pair(None); + + let all = ed25519::AppPublic::all(); + assert!(all.contains(&public0)); + assert!(all.contains(&public1)); + assert!(all.contains(&public2)); + + let signature = public0.sign(&"ed25519").expect("Generates a valid `ed25519` signature."); + assert!(public0.verify(&"ed25519", &signature)); + (signature, public0) } -fn test_sr25519_crypto() -> sr25519::AppSignature { - let public = sr25519::AppPublic::generate_pair(None); - let signature = public.sign(&"sr25519").expect("Generates a valid `sr25519` signature."); - assert!(public.verify(&"sr25519", &signature)); - signature +fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { + let public0 = sr25519::AppPublic::generate_pair(None); + let public1 = sr25519::AppPublic::generate_pair(None); + let public2 = sr25519::AppPublic::generate_pair(None); + + let all = sr25519::AppPublic::all(); + assert!(all.contains(&public0)); + assert!(all.contains(&public1)); + assert!(all.contains(&public2)); + + let signature = public0.sign(&"sr25519").expect("Generates a valid `sr25519` signature."); + assert!(public0.verify(&"sr25519", &signature)); + (signature, public0) } #[cfg(test)] diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 2483425c0999e..23a78215e0ba0 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -84,6 +84,7 @@ use srml_support::{ StorageDoubleMap, print, }; use system::ensure_none; +use app_crypto::RuntimeAppPublic; mod app { pub use app_crypto::sr25519 as crypto; @@ -414,13 +415,9 @@ impl srml_support::unsigned::ValidateUnsigned for Module { // check signature (this is expensive so we do it last). let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| { - let sig: &app::crypto::Signature = signature.as_ref(); - sr_io::sr25519_verify( - sig.as_ref(), - encoded_heartbeat, - &authority_id - ) + authority_id.verify(&encoded_heartbeat, &signature) }); + if !signature_valid { return TransactionValidity::Invalid(ApplyError::BadSignature as i8); } From 01fc842ff858ca836ce1361ffbc057626f02caee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 16:30:49 +0200 Subject: [PATCH 67/80] Cleanup offchain --- core/application-crypto/src/lib.rs | 5 +- core/consensus/aura/src/lib.rs | 10 +- core/executor/src/wasm_executor.rs | 178 +----------------------- core/offchain/src/api.rs | 126 +---------------- core/offchain/src/lib.rs | 23 +-- core/offchain/src/testing.rs | 51 ------- core/primitives/src/crypto.rs | 75 ---------- core/primitives/src/ed25519.rs | 7 +- core/primitives/src/offchain.rs | 70 +--------- core/primitives/src/sr25519.rs | 5 +- core/service/src/lib.rs | 6 +- core/sr-io/src/lib.rs | 35 +---- core/sr-io/with_std.rs | 49 ------- core/sr-io/without_std.rs | 215 ----------------------------- core/sr-primitives/src/lib.rs | 2 +- core/sr-primitives/src/testing.rs | 3 +- core/state-machine/src/lib.rs | 49 ------- srml/im-online/src/lib.rs | 35 ++--- 18 files changed, 31 insertions(+), 913 deletions(-) diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index af56ccac72732..eb8a237f11052 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -25,7 +25,7 @@ pub use primitives::{self, crypto::{CryptoType, Public, Derive, IsWrappedBy, Wra #[doc(hidden)] #[cfg(feature = "std")] pub use primitives::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair}; -pub use primitives::{crypto::{KeyTypeId, key_types, Kind}}; +pub use primitives::{crypto::{KeyTypeId, key_types}}; #[doc(hidden)] pub use codec; @@ -68,7 +68,6 @@ macro_rules! app_crypto { } impl $crate::CryptoType for Pair { - const KIND: $crate::Kind = <$pair as $crate::CryptoType>::KIND; type Pair = Pair; } @@ -195,7 +194,6 @@ macro_rules! app_crypto { } impl $crate::CryptoType for Public { - const KIND: $crate::Kind = <$public as $crate::CryptoType>::KIND; #[cfg(feature="std")] type Pair = Pair; } @@ -259,7 +257,6 @@ macro_rules! app_crypto { } impl $crate::CryptoType for Signature { - const KIND: $crate::Kind = <$public as $crate::CryptoType>::KIND; #[cfg(feature="std")] type Pair = Pair; } diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 0fa2b147bd52d..726be46562d15 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -39,20 +39,14 @@ use consensus_common::import_queue::{ Verifier, BasicQueue, BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport, }; use client::{ - block_builder::api::BlockBuilder as BlockBuilderApi, - blockchain::{ProvideCache, HeaderBackend}, - runtime_api::ApiExt, - error::Result as CResult, - backend::AuxStore, - BlockOf + block_builder::api::BlockBuilder as BlockBuilderApi, BlockOf, + blockchain::ProvideCache, runtime_api::ApiExt, error::Result as CResult, backend::AuxStore, }; -use substrate_keystore::Store; use sr_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification}; use sr_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member}; use primitives::crypto::Pair; -use app_crypto::{AppPair, AppKey}; use inherents::{InherentDataProviders, InherentData}; use futures::{prelude::*, future}; diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index a4544029d20b2..2c69c8ba0588b 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -26,7 +26,7 @@ use wasmi::{ }; use state_machine::{Externalities, ChildStorageKey}; use crate::error::{Error, Result}; -use codec::{Encode, Decode}; +use codec::Encode; use primitives::{ blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair, crypto::KeyTypeId, offchain, hexdisplay::HexDisplay, sandbox as sandbox_primitives, H256, Blake2Hasher, @@ -885,182 +885,6 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, - ext_new_key( - crypto: u32, - key_type: u32, - written_out: *mut u32 - ) -> *mut u8 => { - let kind = offchain::CryptoKind::try_from(crypto) - .map_err(|_| "crypto kind OOB while ext_new_key: wasm")?; - let key_type = offchain::KeyTypeId::try_from(key_type) - .map_err(|_| "crypto kind OOB while ext_new_key: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.new_key(kind, key_type)) - .ok_or_else(|| "Calling unavailable API ext_new_key: wasm")?; - - let encoded = res.encode(); - let len = encoded.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &encoded) - .map_err(|_| "Invalid attempt to set memory in ext_new_key")?; - this.memory.write_primitive(written_out, len) - .map_err(|_| "Invalid attempt to write written_out in ext_new_key")?; - Ok(offset) - }, - ext_public_keys( - crypto: u32, - key_type: u32, - written_out: *mut u32 - ) -> *mut u8 => { - let kind = offchain::CryptoKind::try_from(crypto) - .map_err(|_| "crypto kind OOB while ext_public_keys: wasm")?; - let key_type = offchain::KeyTypeId::try_from(key_type) - .map_err(|_| "crypto kind OOB while ext_public_keys: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.public_keys(kind, key_type)) - .ok_or_else(|| "Calling unavailable API ext_public_keys: wasm")?; - - let encoded = res.encode(); - let len = encoded.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &encoded) - .map_err(|_| "Invalid attempt to set memory in ext_public_keys")?; - this.memory.write_primitive(written_out, len) - .map_err(|_| "Invalid attempt to write written_out in ext_public_keys")?; - Ok(offset) - }, - - ext_encrypt( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - msg_len: *mut u32 - ) -> *mut u8 => { - let key = this.memory.get(key, key_len as usize) - .ok() - .and_then(|x| offchain::CryptoKey::decode(&mut &*x).ok()) - .ok_or("Key OOB while ext_encrypt: wasm")?; - let message = this.memory.get(data, data_len as usize) - .map_err(|_| "OOB while ext_encrypt: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.encrypt(key, &*message)) - .ok_or_else(|| "Calling unavailable API ext_encrypt: wasm")?; - - let (offset,len) = match res { - Ok(encrypted) => { - let len = encrypted.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &encrypted) - .map_err(|_| "Invalid attempt to set memory in ext_encrypt")?; - (offset, len) - }, - Err(()) => (0, u32::max_value()), - }; - - this.memory.write_primitive(msg_len, len) - .map_err(|_| "Invalid attempt to write msg_len in ext_encrypt")?; - - Ok(offset) - }, - ext_decrypt( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - msg_len: *mut u32 - ) -> *mut u8 => { - let key = this.memory.get(key, key_len as usize) - .ok() - .and_then(|x| offchain::CryptoKey::decode(&mut &*x).ok()) - .ok_or("Key OOB while ext_decrypt: wasm")?; - let message = this.memory.get(data, data_len as usize) - .map_err(|_| "OOB while ext_decrypt: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.decrypt(key, &*message)) - .ok_or_else(|| "Calling unavailable API ext_decrypt: wasm")?; - - let (offset,len) = match res { - Ok(decrypted) => { - let len = decrypted.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &decrypted) - .map_err(|_| "Invalid attempt to set memory in ext_decrypt")?; - (offset, len) - }, - Err(()) => (0, u32::max_value()), - }; - - this.memory.write_primitive(msg_len, len) - .map_err(|_| "Invalid attempt to write msg_len in ext_decrypt")?; - - Ok(offset) - }, - ext_sign( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - sig_data_len: *mut u32 - ) -> *mut u8 => { - let key = this.memory.get(key, key_len as usize) - .ok() - .and_then(|x| offchain::CryptoKey::decode(&mut &*x).ok()) - .ok_or("Key OOB while ext_sign: wasm")?; - let message = this.memory.get(data, data_len as usize) - .map_err(|_| "OOB while ext_sign: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.sign(key, &*message)) - .ok_or_else(|| "Calling unavailable API ext_sign: wasm")?; - - let (offset,len) = match res { - Ok(signature) => { - let len = signature.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &signature) - .map_err(|_| "Invalid attempt to set memory in ext_sign")?; - (offset, len) - }, - Err(()) => (0, u32::max_value()), - }; - - this.memory.write_primitive(sig_data_len, len) - .map_err(|_| "Invalid attempt to write sig_data_len in ext_sign")?; - - Ok(offset) - }, - ext_verify( - key: *const u8, - key_len: u32, - msg: *const u8, - msg_len: u32, - signature: *const u8, - signature_len: u32 - ) -> u32 => { - let key = this.memory.get(key, key_len as usize) - .ok() - .and_then(|x| offchain::CryptoKey::decode(&mut &*x).ok()) - .ok_or("Key OOB while ext_verify: wasm")?; - let message = this.memory.get(msg, msg_len as usize) - .map_err(|_| "OOB while ext_verify: wasm")?; - let signature = this.memory.get(signature, signature_len as usize) - .map_err(|_| "OOB while ext_verify: wasm")?; - - let res = this.ext.offchain() - .map(|api| api.verify(key, &*message, &*signature)) - .ok_or_else(|| "Calling unavailable API ext_verify: wasm")?; - - match res { - Ok(true) => Ok(0), - Ok(false) => Ok(1), - Err(()) => Ok(u32::max_value()), - } - }, ext_timestamp() -> u64 => { let timestamp = this.ext.offchain() .map(|api| api.timestamp()) diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 45eb09a85fe70..8be66877b014e 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -28,12 +28,10 @@ use keystore::Store as Keystore; use log::{info, debug, warn, error}; use network::{PeerId, Multiaddr, NetworkStateInfo}; use codec::{Encode, Decode}; -use primitives::crypto::{self, Pair, Public}; use primitives::offchain::{ - CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, HttpRequestId, Timestamp, - HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, + Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, + OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use primitives::{ed25519, sr25519, traits::KeyStorePtr}; use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; @@ -42,56 +40,14 @@ enum ExtMessage { SubmitExtrinsic(Vec), } -enum KnownCryptoKey { - Ed25519(ed25519::Pair), - Sr25519(sr25519::Pair), -} - -impl KnownCryptoKey { - fn public(&self) -> Result, ()> { - match self { - KnownCryptoKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()), - KnownCryptoKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()), - } - } - - fn sign(&self, data: &[u8]) -> Result, ()> { - match self { - KnownCryptoKey::Ed25519(pair) => { - let sig = pair.sign(data); - let bytes: &[u8] = sig.as_ref(); - Ok(bytes.to_vec()) - } - KnownCryptoKey::Sr25519(pair) => { - let sig = pair.sign(data); - let bytes: &[u8] = sig.as_ref(); - Ok(bytes.to_vec()) - } - } - } - - fn verify(&self, msg: &[u8], signature: &[u8]) -> Result { - match self { - KnownCryptoKey::Ed25519(pair) => { - Ok(ed25519::Pair::verify_weak(signature, msg, pair.public())) - } - KnownCryptoKey::Sr25519(pair) => { - Ok(sr25519::Pair::verify_weak(signature, msg, pair.public())) - } - } - } -} - - /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, - keystore: Option, network_state: Arc, - at: BlockId, + _at: BlockId, } fn unavailable_yet(name: &str) -> R { @@ -100,52 +56,9 @@ fn unavailable_yet(name: &str) -> R { Default::default() } -fn log_error(err: keystore::Error) -> () { - warn!("Keystore error when accessing keys from offchain worker: {}", err); -} - const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; const STORAGE_PREFIX: &[u8] = b"storage"; -impl Api where Storage: OffchainStorage, Block: traits::Block { - fn check_allowed(&self, key_type: &KeyTypeId) -> Result<(), ()> { - let blacklist = vec![ - crypto::key_types::SR25519, - crypto::key_types::ED25519, - crypto::key_types::BABE, - crypto::key_types::GRANDPA, - crypto::key_types::ACCOUNT, - crypto::key_types::AURA, - ]; - - if blacklist.contains(key_type) { - Err(()) - } else { - Ok(()) - } - } - - fn keys( - &self, - kind: CryptoKind, - key_type: KeyTypeId, - ) -> Result, ()> { - self.check_allowed(&key_type)?; - unavailable_yet::<()>("keys"); - Err(()) - } - - fn get_key( - &self, - key: CryptoKey, - ) -> Result { - self.check_allowed(&key.key_type)?; - - unavailable_yet::<()>("get key"); - Err(()) - } -} - impl OffchainExt for Api where Storage: OffchainStorage, @@ -168,34 +81,6 @@ where Ok(OpaqueNetworkState::from(state)) } - fn new_key(&mut self, _crypto: CryptoKind, _key_type: KeyTypeId) -> Result { - unavailable_yet::<()>("new_key"); - Err(()) - } - - fn public_keys(&self, crypto: CryptoKind, key_type: KeyTypeId) -> Result, ()> { - self.keys(crypto, key_type) - } - - fn encrypt(&self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { - unavailable_yet::<()>("encrypt"); - Err(()) - } - - fn decrypt(&self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { - unavailable_yet::<()>("decrypt"); - Err(()) - - } - - fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { - self.get_key(key)?.sign(data) - } - - fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { - self.get_key(key)?.verify(msg, signature) - } - fn timestamp(&mut self) -> Timestamp { let now = SystemTime::now(); let epoch_duration = now.duration_since(SystemTime::UNIX_EPOCH); @@ -391,7 +276,6 @@ impl AsyncApi { pub fn new( transaction_pool: Arc>, db: S, - keystore: Option, at: BlockId, network_state: Arc, ) -> (Api, AsyncApi) { @@ -400,9 +284,8 @@ impl AsyncApi { let api = Api { sender, db, - keystore, network_state, - at, + _at: at, }; let async_api = AsyncApi { @@ -478,7 +361,6 @@ mod tests { AsyncApi::new( pool, db, - None, BlockId::Number(Zero::zero()), mock, ) diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index b1e3b4d77a425..431af24dc63bb 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -41,14 +41,10 @@ use std::{ use client::runtime_api::ApiExt; use futures::future::Future; -use keystore::Store as Keystore; use log::{debug, warn}; use network::NetworkStateInfo; -use primitives::{ExecutionContext, traits::KeyStorePtr}; -use sr_primitives::{ - generic::BlockId, - traits::{self, ProvideRuntimeApi}, -}; +use primitives::ExecutionContext; +use sr_primitives::{generic::BlockId, traits::{self, ProvideRuntimeApi}}; use transaction_pool::txpool::{Pool, ChainApi}; mod api; @@ -61,21 +57,15 @@ pub use offchain_primitives::OffchainWorkerApi; pub struct OffchainWorkers { client: Arc, db: Storage, - keystore: Option, _block: PhantomData, } -impl OffchainWorkers< - Client, - Storage, - Block, -> { +impl OffchainWorkers { /// Creates new `OffchainWorkers`. - pub fn new(client: Arc, db: Storage, keystore: Option) -> Self { + pub fn new(client: Arc, db: Storage) -> Self { Self { client, db, - keystore, _block: PhantomData, } } @@ -120,7 +110,6 @@ impl OffchainWorkers< let (api, runner) = api::AsyncApi::new( pool.clone(), self.db.clone(), - self.keystore.clone(), at.clone(), network_state.clone(), ); @@ -184,12 +173,12 @@ mod tests { let _ = env_logger::try_init(); let runtime = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone()))); + let pool = Arc::new(Pool::new(Default::default(), transaction_pool::ChainApi::new(client.clone()))); let db = client_db::offchain::LocalStorage::new_test(); let network_state = Arc::new(MockNetworkStateInfo()); // TODO Test keystore // when - let offchain = OffchainWorkers::new(client, db, None); + let offchain = OffchainWorkers::new(client, db); runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone())); // then diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index 69f4aeded0d1c..3b2a9a6e1b5b1 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -28,9 +28,7 @@ use primitives::offchain::{ HttpRequestId as RequestId, HttpRequestStatus as RequestStatus, Timestamp, - CryptoKind, KeyTypeId, - CryptoKey, StorageKind, OpaqueNetworkState, }; @@ -145,55 +143,6 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn new_key( - &mut self, - _crypto: CryptoKind, - _key_type: KeyTypeId - ) -> Result { - unimplemented!("not needed in tests so far") - } - - fn public_keys( - &self, - _crypto: CryptoKind, - _key_type: KeyTypeId, - ) -> Result, ()> { - unimplemented!("not needed in tests so far") - } - - fn encrypt( - &self, - _key: CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unimplemented!("not needed in tests so far") - } - - fn decrypt( - &self, - _key: CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unimplemented!("not needed in tests so far") - } - - fn sign( - &self, - _key: CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unimplemented!("not needed in tests so far") - } - - fn verify( - &self, - _key: CryptoKey, - _msg: &[u8], - _signature: &[u8], - ) -> Result { - unimplemented!("not needed in tests so far") - } - fn timestamp(&mut self) -> Timestamp { unimplemented!("not needed in tests so far") } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index a44ef389ed3ec..c6e3ac6e6d339 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -506,7 +506,6 @@ mod dummy { } impl CryptoType for Dummy { - const KIND: Kind = Kind::Dummy; type Pair = Dummy; } @@ -689,44 +688,6 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { fn to_raw_vec(&self) -> Vec; } -/// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] -#[repr(u32)] -pub enum Kind { - /// User-level crypto. We (core) can't handle it directly. - User = 0, - /// SR25519 crypto (Schnorrkel) - Sr25519 = 1, - /// ED25519 crypto (Edwards) - Ed25519 = 2, - - /// Dummy kind, just for testing. - #[cfg(feature = "std")] - Dummy = !0, -} - -#[cfg(feature = "std")] -impl TryFrom for Kind { - type Error = (); - - fn try_from(kind: u32) -> Result { - Ok(match kind { - e if e == Kind::User as usize as u32 => Kind::User, - e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, - e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, - e if e == Kind::Dummy as usize as u32 => Kind::Dummy, - _ => return Err(()), - }) - } -} - -impl From for u32 { - fn from(kind: Kind) -> Self { - kind as u32 - } -} - /// One type is wrapped by another. pub trait IsWrappedBy: From + Into { /// Get a reference to the inner from the outer. @@ -783,9 +744,6 @@ macro_rules! impl_as_ref_mut { /// Type which has a particular kind of crypto associated with it. pub trait CryptoType { - /// The kind of crypto it has. - const KIND: Kind; - /// The pair key type of this crypto. #[cfg(feature="std")] type Pair: Pair; @@ -841,37 +799,6 @@ pub mod key_types { pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } -impl rstd::convert::TryFrom for Kind { - type Error = (); - - fn try_from(kind: KeyTypeId) -> Result { - Ok(match kind { - e if e == key_types::SR25519 => Kind::Sr25519, - e if e == key_types::ED25519 => Kind::Ed25519, - e if e == key_types::BABE => Kind::Sr25519, - e if e == key_types::GRANDPA => Kind::Ed25519, - #[cfg(feature = "std")] - e if e == key_types::DUMMY => Kind::Dummy, - _ => return Err(()), - }) - } -} - -// This doesn't make much sense and should be reconsidered. -impl rstd::convert::TryFrom for KeyTypeId { - type Error = (); - - fn try_from(kind: Kind) -> Result { - Ok(match kind { - Kind::Sr25519 => key_types::SR25519, - Kind::Ed25519 => key_types::ED25519, - #[cfg(feature = "std")] - Kind::Dummy => key_types::DUMMY, - Kind::User => return Err(()), - }) - } -} - #[cfg(test)] mod tests { use crate::DeriveJunction; @@ -892,7 +819,6 @@ mod tests { } } impl CryptoType for TestPair { - const KIND: Kind = Kind::Dummy; type Pair = Self; } @@ -909,7 +835,6 @@ mod tests { } } impl CryptoType for TestPublic { - const KIND: Kind = Kind::Dummy; type Pair = TestPair; } impl Derive for TestPublic {} diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index af14260a3c524..4e7bcf81adddd 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -32,9 +32,7 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec}; #[cfg(feature = "std")] use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; -use crate::{impl_as_ref_mut, crypto::{ - Public as TraitPublic, UncheckedFrom, CryptoType, Kind, Derive -}}; +use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we @@ -494,20 +492,17 @@ impl Pair { } impl CryptoType for Public { - const KIND: Kind = Kind::Ed25519; #[cfg(feature="std")] type Pair = Pair; } impl CryptoType for Signature { - const KIND: Kind = Kind::Ed25519; #[cfg(feature="std")] type Pair = Pair; } #[cfg(feature = "std")] impl CryptoType for Pair { - const KIND: Kind = Kind::Ed25519; type Pair = Pair; } diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 20b89930a23cc..8ce5863e010ec 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -20,7 +20,7 @@ use codec::{Encode, Decode}; use rstd::prelude::{Vec, Box}; use rstd::convert::TryFrom; -pub use crate::crypto::{Kind as CryptoKind, KeyTypeId}; +pub use crate::crypto::KeyTypeId; /// A type of supported crypto. #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] @@ -59,18 +59,6 @@ impl From for u32 { } } -/// Key to use in the offchain worker crypto api. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct CryptoKey { - /// Used cryptography. - pub kind: CryptoKind, - /// The app_id of the key. - pub key_type: KeyTypeId, - /// The public key. - pub public: Vec, -} - /// Opaque type for offchain http requests. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "std", derive(Debug))] @@ -252,38 +240,6 @@ pub trait Externalities { /// Returns information about the local node's network state. fn network_state(&self) -> Result; - /// Create new key pair for signing/encryption/decryption. - /// - /// Returns an error if given crypto kind is not supported. - fn new_key(&mut self, crypto: CryptoKind, app_id: KeyTypeId) -> Result; - - /// Get existing public keys for given `crypto` and `app_id`. - /// - /// Return keys if they are available or an error if given `crypto` or `app_id` is not supported. - fn public_keys(&self, crypto: CryptoKind, app_id: KeyTypeId) -> Result, ()>; - - /// Encrypt a piece of data using given crypto key. - /// - /// Returns an error if `key` is not available or does not exist. - fn encrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Decrypt a piece of data using given crypto key. - /// - /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. - fn decrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Sign a piece of data using given crypto key. - /// - /// Returns an error if `key` is not available or does not exist. - fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Verifies that `signature` for `msg` matches given `key`. - /// - /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. - /// Returns an error in case the key is not available or does not exist or the parameters - /// lengths are incorrect. - fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; - /// Returns current UNIX timestamp (in millis) fn timestamp(&mut self) -> Timestamp; @@ -401,30 +357,6 @@ impl Externalities for Box { (& **self).network_state() } - fn new_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result { - (&mut **self).new_key(crypto, key_type) - } - - fn public_keys(&self, crypto: CryptoKind, key_type: KeyTypeId) -> Result, ()> { - (&**self).public_keys(crypto, key_type) - } - - fn encrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&**self).encrypt(key, data) - } - - fn decrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&**self).decrypt(key, data) - } - - fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&**self).sign(key, data) - } - - fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { - (&**self).verify(key, msg, signature) - } - fn timestamp(&mut self) -> Timestamp { (&mut **self).timestamp() } diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index b8a0313f266cb..ebe1dc26179be 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -33,7 +33,7 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{ Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Ss58Codec }; -use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Kind, Derive}}; +use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; use crate::hash::{H256, H512}; use codec::{Encode, Decode}; @@ -527,20 +527,17 @@ impl Pair { } impl CryptoType for Public { - const KIND: Kind = Kind::Sr25519; #[cfg(feature="std")] type Pair = Pair; } impl CryptoType for Signature { - const KIND: Kind = Kind::Sr25519; #[cfg(feature="std")] type Pair = Pair; } #[cfg(feature = "std")] impl CryptoType for Pair { - const KIND: Kind = Kind::Sr25519; type Pair = Pair; } diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 5c5b64f9a7468..4d8f9722a2e8c 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -241,11 +241,7 @@ impl Service { let offchain_storage = client.backend().offchain_storage(); let offchain_workers = match (config.offchain_worker, offchain_storage) { (true, Some(db)) => { - Some(Arc::new(offchain::OffchainWorkers::new( - client.clone(), - db, - Some(keystore.clone()), - ))) + Some(Arc::new(offchain::OffchainWorkers::new(client.clone(), db))) }, (true, None) => { log::warn!("Offchain workers disabled, due to lack of offchain storage support in backend."); diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 8371bafc07dd9..7227ef4f0d3df 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -36,8 +36,7 @@ pub use primitives::Blake2Hasher; use primitives::{ crypto::KeyTypeId, ed25519, sr25519, offchain::{ - Timestamp, HttpRequestId, HttpRequestStatus, HttpError, CryptoKind, CryptoKey, StorageKind, - OpaqueNetworkState, + Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState, }, }; @@ -279,38 +278,6 @@ export_api! { /// Returns information about the local node's network state. fn network_state() -> Result; - /// Create new key pair for signing/encryption/decryption. - /// - /// Returns an error if given crypto kind is not supported. - fn new_key(crypto: CryptoKind, app_id: KeyTypeId) -> Result; - - /// Get existing public keys for given `crypto` and `app_id`. - /// - /// Return keys if they are available or an error if given `crypto` or `app_id` is not supported. - fn public_keys(crypto: CryptoKind, app_id: KeyTypeId) -> Result, ()>; - - /// Encrypt a piece of data using given crypto key. - /// - /// Returns an error if `key` is not available or does not exist. - fn encrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Decrypt a piece of data using given crypto key. - /// - /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. - fn decrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Sign a piece of data using given crypto key. - /// - /// Returns an error if `key` is not available or does not exist. - fn sign(key: CryptoKey, data: &[u8]) -> Result, ()>; - - /// Verifies that `signature` for `msg` matches given `key`. - /// - /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. - /// Returns an error in case the key is not available or does not exist or the parameters - /// lengths are incorrect. - fn verify(key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; - /// Returns current UNIX timestamp (in millis) fn timestamp() -> Timestamp; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index f2f7c45f33b8d..8774412c1cb1b 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -341,55 +341,6 @@ impl OffchainApi for () { }, "network_state can be called only in the offchain worker context") } - fn public_keys(crypto: offchain::CryptoKind, app_id: offchain::KeyTypeId) -> Result, ()> { - with_offchain(|ext| { - ext.public_keys(crypto, app_id) - }, "public_keys can be called only in the offchain worker context") - } - - fn new_key(crypto: offchain::CryptoKind, key_type: offchain::KeyTypeId) -> Result { - with_offchain(|ext| { - ext.new_key(crypto, key_type) - }, "new_key can be called only in the offchain worker context") - } - - fn encrypt( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - with_offchain(|ext| { - ext.encrypt(key, data) - }, "encrypt can be called only in the offchain worker context") - } - - fn decrypt( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - with_offchain(|ext| { - ext.decrypt(key, data) - }, "decrypt can be called only in the offchain worker context") - } - - fn sign( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - with_offchain(|ext| { - ext.sign(key, data) - }, "sign can be called only in the offchain worker context") - } - - fn verify( - key: offchain::CryptoKey, - msg: &[u8], - signature: &[u8], - ) -> Result { - with_offchain(|ext| { - ext.verify(key, msg, signature) - }, "verify can be called only in the offchain worker context") - } - fn timestamp() -> offchain::Timestamp { with_offchain(|ext| { ext.timestamp() diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index c6779d9bb7974..09b3cc0e2e32c 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -446,94 +446,6 @@ pub mod ext { /// runtime code can always rely on it. fn ext_network_state(written_out: *mut u32) -> *mut u8; - /// Create new key pair for signing/encryption/decryption. - /// - /// # Returns - /// - /// The encoded `Result, ()>`. - /// `written_out` contains the length of the message. - /// - /// The ownership of the returned buffer is transferred to the runtime - /// code and the runtime is responsible for freeing it. This is always - /// a properly allocated pointer (which cannot be NULL), hence the - /// runtime code can always rely on it. - fn ext_new_key(crypto: u32, key_type: u32, written_out: *mut u32) -> *mut u8; - - /// Get a list of public keys matching given `crypto` and `key_type`. - /// - /// # Returns - /// - /// The encoded `Result>, ()>`. - /// `written_out` contains the length of the message. - /// - /// The ownership of the returned buffer is transferred to the runtime - /// code and the runtime is responsible for freeing it. This is always - /// a properly allocated pointer (which cannot be NULL), hence the - /// runtime code can always rely on it. - fn ext_public_keys(crypto: u32, key_type: u32, written_out: *mut u32) -> *mut u8; - - /// Encrypt a piece of data using given crypto key. - /// - /// # Returns - /// - /// - `0` in case the key is invalid, `msg_len` is set to `u32::max_value` - /// - Otherwise, pointer to the encrypted message in memory, - /// `msg_len` contains the length of the message. - fn ext_encrypt( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - msg_len: *mut u32 - ) -> *mut u8; - - /// Decrypt a piece of data using given crypto key. - /// - /// # Returns - /// - /// - `0` in case the key is invalid or data couldn't be decrypted, - /// `msg_len` is set to `u32::max_value` - /// - Otherwise, pointer to the decrypted message in memory, - /// `msg_len` contains the length of the message. - fn ext_decrypt( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - msg_len: *mut u32 - ) -> *mut u8; - - /// Sign a piece of data using given crypto key. - /// - /// # Returns - /// - /// - `0` in case the key is invalid, - /// `sig_data_len` is set to `u32::max_value` - /// - Otherwise, pointer to the signature in memory, - /// `sig_data_len` contains the length of the signature. - fn ext_sign( - key: *const u8, - key_len: u32, - data: *const u8, - data_len: u32, - sig_data_len: *mut u32 - ) -> *mut u8; - - /// Verifies that `signature` for `msg` matches given `key`. - /// - /// # Returns - /// - `0` in case the signature is correct - /// - `1` in case it doesn't match the key - /// - `u32::max_value` if the key is invalid. - fn ext_verify( - key: *const u8, - key_len: u32, - msg: *const u8, - msg_len: u32, - signature: *const u8, - signature_len: u32 - ) -> u32; - /// Returns current UNIX timestamp (milliseconds) fn ext_timestamp() -> u64; @@ -1063,133 +975,6 @@ impl OffchainApi for () { } } - fn new_key( - crypto: offchain::CryptoKind, - key_type: offchain::KeyTypeId, - ) -> Result { - let crypto = crypto.into(); - let key_type = key_type.into(); - let mut len = 0_u32; - let raw_result = unsafe { - let ptr = ext_new_key.get()( - crypto, - key_type, - &mut len - ); - - from_raw_parts(ptr, len) - }; - - match raw_result { - Some(raw_result) => codec::Decode::decode(&mut &*raw_result).unwrap_or(Err(())), - None => Err(()) - } - } - - fn public_keys( - crypto: offchain::CryptoKind, - key_type: offchain::KeyTypeId, - ) -> Result, ()> { - let crypto = crypto.into(); - let key_type = key_type.into(); - let mut len = 0u32; - let raw_result = unsafe { - let ptr = ext_public_keys.get()( - crypto, - key_type, - &mut len, - ); - - from_raw_parts(ptr, len) - }; - - match raw_result { - Some(raw_result) => codec::Decode::decode(&mut &*raw_result).unwrap_or(Err(())), - None => Err(()) - } - } - - fn encrypt( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - let key = codec::Encode::encode(&key); - let mut len = 0_u32; - unsafe { - let ptr = ext_encrypt.get()( - key.as_ptr(), - key.len() as u32, - data.as_ptr(), - data.len() as u32, - &mut len - ); - - from_raw_parts(ptr, len).ok_or(()) - } - } - - fn decrypt( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - let key = codec::Encode::encode(&key); - let mut len = 0_u32; - unsafe { - let ptr = ext_decrypt.get()( - key.as_ptr(), - key.len() as u32, - data.as_ptr(), - data.len() as u32, - &mut len - ); - - from_raw_parts(ptr, len).ok_or(()) - } - } - - fn sign( - key: offchain::CryptoKey, - data: &[u8], - ) -> Result, ()> { - let key = codec::Encode::encode(&key); - let mut len = 0_u32; - unsafe { - let ptr = ext_sign.get()( - key.as_ptr(), - key.len() as u32, - data.as_ptr(), - data.len() as u32, - &mut len - ); - - from_raw_parts(ptr, len).ok_or(()) - } - } - - fn verify( - key: offchain::CryptoKey, - msg: &[u8], - signature: &[u8], - ) -> Result { - let key = codec::Encode::encode(&key); - let val = unsafe { - ext_verify.get()( - key.as_ptr(), - key.len() as u32, - msg.as_ptr(), - msg.len() as u32, - signature.as_ptr(), - signature.len() as u32, - ) - }; - - match val { - 0 => Ok(true), - 1 => Ok(false), - _ => Err(()), - } - } - fn timestamp() -> offchain::Timestamp { offchain::Timestamp::from_unix_millis(unsafe { ext_timestamp.get()() diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 8e41d4f13975d..66d1b6cfb8311 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -55,7 +55,7 @@ pub mod transaction_validity; pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. -pub use primitives::crypto::{key_types, KeyTypeId, Kind, CryptoType}; +pub use primitives::crypto::{key_types, KeyTypeId, CryptoType}; pub use app_crypto::AppKey; /// A message indicating an invalid signature in extrinsic. diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 41f1278408a52..c91c8366c1123 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -26,7 +26,7 @@ use crate::traits::{ use crate::{generic, KeyTypeId}; use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use primitives::H256; -use primitives::{crypto::{Kind, CryptoType, Dummy, key_types, Public}, U256}; +use primitives::{crypto::{CryptoType, Dummy, key_types, Public}, U256}; use crate::transaction_validity::TransactionValidity; /// Authority Id @@ -42,7 +42,6 @@ impl UintAuthorityId { } impl CryptoType for UintAuthorityId { - const KIND: Kind = Kind::Dummy; type Pair = Dummy; } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 0511fa8294dde..200f27ac727d1 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -251,55 +251,6 @@ impl offchain::Externalities for NeverOffchainExt { unreachable!() } - fn new_key( - &mut self, - _crypto: offchain::CryptoKind, - _key_type: offchain::KeyTypeId, - ) -> Result { - unreachable!() - } - - fn public_keys( - &self, - _crypto: offchain::CryptoKind, - _key_type: offchain::KeyTypeId, - ) -> Result, ()> { - unreachable!() - } - - fn encrypt( - &self, - _key: offchain::CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unreachable!() - } - - fn decrypt( - &self, - _key: offchain::CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unreachable!() - } - - fn sign( - &self, - _key: offchain::CryptoKey, - _data: &[u8], - ) -> Result, ()> { - unreachable!() - } - - fn verify( - &self, - _key: offchain::CryptoKey, - _msg: &[u8], - _signature: &[u8], - ) -> Result { - unreachable!() - } - fn timestamp(&mut self) -> offchain::Timestamp { unreachable!() } diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 23a78215e0ba0..23345ea9745b2 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -67,10 +67,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use primitives::{ - crypto::{CryptoType, KeyTypeId}, - offchain::{OpaqueNetworkState, StorageKind}, -}; +use primitives::offchain::{OpaqueNetworkState, StorageKind}; use codec::{Encode, Decode}; use sr_primitives::{ ApplyError, traits::{Extrinsic as ExtrinsicT}, @@ -80,8 +77,7 @@ use rstd::prelude::*; use session::SessionIndex; use sr_io::Printable; use srml_support::{ - StorageValue, decl_module, decl_event, decl_storage, - StorageDoubleMap, print, + StorageValue, decl_module, decl_event, decl_storage, StorageDoubleMap, print, }; use system::ensure_none; use app_crypto::RuntimeAppPublic; @@ -124,7 +120,6 @@ struct WorkerStatus { // Error which may occur while executing the off-chain code. enum OffchainErr { DecodeWorkerStatus, - NoKeys, ExtrinsicCreation, FailedSigning, NetworkState, @@ -135,7 +130,6 @@ impl Printable for OffchainErr { fn print(self) { match self { OffchainErr::DecodeWorkerStatus => print("Offchain error: decoding WorkerStatus failed!"), - OffchainErr::NoKeys => print("Offchain error: could not find local keys!"), OffchainErr::ExtrinsicCreation => print("Offchain error: extrinsic creation failed!"), OffchainErr::FailedSigning => print("Offchain error: signing failed!"), OffchainErr::NetworkState => print("Offchain error: fetching network state failed!"), @@ -266,24 +260,19 @@ impl Module { fn do_gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { // we run only when a local authority key is configured - let key_type = KeyTypeId(*b"imon"); let authorities = Keys::get(); - let mut local_keys = sr_io::public_keys(AuthorityId::KIND, key_type) - .map_err(|_| OffchainErr::NoKeys)?; - local_keys.sort_by(|a, b| a.public.cmp(&b.public)); + let mut local_keys = app::Public::all(); + local_keys.sort(); + for (authority_index, key) in authorities.into_iter() .enumerate() .filter_map(|(index, authority)| { - let authority = app::crypto::Public::from(authority); - let authority: &[u8] = authority.as_ref(); - - local_keys.binary_search_by(|probe| probe.public[..].cmp(authority)) + local_keys.binary_search(&authority) .ok() - .map(|location| (index as u32, local_keys[location].clone())) + .map(|location| (index as u32, &local_keys[location])) }) { - let network_state = - sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; + let network_state = sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; let heartbeat_data = Heartbeat { block_number, network_state, @@ -291,15 +280,11 @@ impl Module { authority_index, }; - let signature = sr_io::sign(key, &heartbeat_data.encode()) - .map_err(|_| OffchainErr::FailedSigning)?; - let signature = AuthoritySignature::decode(&mut &*signature) - .map_err(|_| OffchainErr::ExtrinsicCreation)?; + let signature = key.sign(&heartbeat_data.encode()).ok_or(OffchainErr::FailedSigning)?; let call = Call::heartbeat(heartbeat_data, signature); let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) .ok_or(OffchainErr::ExtrinsicCreation)?; - sr_io::submit_transaction(&ex) - .map_err(|_| OffchainErr::SubmitTransaction)?; + sr_io::submit_transaction(&ex).map_err(|_| OffchainErr::SubmitTransaction)?; // once finished we set the worker status without comparing // if the existing value changed in the meantime. this is From 1d2da8da71ae7151601ffff5f29431f990e71901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 16:50:10 +0200 Subject: [PATCH 68/80] Remove warnings --- core/offchain/src/api.rs | 1 - core/offchain/src/testing.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 8be66877b014e..c13b79131bcb3 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -24,7 +24,6 @@ use std::{ use client::backend::OffchainStorage; use futures::{Stream, Future, sync::mpsc}; -use keystore::Store as Keystore; use log::{info, debug, warn, error}; use network::{PeerId, Multiaddr, NetworkStateInfo}; use codec::{Encode, Decode}; diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index 3b2a9a6e1b5b1..e01e4f5f59a0e 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -28,7 +28,6 @@ use primitives::offchain::{ HttpRequestId as RequestId, HttpRequestStatus as RequestStatus, Timestamp, - KeyTypeId, StorageKind, OpaqueNetworkState, }; From 10ffc74bd450e87198236784d9c811c2e6c20ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 17:55:38 +0200 Subject: [PATCH 69/80] More cleanup --- Cargo.lock | 2 +- core/application-crypto/src/ed25519.rs | 2 +- core/application-crypto/src/lib.rs | 9 +-- core/application-crypto/src/sr25519.rs | 2 +- core/consensus/aura/src/lib.rs | 6 +- core/consensus/babe/src/lib.rs | 2 +- .../finality-grandpa/src/communication/mod.rs | 2 +- core/keyring/src/ed25519.rs | 24 +++++++- core/keyring/src/sr25519.rs | 24 +++++++- core/primitives/src/crypto.rs | 39 ++----------- core/primitives/src/ed25519.rs | 8 +-- core/primitives/src/sr25519.rs | 58 +++---------------- node-template/src/service.rs | 2 +- node/cli/src/chain_spec.rs | 2 - subkey/src/main.rs | 2 +- 15 files changed, 69 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c26d857f2782f..3a7ddfe87787a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4474,8 +4474,8 @@ dependencies = [ name = "substrate-consensus-babe-primitives" version = "2.0.0" dependencies = [ - "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index 5cffe3c1c8005..790ae7f271c78 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -70,6 +70,6 @@ mod tests { let key_pair = keystore.read().ed25519_key_pair(crate::key_types::ED25519, &public.as_ref()) .expect("There should be at a `ed25519` key in the keystore for the given public key."); - assert!(AppPair::verify(&signature, "ed25519", AppPublic::from(key_pair.public()))); + assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(key_pair.public()))); } } \ No newline at end of file diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index eb8a237f11052..fadf9223cfc74 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -107,12 +107,12 @@ macro_rules! app_crypto { fn sign(&self, msg: &[u8]) -> Self::Signature { Signature(self.0.sign(msg)) } - fn verify, M: AsRef<[u8]>>( + fn verify>( sig: &Self::Signature, message: M, - pubkey: P, + pubkey: &Self::Public, ) -> bool { - <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) + <$pair>::verify(&sig.0, message, pubkey.as_ref()) } fn verify_weak, M: AsRef<[u8]>>( sig: &[u8], @@ -145,9 +145,6 @@ macro_rules! app_crypto { #[cfg_attr(feature = "std", derive(Debug, Hash))] pub struct Public($public); } - // TODO: needed for verify since it takes an AsRef, but should be removed once that is - // refactored. - $crate::primitives::impl_as_ref_mut!(Public); impl $crate::Derive for Public { #[cfg(feature = "std")] diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 0e3c0c5384dde..3cc9322158906 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -70,6 +70,6 @@ mod tests { let key_pair = keystore.read().sr25519_key_pair(crate::key_types::SR25519, public.as_ref()) .expect("There should be at a `sr25519` key in the keystore for the given public key."); - assert!(AppPair::verify(&signature, "sr25519", AppPublic::from(key_pair.public()))); + assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(key_pair.public()))); } } \ No newline at end of file diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 726be46562d15..8eaca4f74f17d 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -394,7 +394,7 @@ fn check_header( DigestItemFor: CompatibleDigestItem

, P::Signature: Decode, C: client::backend::AuxStore, - P::Public: AsRef + Encode + Decode + PartialEq + Clone, + P::Public: Encode + Decode + PartialEq + Clone, { let seal = match header.digest_mut().pop() { Some(x) => x, @@ -508,7 +508,7 @@ impl Verifier for AuraVerifier where C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

, P: Pair + Send + Sync + 'static, - P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef + 'static, + P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static, P::Signature: Encode + Decode, { fn verify( @@ -686,7 +686,7 @@ pub fn import_queue( C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

, P: Pair + Send + Sync + 'static, - P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode + AsRef, + P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode, P::Signature: Encode + Decode, { register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.get())?; diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 3e8f45d49ab5f..c8b9f255595c5 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -492,7 +492,7 @@ fn check_header( } else { let (pre_hash, author) = (header.hash(), &authorities[authority_index as usize].0); - if AuthorityPair::verify(&sig, pre_hash, author.clone()) { + if AuthorityPair::verify(&sig, pre_hash, &author) { let (inout, _batchable_proof) = { let transcript = make_transcript( &randomness, diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 7b58ca08e6867..2aa2618535948 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -634,7 +634,7 @@ pub(crate) fn check_message_sig( ) -> Result<(), ()> { let as_public = id.clone(); let encoded_raw = localized_payload(round, set_id, message); - if AuthorityPair::verify(signature, &encoded_raw, as_public) { + if AuthorityPair::verify(signature, &encoded_raw, &as_public) { Ok(()) } else { debug!(target: "afg", "Bad signature on message from {:?}", id); diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index f4d4ec5993432..56bdb1ce8c0e6 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -169,8 +169,26 @@ mod tests { #[test] fn should_work() { - assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice)); - assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice)); - assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob)); + assert!( + Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Alice.public(), + ) + ); + assert!( + !Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Bob!", + &Keyring::Alice.public(), + ) + ); + assert!( + !Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Bob.public(), + ) + ); } } diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index 21f0f1bb7d274..bb3aaa6b51db1 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -170,8 +170,26 @@ mod tests { #[test] fn should_work() { - assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice)); - assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice)); - assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob)); + assert!( + Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Alice.public(), + ) + ); + assert!( + !Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Bob!", + &Keyring::Alice.public(), + ) + ); + assert!( + !Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Bob.public(), + ) + ); } } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index c6e3ac6e6d339..b77fba56e99c1 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -542,16 +542,8 @@ mod dummy { _: I ) -> Result { Ok(Self) } fn sign(&self, _: &[u8]) -> Self::Signature { Self } - fn verify, M: AsRef<[u8]>>( - _: &Self::Signature, - _: M, - _: P - ) -> bool { true } - fn verify_weak, M: AsRef<[u8]>>( - _: &[u8], - _: M, - _: P - ) -> bool { true } + fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true } fn public(&self) -> Self::Public { Self } fn to_raw_vec(&self) -> Vec { vec![] } } @@ -623,7 +615,7 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { fn sign(&self, message: &[u8]) -> Self::Signature; /// Verify a signature on a message. Returns true if the signature is good. - fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool; + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool; /// Verify a signature on a message. Returns true if the signature is good. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool; @@ -723,25 +715,6 @@ impl UncheckedFrom for Outer where } } -/// Implement `AsRef` and `AsMut` for the provided type. -#[macro_export] -macro_rules! impl_as_ref_mut { - ($name:ty) => { - impl AsMut for $name { - fn as_mut(&mut self) -> &mut Self { - self - } - } - impl AsRef for $name { - fn as_ref(&self) -> &Self { - &self - } - } - } -} - -// TODO: remove default cryptos - /// Type which has a particular kind of crypto associated with it. pub trait CryptoType { /// The pair key type of this crypto. @@ -874,11 +847,7 @@ mod tests { } fn from_seed(_seed: &::Seed) -> Self { TestPair::Seed(vec![]) } fn sign(&self, _message: &[u8]) -> Self::Signature { [] } - fn verify, M: AsRef<[u8]>>( - _sig: &Self::Signature, - _message: M, - _pubkey: P - ) -> bool { true } + fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } fn verify_weak, M: AsRef<[u8]>>( _sig: &[u8], _message: M, diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 4e7bcf81adddd..810e86767d8e3 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -32,7 +32,7 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec}; #[cfg(feature = "std")] use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; -use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; +use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we @@ -318,8 +318,6 @@ impl Public { } } -impl_as_ref_mut!(Public); - impl TraitPublic for Public { /// A new instance from the given slice that should be 32 bytes long. /// @@ -441,8 +439,8 @@ impl TraitPair for Pair { } /// Verify a signature on a message. Returns true if the signature is good. - fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool { - Self::verify_weak(&sig.0[..], message.as_ref(), &pubkey.as_ref().0[..]) + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + Self::verify_weak(&sig.0[..], message.as_ref(), pubkey) } /// Verify a signature on a message. Returns true if the signature is good. diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 620e16c031677..0e573f49ce34c 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -33,7 +33,7 @@ use bip39::{Mnemonic, Language, MnemonicType}; use crate::crypto::{ Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Ss58Codec }; -use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; +use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; use crate::hash::{H256, H512}; use codec::{Encode, Decode}; @@ -65,8 +65,6 @@ impl Clone for Pair { } } -impl_as_ref_mut!(Public); - impl AsRef<[u8; 32]> for Public { fn as_ref(&self) -> &[u8; 32] { &self.0 @@ -483,20 +481,15 @@ impl TraitPair for Pair { } /// Verify a signature on a message. Returns true if the signature is good. - fn verify, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool { - // Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets - // that have not been upgraded and those that have. To swap to 0.8.0 only, - // create `schnorrkel::Signature` and pass that into `verify_simple` - match PublicKey::from_bytes(pubkey.as_ref().as_slice()) { - Ok(pk) => pk.verify_simple_preaudit_deprecated( - SIGNING_CTX, message.as_ref(), &sig.as_ref(), - ).is_ok(), - Err(_) => false, - } + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + Self::verify_weak(&sig.0[..], message, pubkey) } /// Verify a signature on a message. Returns true if the signature is good. fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { + // Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets + // that have not been upgraded and those that have. To swap to 0.8.0 only, + // create `schnorrkel::Signature` and pass that into `verify_simple` match PublicKey::from_bytes(pubkey.as_ref()) { Ok(pk) => pk.verify_simple_preaudit_deprecated( SIGNING_CTX, message.as_ref(), &sig, @@ -578,43 +571,6 @@ mod compatibility_test { } } -#[cfg(test)] -mod compatibility_test { - use super::*; - use crate::crypto::{DEV_PHRASE}; - use hex_literal::hex; - - // NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are - // still functional. - - #[test] - fn derive_soft_known_pair_should_work() { - let pair = Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap(); - // known address of DEV_PHRASE with 1.1 - let known = hex!("d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e"); - assert_eq!(pair.public().to_raw_vec(), known); - } - - #[test] - fn derive_hard_known_pair_should_work() { - let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap(); - // known address of DEV_PHRASE with 1.1 - let known = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); - assert_eq!(pair.public().to_raw_vec(), known); - } - - #[test] - fn verify_known_message_should_work() { - let public = Public::from_raw(hex!("b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918")); - // signature generated by the 1.1 version with the same ^^ public key. - let signature = Signature::from_raw(hex!( - "5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202" - )); - let message = b"Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n"; - assert!(Pair::verify(&signature, &message[..], &public)); - } -} - #[cfg(test)] mod test { use super::*; @@ -760,6 +716,6 @@ mod test { let js_signature = Signature::from_raw(hex!( "28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00" )); - assert!(Pair::verify(&js_signature, b"SUBSTRATE", public)); + assert!(Pair::verify(&js_signature, b"SUBSTRATE", &public)); } } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 92e0153b482c1..31323e11adf28 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -66,7 +66,7 @@ construct_service_factory! { }, AuthoritySetup = { |service: Self::FullService| { - if let Some(key) = None:: /* service.authority_key() */ { + if let Some(key) = None:: { info!("Using authority key {}", key.public()); let proposer = ProposerFactory { client: service.client(), diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 1d59882407e2f..c14a2709c1120 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -54,8 +54,6 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // and // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done - // TODO: actually use sr25519 for babe keys (right now they seems to just be copies of the - // ed25519 grandpa key). let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId)> = vec![( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), diff --git a/subkey/src/main.rs b/subkey/src/main.rs index c123e88ec2f7a..5b16bde28d801 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -88,7 +88,7 @@ impl Crypto for Sr25519 { fn execute(matches: clap::ArgMatches) where <::Pair as Pair>::Signature: AsRef<[u8]> + AsMut<[u8]> + Default, - <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, + <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec, { let extra = |i: Index, f: Balance| { ( From ac05779f27b95906157694c17946f1ea25ca60a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 18:19:30 +0200 Subject: [PATCH 70/80] Apply suggestions from code review Co-Authored-By: Benjamin Kampmann --- core/application-crypto/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index fadf9223cfc74..d9bff822eedee 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -62,7 +62,7 @@ macro_rules! app_crypto { $crate::app_crypto!($public, $sig, $key_type); $crate::wrap!{ - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + /// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App. #[derive(Clone)] pub struct Pair($pair); } @@ -137,7 +137,7 @@ macro_rules! app_crypto { }; ($public:ty, $sig:ty, $key_type:expr) => { $crate::wrap!{ - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::codec::Encode, $crate::codec::Decode, @@ -237,7 +237,7 @@ macro_rules! app_crypto { } $crate::wrap! { - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive(Clone, Default, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode)] #[cfg_attr(feature = "std", derive(Debug, Hash))] pub struct Signature($sig); From ecae8346355627f6a67eb01a183dc0b21f987059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 18:29:19 +0200 Subject: [PATCH 71/80] More cleanups --- core/offchain/src/lib.rs | 2 +- core/primitives/src/testing.rs | 4 ++-- core/primitives/src/traits.rs | 4 ++-- core/session/Cargo.toml | 2 +- core/session/src/lib.rs | 13 ++++--------- core/sr-primitives/src/lib.rs | 11 ++++------- srml/membership/src/lib.rs | 2 +- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index 431af24dc63bb..5525546f2558a 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -176,7 +176,7 @@ mod tests { let pool = Arc::new(Pool::new(Default::default(), transaction_pool::ChainApi::new(client.clone()))); let db = client_db::offchain::LocalStorage::new_test(); let network_state = Arc::new(MockNetworkStateInfo()); - // TODO Test keystore + // when let offchain = OffchainWorkers::new(client, db); runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone())); diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index b6610db64df49..e3faefa0fbe62 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -112,4 +112,4 @@ impl crate::traits::KeyStore for KeyStore { .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) ) } -} \ No newline at end of file +} diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index 03299aca43484..a6d6e50921dad 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -56,4 +56,4 @@ pub trait KeyStore: Send + Sync { /// A pointer to the key store. #[cfg(feature = "std")] -pub type KeyStorePtr = std::sync::Arc>; \ No newline at end of file +pub type KeyStorePtr = std::sync::Arc>; diff --git a/core/session/Cargo.toml b/core/session/Cargo.toml index 2c996ef9246d2..5d8cb3f0001ba 100644 --- a/core/session/Cargo.toml +++ b/core/session/Cargo.toml @@ -12,4 +12,4 @@ primitives = { package = "substrate-primitives", path = "../primitives", optiona [features] default = [ "std" ] -std = [ "client/std", "rstd/std", "sr-primitives", "primitives" ] \ No newline at end of file +std = [ "client/std", "rstd/std", "sr-primitives", "primitives" ] diff --git a/core/session/src/lib.rs b/core/session/src/lib.rs index a3803efc7b4bb..a962f2bfe31b9 100644 --- a/core/session/src/lib.rs +++ b/core/session/src/lib.rs @@ -54,15 +54,10 @@ where let runtime_api = client.runtime_api(); for seed in seeds { - let seed = seed.as_bytes(); - - // We need to generate the keys for the best block + the last finalized block. - for number in &[info.best_number, info.finalized_number] { - runtime_api.generate_session_keys( - &sr_primitives::generic::BlockId::Number(*number), - Some(seed.to_vec()), - )?; - } + runtime_api.generate_session_keys( + &sr_primitives::generic::BlockId::Number(info.best_number), + Some(seed.as_bytes().to_vec()), + )?; } Ok(()) diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 66d1b6cfb8311..3c4c69f084ef6 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -664,16 +664,13 @@ pub struct AnySignature(H512); impl Verify for AnySignature { type Signer = sr25519::Public; fn verify>(&self, mut msg: L, signer: &sr25519::Public) -> bool { - let sr25519 = sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) + sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) .map(|s| runtime_io::sr25519_verify(&s, msg.get(), &signer)) - .unwrap_or(false); - - let ed25519 = ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) + .unwrap_or(false) + || ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) .and_then(|s| ed25519::Public::try_from(signer.0.as_ref()).map(|p| (s, p))) .map(|(s, p)| runtime_io::ed25519_verify(&s, msg.get(), &p)) - .unwrap_or(false); - - sr25519 || ed25519 + .unwrap_or(false) } } diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index e80e0c61f4dd5..805ec368bbad9 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify From 900d1772b4b39a53c95a0c87c776eabb2adf57fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 18:43:42 +0200 Subject: [PATCH 72/80] JSONRPC API for setting keys. Also, rename traits::KeyStore* -> traits::BareCryptoStore* --- Cargo.lock | 39 ++++++------ core/client/Cargo.toml | 2 +- core/client/db/Cargo.toml | 2 +- core/client/db/src/lib.rs | 2 +- core/client/src/call_executor.rs | 4 +- core/client/src/client.rs | 4 +- core/consensus/aura/Cargo.toml | 2 +- core/consensus/aura/src/lib.rs | 4 +- core/consensus/babe/Cargo.toml | 2 +- core/consensus/babe/src/tests.rs | 4 +- core/consensus/common/Cargo.toml | 2 +- core/consensus/rhd/Cargo.toml | 2 +- core/consensus/slots/Cargo.toml | 2 +- core/executor/Cargo.toml | 2 +- core/finality-grandpa/Cargo.toml | 2 +- core/finality-grandpa/src/tests.rs | 2 +- core/inherents/Cargo.toml | 2 +- core/keystore/src/lib.rs | 77 ++++++++++++++++++----- core/network/Cargo.toml | 2 +- core/offchain/Cargo.toml | 2 +- core/offchain/src/api.rs | 6 +- core/offchain/src/lib.rs | 6 +- core/primitives/src/crypto.rs | 15 ++++- core/primitives/src/testing.rs | 4 +- core/primitives/src/traits.rs | 17 ++++- core/rpc/Cargo.toml | 5 +- core/rpc/src/author/error.rs | 12 ++++ core/rpc/src/author/mod.rs | 87 ++++++++++++++++++++++---- core/rpc/src/author/tests.rs | 52 ++++++++++++++- core/service/src/components.rs | 13 ++-- core/service/src/lib.rs | 1 + core/state-db/Cargo.toml | 2 +- core/state-machine/src/basic.rs | 2 +- core/state-machine/src/ext.rs | 8 +-- core/state-machine/src/lib.rs | 17 ++--- core/state-machine/src/testing.rs | 6 +- core/telemetry/Cargo.toml | 2 +- core/test-client/src/lib.rs | 6 +- core/transaction-pool/Cargo.toml | 2 +- core/transaction-pool/graph/Cargo.toml | 2 +- node-template/Cargo.toml | 2 +- node/cli/src/service.rs | 2 +- srml/aura/Cargo.toml | 2 +- 43 files changed, 317 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce037ef45c747..2b8fe4b3b3083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2414,7 +2414,7 @@ dependencies = [ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "node-template-runtime 2.0.0", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", @@ -3711,7 +3711,7 @@ version = "2.0.0" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4342,7 +4342,7 @@ dependencies = [ "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-api-macros 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", @@ -4370,7 +4370,7 @@ dependencies = [ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-common 2.0.0", @@ -4393,7 +4393,7 @@ dependencies = [ "futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-version 2.0.0", @@ -4442,7 +4442,7 @@ dependencies = [ "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", @@ -4491,7 +4491,7 @@ dependencies = [ "libp2p 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", @@ -4519,7 +4519,7 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rhododendron 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4542,7 +4542,7 @@ dependencies = [ "futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-common 2.0.0", @@ -4564,7 +4564,7 @@ dependencies = [ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-version 2.0.0", "substrate-client 2.0.0", @@ -4591,7 +4591,7 @@ dependencies = [ "futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -4631,7 +4631,7 @@ name = "substrate-inherents" version = "2.0.0" dependencies = [ "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", ] @@ -4683,7 +4683,7 @@ dependencies = [ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4718,7 +4718,7 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", @@ -4809,7 +4809,7 @@ dependencies = [ "jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4818,6 +4818,7 @@ dependencies = [ "sr-version 2.0.0", "substrate-client 2.0.0", "substrate-executor 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-state-machine 2.0.0", @@ -4937,7 +4938,7 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", ] @@ -4968,7 +4969,7 @@ dependencies = [ "futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libp2p 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5050,7 +5051,7 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (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", "substrate-primitives 2.0.0", @@ -5065,7 +5066,7 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-keyring 2.0.0", diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index 5848c67349852..793db376135fc 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" derive_more = { version = "0.14.0", optional = true } fnv = { version = "1.0", optional = true } log = { version = "0.4", optional = true } -parking_lot = { version = "0.8.0", optional = true } +parking_lot = { version = "0.9.0", optional = true } hex = { package = "hex-literal", version = "0.2", optional = true } futures-preview = { version = "0.3.0-alpha.17", optional = true } consensus = { package = "substrate-consensus-common", path = "../consensus/common", optional = true } diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml index 5df825fe12747..b7bc835ef012a 100644 --- a/core/client/db/Cargo.toml +++ b/core/client/db/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parking_lot = "0.8" +parking_lot = "0.9.0" log = "0.4" kvdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } # FIXME replace with release as soon as our rocksdb changes are released upstream https://github.com/paritytech/parity-common/issues/88 diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 7820891330599..250af8ea60582 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -195,7 +195,7 @@ pub fn new_client( executor: E, genesis_storage: S, execution_strategies: ExecutionStrategies, - keystore: Option, + keystore: Option, ) -> Result< client::Client, client::LocalCallExecutor, E>, Block, RA>, client::error::Error diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 9c70a530e619a..41610744c865b 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -151,7 +151,7 @@ where pub struct LocalCallExecutor { backend: Arc, executor: E, - keystore: Option, + keystore: Option, } impl LocalCallExecutor { @@ -159,7 +159,7 @@ impl LocalCallExecutor { pub fn new( backend: Arc, executor: E, - keystore: Option, + keystore: Option, ) -> Self { LocalCallExecutor { backend, diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 4e32a8f7efc7b..7213db0c9fd29 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -253,7 +253,7 @@ impl PrePostHeader { pub fn new_in_mem( executor: E, genesis_storage: S, - keystore: Option, + keystore: Option, ) -> error::Result, LocalCallExecutor, E>, @@ -273,7 +273,7 @@ pub fn new_with_backend( backend: Arc, executor: E, build_genesis_storage: S, - keystore: Option, + keystore: Option, ) -> error::Result, Block, RA>> where E: CodeExecutor + RuntimeInfo, diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index e704af23dd817..c27aa5df6dd6c 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -24,7 +24,7 @@ sr-primitives = { path = "../../sr-primitives" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } futures01 = { package = "futures", version = "0.1" } futures-timer = "0.2.1" -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4" [dev-dependencies] diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 0fa2b147bd52d..eb7633f9f1e11 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -40,19 +40,17 @@ use consensus_common::import_queue::{ }; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, - blockchain::{ProvideCache, HeaderBackend}, + blockchain::ProvideCache, runtime_api::ApiExt, error::Result as CResult, backend::AuxStore, BlockOf }; -use substrate_keystore::Store; use sr_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification}; use sr_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member}; use primitives::crypto::Pair; -use app_crypto::{AppPair, AppKey}; use inherents::{InherentDataProviders, InherentData}; use futures::{prelude::*, future}; diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index b4bb9c96de75a..9e1fb6bd4b089 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -28,7 +28,7 @@ fork-tree = { path = "../../utils/fork-tree" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } futures01 = { package = "futures", version = "0.1" } futures-timer = "0.2.1" -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4.6" schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"] } rand = "0.6.5" diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index c3a44cff61156..f1983a99628d7 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -196,7 +196,7 @@ fn run_one_test() { for (peer_id, seed) in peers { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); - keystore.write().generate_from_seed::(seed).expect("Generates authority key"); + keystore.write().insert_ephemeral_from_seed::(seed).expect("Generates authority key"); keystore_paths.push(keystore_path); let client = net.lock().peer(*peer_id).client().as_full().unwrap(); @@ -312,7 +312,7 @@ fn can_author_block() { let _ = env_logger::try_init(); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); - let pair = keystore.write().generate_from_seed::("//Alice") + let pair = keystore.write().insert_ephemeral_from_seed::("//Alice") .expect("Generates authority pair"); let mut i = 0; diff --git a/core/consensus/common/Cargo.toml b/core/consensus/common/Cargo.toml index b327e9456ae13..29f30e363d1b9 100644 --- a/core/consensus/common/Cargo.toml +++ b/core/consensus/common/Cargo.toml @@ -17,7 +17,7 @@ rstd = { package = "sr-std", path = "../../sr-std" } runtime_version = { package = "sr-version", path = "../../sr-version" } sr-primitives = { path = "../../sr-primitives" } codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } -parking_lot = "0.8.0" +parking_lot = "0.9.0" [dev-dependencies] test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" } diff --git a/core/consensus/rhd/Cargo.toml b/core/consensus/rhd/Cargo.toml index 3f6fef71a3739..801605c3f64ca 100644 --- a/core/consensus/rhd/Cargo.toml +++ b/core/consensus/rhd/Cargo.toml @@ -19,7 +19,7 @@ sr-primitives = { path = "../../sr-primitives" } runtime_version = { package = "sr-version", path = "../../sr-version" } runtime_io = { package = "sr-io", path = "../../sr-io" } tokio = "0.1.7" -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4" rhododendron = { version = "0.7.0", features = ["codec"] } exit-future = "0.1" diff --git a/core/consensus/slots/Cargo.toml b/core/consensus/slots/Cargo.toml index 30e3eb654c06b..857d1e3a6b94e 100644 --- a/core/consensus/slots/Cargo.toml +++ b/core/consensus/slots/Cargo.toml @@ -14,7 +14,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../common" inherents = { package = "substrate-inherents", path = "../../inherents" } futures-preview = "0.3.0-alpha.17" futures-timer = "0.2.1" -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4" [dev-dependencies] diff --git a/core/executor/Cargo.toml b/core/executor/Cargo.toml index c5b296b86675f..a4707fb89e3d4 100644 --- a/core/executor/Cargo.toml +++ b/core/executor/Cargo.toml @@ -18,7 +18,7 @@ wasmi = "0.5.0" parity-wasm = "0.31" byteorder = "1.3" lazy_static = "1.3" -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4" libsecp256k1 = "0.2.1" tiny-keccak = "1.4.2" diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 8abd3bbc6b7ad..71a0775cd7e87 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -9,7 +9,7 @@ fork-tree = { path = "../../core/utils/fork-tree" } futures = "0.1" futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } log = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" tokio-executor = "0.1.7" tokio-timer = "0.2.11" rand = "0.6" diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index b46ec8f63df5f..8b0cc3bc0ca64 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -349,7 +349,7 @@ fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { fn create_keystore(authority: Ed25519Keyring) -> (KeyStorePtr, tempfile::TempDir) { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); - keystore.write().generate_from_seed::(&authority.to_seed()) + keystore.write().insert_ephemeral_from_seed::(&authority.to_seed()) .expect("Creates authority key"); (keystore, keystore_path) diff --git a/core/inherents/Cargo.toml b/core/inherents/Cargo.toml index f89288578ac8c..45e0b9e828ec7 100644 --- a/core/inherents/Cargo.toml +++ b/core/inherents/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parking_lot = { version = "0.8.0", optional = true } +parking_lot = { version = "0.9.0", optional = true } rstd = { package = "sr-std", path = "../sr-std", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } sr-primitives = { path = "../sr-primitives", default-features = false } diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index c66e245113e2c..04514995542ca 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -21,7 +21,7 @@ use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}, sync::Arc}; use primitives::{ - crypto::{KeyTypeId, Pair as PairT, Public, IsWrappedBy, Protected}, traits::KeyStore, + crypto::{KeyTypeId, Pair as PairT, Public, IsWrappedBy, Protected}, traits::BareCryptoStore, }; use app_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519}; @@ -47,6 +47,9 @@ pub enum Error { /// Invalid seed #[display(fmt="Invalid seed")] InvalidSeed, + /// Keystore unavailable + #[display(fmt="Keystore unavailable")] + Unavailable, } /// Keystore Result @@ -99,17 +102,49 @@ impl Store { } /// Insert the given public/private key pair with the given key type. - fn insert_pair(&mut self, pair: &Pair, key_type: KeyTypeId) { + /// + /// Does not place it into the file system store. + fn insert_ephemeral_pair(&mut self, pair: &Pair, key_type: KeyTypeId) { let key = (key_type, pair.public().to_raw_vec()); self.additional.insert(key, pair.to_raw_vec()); } + /// Insert a new key with anonymous crypto. + /// + /// Places it into the file system store. + fn insert_unknown(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> { + let mut file = File::create(self.key_file_path(public, key_type)).map_err(Error::Io)?; + serde_json::to_writer(&file, &suri).map_err(Error::Json)?; + file.flush().map_err(Error::Io)?; + Ok(()) + } + + /// Insert a new key. + /// + /// Places it into the file system store. + pub fn insert_by_type(&self, key_type: KeyTypeId, suri: &str) -> Result { + let pair = Pair::from_string( + suri, + self.password.as_ref().map(|p| &***p) + ).map_err(|_| Error::InvalidSeed)?; + self.insert_unknown(key_type, suri, pair.public().as_slice()) + .map_err(|_| Error::Unavailable)?; + Ok(pair) + } + + /// Insert a new key. + /// + /// Places it into the file system store. + pub fn insert(&self, suri: &str) -> Result { + self.insert_by_type::(Pair::ID, suri).map(Into::into) + } + /// Generate a new key. /// /// Places it into the file system store. pub fn generate_by_type(&self, key_type: KeyTypeId) -> Result { let (pair, phrase, _) = Pair::generate_with_phrase(self.password.as_ref().map(|p| &***p)); - let mut file = File::create(self.key_file_path::(&pair.public(), key_type))?; + let mut file = File::create(self.key_file_path(pair.public().as_slice(), key_type))?; serde_json::to_writer(&file, &phrase)?; file.flush()?; Ok(pair) @@ -125,21 +160,21 @@ impl Store { /// Create a new key from seed. /// /// Does not place it into the file system store. - pub fn generate_from_seed_by_type( + pub fn insert_ephemeral_from_seed_by_type( &mut self, seed: &str, key_type: KeyTypeId, ) -> Result { let pair = Pair::from_string(seed, None).map_err(|_| Error::InvalidSeed)?; - self.insert_pair(&pair, key_type); + self.insert_ephemeral_pair(&pair, key_type); Ok(pair) } /// Create a new key from seed. /// /// Does not place it into the file system store. - pub fn generate_from_seed(&mut self, seed: &str) -> Result { - self.generate_from_seed_by_type::(seed, Pair::ID).map(Into::into) + pub fn insert_ephemeral_from_seed(&mut self, seed: &str) -> Result { + self.insert_ephemeral_from_seed_by_type::(seed, Pair::ID).map(Into::into) } /// Get a key pair for the given public key and key type. @@ -151,7 +186,7 @@ impl Store { return Ok(pair) } - let path = self.key_file_path::(public, key_type); + let path = self.key_file_path(public.as_slice(), key_type); let file = File::open(path)?; let phrase: String = serde_json::from_reader(&file)?; @@ -216,23 +251,23 @@ impl Store { } /// Returns the file path for the given public key and key type. - fn key_file_path(&self, public: &Pair::Public, key_type: KeyTypeId) -> PathBuf { + fn key_file_path(&self, public: &[u8], key_type: KeyTypeId) -> PathBuf { let mut buf = self.path.clone(); let key_type = hex::encode(key_type.0); - let key = hex::encode(public.as_slice()); + let key = hex::encode(public); buf.push(key_type + key.as_str()); buf } } -impl KeyStore for Store { +impl BareCryptoStore for Store { fn sr25519_generate_new( &mut self, id: KeyTypeId, seed: Option<&str>, ) -> std::result::Result<[u8; 32], String> { let pair = match seed { - Some(seed) => self.generate_from_seed_by_type::(seed, id), + Some(seed) => self.insert_ephemeral_from_seed_by_type::(seed, id), None => self.generate_by_type::(id), }.map_err(|e| e.to_string())?; @@ -249,7 +284,7 @@ impl KeyStore for Store { seed: Option<&str>, ) -> std::result::Result<[u8; 32], String> { let pair = match seed { - Some(seed) => self.generate_from_seed_by_type::(seed, id), + Some(seed) => self.insert_ephemeral_from_seed_by_type::(seed, id), None => self.generate_by_type::(id), }.map_err(|e| e.to_string())?; @@ -259,6 +294,16 @@ impl KeyStore for Store { fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { self.key_pair_by_type::(pub_key, id).ok() } + + fn insert_unknown(&mut self, key_type: KeyTypeId, suri: &str, public: &[u8]) + -> std::result::Result<(), ()> + { + Store::insert_unknown(self, key_type, suri, public).map_err(|_| ()) + } + + fn password(&self) -> Option<&str> { + self.password.as_ref().map(|x| x.as_str()) + } } #[cfg(test)] @@ -283,13 +328,13 @@ mod tests { } #[test] - fn test_generate_from_seed() { + fn test_insert_ephemeral_from_seed() { let temp_dir = TempDir::new("keystore").unwrap(); let store = Store::open(temp_dir.path(), None).unwrap(); let pair: ed25519::AppPair = store .write() - .generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc") + .insert_ephemeral_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc") .unwrap(); assert_eq!( "5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", @@ -333,7 +378,7 @@ mod tests { let mut public_keys = Vec::new(); for i in 0..10 { public_keys.push(store.write().generate::().unwrap().public()); - public_keys.push(store.write().generate_from_seed::( + public_keys.push(store.write().insert_ephemeral_from_seed::( &format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i), ).unwrap().public()); } diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index e1cbcfca44fed..0600a60999c64 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -11,7 +11,7 @@ bytes = "0.4" derive_more = "0.14.0" either = "1.5.2" log = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" bitflags = "1.0" fnv = "1.0" futures = "0.1.17" diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index 4e8ede20fd04f..ed201c9316ad5 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -12,7 +12,7 @@ futures = "0.1.25" log = "0.4" offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" } codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } -parking_lot = "0.8.0" +parking_lot = "0.9.0" primitives = { package = "substrate-primitives", path = "../../core/primitives" } sr-primitives = { path = "../../core/sr-primitives" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 45eb09a85fe70..88f85a96955ee 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -33,7 +33,7 @@ use primitives::offchain::{ CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use primitives::{ed25519, sr25519, traits::KeyStorePtr}; +use primitives::{ed25519, sr25519, traits::BareCryptoStorePtr}; use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; @@ -89,7 +89,7 @@ impl KnownCryptoKey { pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, - keystore: Option, + keystore: Option, network_state: Arc, at: BlockId, } @@ -391,7 +391,7 @@ impl AsyncApi { pub fn new( transaction_pool: Arc>, db: S, - keystore: Option, + keystore: Option, at: BlockId, network_state: Arc, ) -> (Api, AsyncApi) { diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index b1e3b4d77a425..3378c284ccce3 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -44,7 +44,7 @@ use futures::future::Future; use keystore::Store as Keystore; use log::{debug, warn}; use network::NetworkStateInfo; -use primitives::{ExecutionContext, traits::KeyStorePtr}; +use primitives::{ExecutionContext, traits::BareCryptoStorePtr}; use sr_primitives::{ generic::BlockId, traits::{self, ProvideRuntimeApi}, @@ -61,7 +61,7 @@ pub use offchain_primitives::OffchainWorkerApi; pub struct OffchainWorkers { client: Arc, db: Storage, - keystore: Option, + keystore: Option, _block: PhantomData, } @@ -71,7 +71,7 @@ impl OffchainWorkers< Block, > { /// Creates new `OffchainWorkers`. - pub fn new(client: Arc, db: Storage, keystore: Option) -> Self { + pub fn new(client: Arc, db: Storage, keystore: Option) -> Self { Self { client, db, diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index a44ef389ed3ec..cf2e77c55fddf 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -18,7 +18,6 @@ //! Cryptographic utilities. // end::description[] -#[cfg(feature ="std")] use rstd::convert::{TryFrom, TryInto}; #[cfg(feature = "std")] use parking_lot::Mutex; @@ -814,6 +813,19 @@ impl From for u32 { } } +impl<'a> TryFrom<&'a str> for KeyTypeId { + type Error = (); + fn try_from(x: &'a str) -> Result { + let b = x.as_bytes(); + if b.len() != 4 { + return Err(()); + } + let mut res = KeyTypeId::default(); + res.0.copy_from_slice(&b[0..4]); + Ok(res) + } +} + /// Known key types; this also functions as a global registry of key types for projects wishing to /// avoid collisions with each other. /// @@ -850,6 +862,7 @@ impl rstd::convert::TryFrom for Kind { e if e == key_types::ED25519 => Kind::Ed25519, e if e == key_types::BABE => Kind::Sr25519, e if e == key_types::GRANDPA => Kind::Ed25519, + e if e == key_types::IM_ONLINE => Kind::Sr25519, #[cfg(feature = "std")] e if e == key_types::DUMMY => Kind::Dummy, _ => return Err(()), diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index c852ec5f26d52..4508346dd0d22 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -58,7 +58,7 @@ impl KeyStore { } #[cfg(feature = "std")] -impl crate::traits::KeyStore for KeyStore { +impl crate::traits::BareCryptoStore for KeyStore { fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) -> Result<[u8; 32], String> { match seed { Some(seed) => { @@ -104,4 +104,4 @@ impl crate::traits::KeyStore for KeyStore { .map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid")) ) } -} \ No newline at end of file +} diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index ff8d68e6494f6..67e0b7d14878d 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -21,7 +21,7 @@ use crate::{crypto::KeyTypeId, ed25519, sr25519}; /// Something that generates, stores and provides access to keys. #[cfg(feature = "std")] -pub trait KeyStore: Send + Sync { +pub trait BareCryptoStore: Send + Sync { /// Generate a new sr25519 key pair for the given key type and an optional seed. /// /// If the given seed is `Some(_)`, the key pair will only be stored in memory. @@ -40,8 +40,21 @@ pub trait KeyStore: Send + Sync { /// Returns the ed25519 key pair for the given key type and public key combination. fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option; + + /// Insert a new key. This doesn't require any known of the crypto; but a public key must be + /// manually provided. + /// + /// Places it into the file system store. + /// + /// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`. + fn insert_unknown(&mut self, _key_type: KeyTypeId, _suri: &str, _public: &[u8]) -> Result<(), ()> { + Err(()) + } + + /// Get the password for this store. + fn password(&self) -> Option<&str> { None } } /// A pointer to the key store. #[cfg(feature = "std")] -pub type KeyStorePtr = std::sync::Arc>; \ No newline at end of file +pub type BareCryptoStorePtr = std::sync::Arc>; diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index cf129a03e6bca..3072ba47830dc 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -13,7 +13,7 @@ jsonrpc-core-client = "12.0.0" jsonrpc-pubsub = "12.0.0" jsonrpc-derive = "12.0.0" log = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" codec = { package = "parity-scale-codec", version = "1.0.0" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -23,8 +23,9 @@ network = { package = "substrate-network", path = "../network" } primitives = { package = "substrate-primitives", path = "../primitives" } state_machine = { package = "substrate-state-machine", path = "../state-machine" } transaction_pool = { package = "substrate-transaction-pool", path = "../transaction-pool" } -sr-primitives = { path = "../sr-primitives" } +sr-primitives = { path = "../sr-primitives" } runtime_version = { package = "sr-version", path = "../sr-version" } +substrate-keystore = { path = "../keystore" } [dev-dependencies] assert_matches = "1.1" diff --git a/core/rpc/src/author/error.rs b/core/rpc/src/author/error.rs index 769f111105aad..2fcc8c780dfdb 100644 --- a/core/rpc/src/author/error.rs +++ b/core/rpc/src/author/error.rs @@ -37,6 +37,18 @@ pub enum Error { /// Incorrect extrinsic format. #[display(fmt="Invalid extrinsic format: {}", _0)] BadFormat(codec::Error), + /// Incorrect seed phrase. + #[display(fmt="Invalid seed phrase/SURI")] + BadSeedPhrase, + /// Key type ID has an unknown format. + #[display(fmt="Invalid key type ID format (should be of length four)")] + BadKeyType, + /// Key type ID has some unsupported crypto. + #[display(fmt="The crypto of key type ID is unknown")] + UnsupportedKeyType, + /// Some random issue with the key store. Shouldn't happen. + #[display(fmt="The key store is unavailable")] + KeyStoreUnavailable, } impl std::error::Error for Error { diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index aa238aeb709d8..6a1ca0a137788 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -22,7 +22,7 @@ pub mod hash; #[cfg(test)] mod tests; -use std::sync::Arc; +use std::{sync::Arc, convert::{TryFrom, TryInto}}; use client::{self, Client}; use crate::rpc::futures::{Sink, Stream, Future}; @@ -31,9 +31,12 @@ use jsonrpc_derive::rpc; use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; use log::warn; use codec::{Encode, Decode}; -use primitives::{Bytes, Blake2Hasher, H256}; +use primitives::{ + Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Kind, Pair, Public}, + traits::{BareCryptoStore, BareCryptoStorePtr} +}; use sr_primitives::{generic, traits}; -use self::error::Result; +use self::error::{Error, Result}; use transaction_pool::{ txpool::{ ChainApi as PoolChainApi, @@ -57,21 +60,46 @@ pub trait AuthorApi { #[rpc(name = "author_submitExtrinsic")] fn submit_extrinsic(&self, extrinsic: Bytes) -> Result; + /// Insert a key into the keystore. + #[rpc(name = "author_insertKey")] + fn insert_key(&self, + key_type: String, + suri: String, + maybe_public: Option + ) -> Result; + /// Returns all pending extrinsics, potentially grouped by sender. #[rpc(name = "author_pendingExtrinsics")] fn pending_extrinsics(&self) -> Result>; /// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting. #[rpc(name = "author_removeExtrinsic")] - fn remove_extrinsic(&self, bytes_or_hash: Vec>) -> Result>; + fn remove_extrinsic(&self, + bytes_or_hash: Vec> + ) -> Result>; /// Submit an extrinsic to watch. - #[pubsub(subscription = "author_extrinsicUpdate", subscribe, name = "author_submitAndWatchExtrinsic")] - fn watch_extrinsic(&self, metadata: Self::Metadata, subscriber: Subscriber>, bytes: Bytes); + #[pubsub( + subscription = "author_extrinsicUpdate", + subscribe, + name = "author_submitAndWatchExtrinsic" + )] + fn watch_extrinsic(&self, + metadata: Self::Metadata, + subscriber: Subscriber>, + bytes: Bytes + ); /// Unsubscribe from extrinsic watching. - #[pubsub(subscription = "author_extrinsicUpdate", unsubscribe, name = "author_unwatchExtrinsic")] - fn unwatch_extrinsic(&self, metadata: Option, id: SubscriptionId) -> Result; + #[pubsub( + subscription = "author_extrinsicUpdate", + unsubscribe, + name = "author_unwatchExtrinsic" + )] + fn unwatch_extrinsic(&self, + metadata: Option, + id: SubscriptionId + ) -> Result; } /// Authoring API @@ -82,6 +110,8 @@ pub struct Author where P: PoolChainApi + Sync + Send + 'static { pool: Arc>, /// Subscriptions manager subscriptions: Subscriptions, + /// The key store. + keystore: BareCryptoStorePtr, } impl Author where P: PoolChainApi + Sync + Send + 'static { @@ -90,11 +120,13 @@ impl Author where P: PoolChainApi + Sync + Send + 'sta client: Arc::Block, RA>>, pool: Arc>, subscriptions: Subscriptions, + keystore: BareCryptoStorePtr, ) -> Self { Author { client, pool, subscriptions, + keystore, } } } @@ -105,10 +137,37 @@ impl AuthorApi, BlockHash

> for Author whe P: PoolChainApi + Sync + Send + 'static, P::Block: traits::Block, P::Error: 'static, - RA: Send + Sync + 'static + RA: Send + Sync + 'static, { type Metadata = crate::metadata::Metadata; + fn insert_key(&self, + key_type: String, + suri: String, + maybe_public: Option, + ) -> Result { + let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; + let mut keystore = self.keystore.write(); + let maybe_password = keystore.password(); + let public = match maybe_public { + Some(public) => public.0, + None => { + let crypto_kind = Kind::try_from(key_type).map_err(|_| Error::UnsupportedKeyType)?; + let maybe_public = match crypto_kind { + Kind::Sr25519 => sr25519::Pair::from_string(&suri, maybe_password) + .map(|pair| pair.public().to_raw_vec()), + Kind::Ed25519 => ed25519::Pair::from_string(&suri, maybe_password) + .map(|pair| pair.public().to_raw_vec()), + _ => Err(Error::UnsupportedKeyType)?, + }; + maybe_public.map_err(|_| Error::BadSeedPhrase)? + } + }; + keystore.insert_unknown(key_type, &suri, &public[..]) + .map_err(|_| Error::KeyStoreUnavailable)?; + Ok(public.into()) + } + fn submit_extrinsic(&self, ext: Bytes) -> Result> { let xt = Decode::decode(&mut &ext[..])?; let best_block_hash = self.client.info().chain.best_hash; @@ -124,7 +183,9 @@ impl AuthorApi, BlockHash

> for Author whe Ok(self.pool.ready().map(|tx| tx.data.encode().into()).collect()) } - fn remove_extrinsic(&self, bytes_or_hash: Vec>>) -> Result>> { + fn remove_extrinsic(&self, + bytes_or_hash: Vec>> + ) -> Result>> { let hashes = bytes_or_hash.into_iter() .map(|x| match x { hash::ExtrinsicOrHash::Hash(h) => Ok(h), @@ -143,7 +204,11 @@ impl AuthorApi, BlockHash

> for Author whe ) } - fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber, BlockHash

>>, xt: Bytes) { + fn watch_extrinsic(&self, + _metadata: Self::Metadata, + subscriber: Subscriber, BlockHash

>>, + xt: Bytes + ) { let submit = || -> Result<_> { let best_block_hash = self.client.info().chain.best_hash; let dxt = <

::Block as traits::Block>::Extrinsic::decode(&mut &xt[..])?; diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 629522082009f..dde5f39fc8f71 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -23,9 +23,12 @@ use transaction_pool::{ txpool::Pool, ChainApi, }; -use primitives::{H256, blake2_256, hexdisplay::HexDisplay}; +use primitives::{H256, blake2_256, hexdisplay::HexDisplay, traits::BareCryptoStore}; use test_client::{self, AccountKeyring, runtime::{Extrinsic, Transfer}}; use tokio::runtime; +use std::collections::HashMap; +use sr_primitives::KeyTypeId; +use parking_lot::RwLock; fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { let tx = Transfer { @@ -37,14 +40,53 @@ fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { tx.into_signed_tx() } +#[derive(Default)] +struct TestKeyStore { + keys: HashMap, String>>, +} + +impl BareCryptoStore for TestKeyStore { + fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) + -> std::result::Result<[u8; 32], String> + { + Err("unimplemented".into()) + } + fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { + None + } + fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) + -> std::result::Result<[u8; 32], String> + { + Err("unimplemented".into()) + } + fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { + None + } + + fn insert_unknown(&mut self, key_type: KeyTypeId, suri: &str, public: &[u8]) + -> std::result::Result<(), ()> + { + self.keys + .entry(key_type) + .or_default() + .insert(public.to_owned(), suri.to_owned()); + Ok(()) + } + + fn password(&self) -> Option<&str> { None } +} + #[test] fn submit_transaction_should_not_cause_error() { let runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); + let mut keystore = TestKeyStore::default(); + let keystore = Arc::new(RwLock::new(keystore)); 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 xt = uxt(AccountKeyring::Alice, 1).encode(); let h: H256 = blake2_256(&xt).into(); @@ -62,10 +104,12 @@ fn submit_transaction_should_not_cause_error() { fn submit_rich_transaction_should_not_cause_error() { let runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); + let keystore = Arc::new(RwLock::new(TestKeyStore::default())); let p = Author { client: client.clone(), pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))), subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), }; let xt = uxt(AccountKeyring::Alice, 0).encode(); let h: H256 = blake2_256(&xt).into(); @@ -85,10 +129,12 @@ fn should_watch_extrinsic() { let mut runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))); + let keystore = Arc::new(RwLock::new(TestKeyStore::default())); let p = Author { client, pool: pool.clone(), subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), }; let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test"); @@ -125,10 +171,12 @@ fn should_return_pending_extrinsics() { let runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))); + let keystore = Arc::new(RwLock::new(TestKeyStore::default())); let p = Author { client, pool: pool.clone(), subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), }; let ex = uxt(AccountKeyring::Alice, 0); AuthorApi::submit_extrinsic(&p, ex.encode().into()).unwrap(); @@ -143,10 +191,12 @@ fn should_remove_extrinsics() { let runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))); + let keystore = Arc::new(RwLock::new(TestKeyStore::default())); let p = Author { client, pool: pool.clone(), subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), }; let ex1 = uxt(AccountKeyring::Alice, 0); p.submit_extrinsic(ex1.encode().into()).unwrap(); diff --git a/core/service/src/components.rs b/core/service/src/components.rs index c4f3b8e0261b8..47781aa79d810 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -19,6 +19,7 @@ use std::{sync::Arc, ops::Deref, ops::DerefMut}; use serde::{Serialize, de::DeserializeOwned}; use crate::chain_spec::ChainSpec; +use keystore::KeyStorePtr; use client_db; use client::{self, Client, runtime_api}; use crate::{error, Service}; @@ -32,7 +33,7 @@ use sr_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256, traits::KeyStorePtr}; +use primitives::{Blake2Hasher, H256, traits::BareCryptoStorePtr}; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor}; use futures03::channel::mpsc; @@ -173,6 +174,7 @@ pub trait StartRPC { system_info: SystemInfo, task_executor: TaskExecutor, transaction_pool: Arc>, + keystore: KeyStorePtr, ) -> rpc::RpcHandler; } @@ -186,11 +188,12 @@ impl StartRPC for C where rpc_system_info: SystemInfo, task_executor: TaskExecutor, transaction_pool: Arc>, + keystore: KeyStorePtr, ) -> rpc::RpcHandler { 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); + 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, @@ -421,7 +424,7 @@ pub trait Components: Sized + 'static { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, - keystore: Option, + keystore: Option, ) -> Result< ( Arc>, @@ -508,7 +511,7 @@ impl Components for FullComponents { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, - keystore: Option, + keystore: Option, ) -> Result< (Arc>, Option>>>), error::Error, @@ -617,7 +620,7 @@ impl Components for LightComponents { fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, - _: Option, + _: Option, ) -> Result< ( diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 5c5b64f9a7468..fc2e07f616dd6 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -383,6 +383,7 @@ impl Service { system_info.clone(), Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone() }), transaction_pool.clone(), + keystore.clone(), ) }; let rpc_handlers = gen_handler(); diff --git a/core/state-db/Cargo.toml b/core/state-db/Cargo.toml index 55d66ea5f8d98..332751c927f5d 100644 --- a/core/state-db/Cargo.toml +++ b/core/state-db/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -parking_lot = "0.8.0" +parking_lot = "0.9.0" log = "0.4" primitives = { package = "substrate-primitives", path = "../../core/primitives" } codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs index a99133b481afe..85f5fa28b6369 100644 --- a/core/state-machine/src/basic.rs +++ b/core/state-machine/src/basic.rs @@ -172,7 +172,7 @@ impl Externalities for BasicExternalities where H::Out: Ord { None } - fn keystore(&self) -> Option { + fn keystore(&self) -> Option { warn!("Call to non-existent keystore."); None } diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index 088471649bb8b..f7ff649925ea2 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -22,7 +22,7 @@ use crate::backend::Backend; use crate::changes_trie::{Storage as ChangesTrieStorage, build_changes_trie}; use crate::{Externalities, OverlayedChanges, ChildStorageKey}; use hash_db::Hasher; -use primitives::{offchain, storage::well_known_keys::is_child_storage_key, traits::KeyStorePtr}; +use primitives::{offchain, storage::well_known_keys::is_child_storage_key, traits::BareCryptoStorePtr}; use trie::{MemoryDB, default_child_trie_root}; use trie::trie_types::Layout; @@ -84,7 +84,7 @@ where /// If None, some methods from the trait might not be supported. offchain_externalities: Option<&'a mut O>, /// The keystore that manages the keys of the node. - keystore: Option, + keystore: Option, /// Dummy usage of N arg. _phantom: ::std::marker::PhantomData, } @@ -104,7 +104,7 @@ where backend: &'a B, changes_trie_storage: Option<&'a T>, offchain_externalities: Option<&'a mut O>, - keystore: Option, + keystore: Option, ) -> Self { Ext { overlay, @@ -337,7 +337,7 @@ where self.offchain_externalities.as_mut().map(|x| &mut **x as _) } - fn keystore(&self) -> Option { + fn keystore(&self) -> Option { self.keystore.clone() } } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 0511fa8294dde..d1ea7b5785ab8 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -24,7 +24,8 @@ use log::warn; use hash_db::Hasher; use codec::{Decode, Encode}; use primitives::{ - storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain, traits::KeyStorePtr, + storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain, + traits::BareCryptoStorePtr, }; pub mod backend; @@ -227,7 +228,7 @@ pub trait Externalities { fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities>; /// Returns the keystore. - fn keystore(&self) -> Option; + fn keystore(&self) -> Option; } /// An implementation of offchain extensions that should never be triggered. @@ -487,7 +488,7 @@ pub fn new<'a, H, N, B, T, O, Exec>( exec: &'a Exec, method: &'a str, call_data: &'a [u8], - keystore: Option, + keystore: Option, ) -> StateMachine<'a, H, N, B, T, O, Exec> { StateMachine { backend, @@ -511,7 +512,7 @@ pub struct StateMachine<'a, H, N, B, T, O, Exec> { exec: &'a Exec, method: &'a str, call_data: &'a [u8], - keystore: Option, + keystore: Option, _hasher: PhantomData<(H, N)>, } @@ -717,7 +718,7 @@ pub fn prove_execution( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result<(Vec, Vec>), Box> where B: Backend, @@ -745,7 +746,7 @@ pub fn prove_execution_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result<(Vec, Vec>), Box> where S: trie_backend_essence::TrieBackendStorage, @@ -782,7 +783,7 @@ pub fn execution_proof_check( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result, Box> where H: Hasher, @@ -800,7 +801,7 @@ pub fn execution_proof_check_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result, Box> where H: Hasher, diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index 43c223466413e..0722eda456334 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -26,7 +26,7 @@ use crate::changes_trie::{ BlockNumber as ChangesTrieBlockNumber, }; use primitives::{ - storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}, traits::KeyStorePtr, offchain + storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}, traits::BareCryptoStorePtr, offchain }; use codec::Encode; use super::{ChildStorageKey, Externalities, OverlayedChanges}; @@ -41,7 +41,7 @@ pub struct TestExternalities { backend: InMemory, changes_trie_storage: ChangesTrieInMemoryStorage, offchain: Option>, - keystore: Option, + keystore: Option, } impl TestExternalities { @@ -267,7 +267,7 @@ impl Externalities for TestExternalities .map(|x| &mut **x as _) } - fn keystore(&self) -> Option { + fn keystore(&self) -> Option { self.keystore.clone() } } diff --git a/core/telemetry/Cargo.toml b/core/telemetry/Cargo.toml index 540305435f706..8647462739861 100644 --- a/core/telemetry/Cargo.toml +++ b/core/telemetry/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] bytes = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" futures01 = { package = "futures", version = "0.1" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } futures-timer = "0.2.1" diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index c9e1f2332a0e7..d0d4a54b0f4ae 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -30,7 +30,7 @@ pub use keyring::{ ed25519::Keyring as Ed25519Keyring, sr25519::Keyring as Sr25519Keyring, }; -pub use primitives::{Blake2Hasher, traits::KeyStorePtr}; +pub use primitives::{Blake2Hasher, traits::BareCryptoStorePtr}; pub use sr_primitives::{StorageOverlay, ChildrenStorageOverlay}; pub use state_machine::ExecutionStrategy; @@ -73,7 +73,7 @@ pub struct TestClientBuilder { child_storage_extension: HashMap, Vec<(Vec, Vec)>>, backend: Arc, _executor: std::marker::PhantomData, - keystore: Option, + keystore: Option, } impl Default for TestClientBuilder< @@ -115,7 +115,7 @@ impl TestClientBuilder } /// Set the keystore that should be used by the externalities. - pub fn set_keystore(mut self, keystore: KeyStorePtr) -> Self { + pub fn set_keystore(mut self, keystore: BareCryptoStorePtr) -> Self { self.keystore = Some(keystore); self } diff --git a/core/transaction-pool/Cargo.toml b/core/transaction-pool/Cargo.toml index c18a50778df64..747c39a16566a 100644 --- a/core/transaction-pool/Cargo.toml +++ b/core/transaction-pool/Cargo.toml @@ -9,7 +9,7 @@ derive_more = "0.14.0" futures = "0.1" log = "0.4" codec = { package = "parity-scale-codec", version = "1.0.0" } -parking_lot = "0.8.0" +parking_lot = "0.9.0" sr-primitives = { path = "../sr-primitives" } client = { package = "substrate-client", path = "../client" } primitives = { package = "substrate-primitives", path = "../primitives" } diff --git a/core/transaction-pool/graph/Cargo.toml b/core/transaction-pool/graph/Cargo.toml index 8010b07ac4aad..4dc7ce69cffe9 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" derive_more = "0.14.0" futures = "0.1" log = "0.4" -parking_lot = "0.8.0" +parking_lot = "0.9.0" serde = { version = "1.0", features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../primitives" } sr-primitives = { path = "../../sr-primitives" } diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index dbe00a23116fe..4112452b2722f 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -16,7 +16,7 @@ ctrlc = { version = "3.0", features = ["termination"] } log = "0.4" tokio = "0.1" exit-future = "0.1" -parking_lot = "0.8.0" +parking_lot = "0.9.0" codec = { package = "parity-scale-codec", version = "1.0.0" } trie-root = "0.15.0" sr-io = { path = "../core/sr-io" } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 84e5d4ab03509..86247668f7550 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -320,7 +320,7 @@ mod tests { fn test_sync() { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore"); - let alice = keystore.write().generate_from_seed::("//Alice") + let alice = keystore.write().insert_ephemeral_from_seed::("//Alice") .expect("Creates authority pair"); let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); diff --git a/srml/aura/Cargo.toml b/srml/aura/Cargo.toml index 3baeccb347c3d..955831ba29910 100644 --- a/srml/aura/Cargo.toml +++ b/srml/aura/Cargo.toml @@ -21,7 +21,7 @@ substrate-consensus-aura-primitives = { path = "../../core/consensus/aura/primit [dev-dependencies] lazy_static = "1.0" -parking_lot = "0.8.0" +parking_lot = "0.9.0" runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] From 301d40bf97b6c5a264d15b1e9d356900dc402d69 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 18:56:46 +0200 Subject: [PATCH 73/80] Bad merge --- core/primitives/src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index bf439fafa0fef..6fa84088db710 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -69,4 +69,4 @@ pub trait BareCryptoStore: Send + Sync { /// A pointer to the key store. #[cfg(feature = "std")] -pub type BareCryptoStorePtr = std::sync::Arc>; +pub type BareCryptoStorePtr = std::sync::Arc>; From 4bf2c3f395af1deda507df3c3c3875375c9d44cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 7 Aug 2019 18:58:40 +0200 Subject: [PATCH 74/80] Fix integration tests --- core/service/test/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 43ea7a1c010f2..b9f05af2c7fa1 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -135,10 +135,6 @@ fn node_config ( ) -> FactoryFullConfiguration { let root = root.path().join(format!("node-{}", index)); - let mut keys = Vec::new(); - if let Some(seed) = key_seed { - keys.push(seed); - } let config_path = Some(String::from(root.join("network").to_str().unwrap())); let net_config_path = config_path.clone(); @@ -195,7 +191,7 @@ fn node_config ( force_authoring: false, disable_grandpa: false, grandpa_voter: false, - dev_key_seed: None, + dev_key_seed: key_seed, } } From e0e90dd3b3e717f54caf26397a1208405f8ba04c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 19:44:01 +0200 Subject: [PATCH 75/80] Fix test build --- core/application-crypto/src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index 790ae7f271c78..6c5458492b6b8 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -53,7 +53,7 @@ impl RuntimePublic for Public { #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{testing::KeyStore, crypto::Pair, traits::KeyStore as _}; + use primitives::{testing::KeyStore, crypto::Pair, traits::BareCryptoStore as _}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, runtime::{TestAPI, app_crypto::ed25519::{AppPair, AppPublic}}, @@ -72,4 +72,4 @@ mod tests { assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(key_pair.public()))); } -} \ No newline at end of file +} From 2ab31c854d60cb51c7aee8c68d1dff1986542378 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 19:49:09 +0200 Subject: [PATCH 76/80] Test fix --- core/application-crypto/src/sr25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 3cc9322158906..af112dc70ee7e 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -53,7 +53,7 @@ impl RuntimePublic for Public { #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{testing::KeyStore, crypto::Pair, traits::KeyStore as _}; + use primitives::{testing::KeyStore, crypto::Pair, traits::BareCryptoStore as _}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, runtime::{TestAPI, app_crypto::sr25519::{AppPair, AppPublic}}, @@ -72,4 +72,4 @@ mod tests { assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(key_pair.public()))); } -} \ No newline at end of file +} From 7bd33d02a6386e2d95c67692ac54316fd5a9535b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 19:59:12 +0200 Subject: [PATCH 77/80] Fixes --- core/rpc/src/author/mod.rs | 17 +++++++++-------- core/rpc/src/author/tests.rs | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index 6a1ca0a137788..a6362fa433436 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -22,7 +22,7 @@ pub mod hash; #[cfg(test)] mod tests; -use std::{sync::Arc, convert::{TryFrom, TryInto}}; +use std::{sync::Arc, convert::TryInto}; use client::{self, Client}; use crate::rpc::futures::{Sink, Stream, Future}; @@ -32,7 +32,7 @@ use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; use log::warn; use codec::{Encode, Decode}; use primitives::{ - Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Kind, Pair, Public}, + Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Pair, Public, key_types}, traits::{BareCryptoStore, BareCryptoStorePtr} }; use sr_primitives::{generic, traits}; @@ -152,12 +152,13 @@ impl AuthorApi, BlockHash

> for Author whe let public = match maybe_public { Some(public) => public.0, None => { - let crypto_kind = Kind::try_from(key_type).map_err(|_| Error::UnsupportedKeyType)?; - let maybe_public = match crypto_kind { - Kind::Sr25519 => sr25519::Pair::from_string(&suri, maybe_password) - .map(|pair| pair.public().to_raw_vec()), - Kind::Ed25519 => ed25519::Pair::from_string(&suri, maybe_password) - .map(|pair| pair.public().to_raw_vec()), + let maybe_public = match key_type { + key_types::BABE | key_types::IM_ONLINE | key_types::SR25519 => + sr25519::Pair::from_string(&suri, maybe_password) + .map(|pair| pair.public().to_raw_vec()), + key_types::GRANDPA | key_types::ED25519 => + ed25519::Pair::from_string(&suri, maybe_password) + .map(|pair| pair.public().to_raw_vec()), _ => Err(Error::UnsupportedKeyType)?, }; maybe_public.map_err(|_| Error::BadSeedPhrase)? diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index dde5f39fc8f71..7f5069f5210f4 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -46,16 +46,18 @@ struct TestKeyStore { } impl BareCryptoStore for TestKeyStore { + fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { vec![] } fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) - -> std::result::Result<[u8; 32], String> + -> std::result::Result { Err("unimplemented".into()) } fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { None } + fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { vec![] } fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) - -> std::result::Result<[u8; 32], String> + -> std::result::Result { Err("unimplemented".into()) } From 2afad01262184dff65987d6d7605273ad7048935 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 20:00:41 +0200 Subject: [PATCH 78/80] Warnings --- core/rpc/src/author/mod.rs | 2 +- core/rpc/src/author/tests.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index a6362fa433436..226fd2b105cbe 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -33,7 +33,7 @@ use log::warn; use codec::{Encode, Decode}; use primitives::{ Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Pair, Public, key_types}, - traits::{BareCryptoStore, BareCryptoStorePtr} + traits::BareCryptoStorePtr }; use sr_primitives::{generic, traits}; use self::error::{Error, Result}; diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 7f5069f5210f4..f942fd9e95720 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -46,22 +46,22 @@ struct TestKeyStore { } impl BareCryptoStore for TestKeyStore { - fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { vec![] } - fn sr25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) + fn sr25519_public_keys(&self, _id: KeyTypeId) -> Vec { vec![] } + fn sr25519_generate_new(&mut self, _id: KeyTypeId, _seed: Option<&str>) -> std::result::Result { Err("unimplemented".into()) } - fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { + fn sr25519_key_pair(&self, _id: KeyTypeId, _pub_key: &sr25519::Public) -> Option { None } - fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { vec![] } - fn ed25519_generate_new(&mut self, id: KeyTypeId, seed: Option<&str>) + fn ed25519_public_keys(&self, _id: KeyTypeId) -> Vec { vec![] } + fn ed25519_generate_new(&mut self, _id: KeyTypeId, _seed: Option<&str>) -> std::result::Result { Err("unimplemented".into()) } - fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { + fn ed25519_key_pair(&self, _id: KeyTypeId, _pub_key: &ed25519::Public) -> Option { None } From f2e676ce5234489442a2b873e7c573131968d2eb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 20:01:06 +0200 Subject: [PATCH 79/80] Another warning --- core/rpc/src/author/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index f942fd9e95720..93c39a4bc5a70 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -82,7 +82,7 @@ impl BareCryptoStore for TestKeyStore { fn submit_transaction_should_not_cause_error() { let runtime = runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::new()); - let mut keystore = TestKeyStore::default(); + let keystore = TestKeyStore::default(); let keystore = Arc::new(RwLock::new(keystore)); let p = Author { client: client.clone(), From c9c1b3bc88cc289425c448180d399f5f98a53613 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Aug 2019 20:33:00 +0200 Subject: [PATCH 80/80] Bump version. --- node/runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a0fd1903fc546..0ecbec76018a6 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -80,8 +80,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 130, - impl_version: 130, + spec_version: 131, + impl_version: 131, apis: RUNTIME_API_VERSIONS, };

, P: Pair + Send + Sync + 'static, diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index c131bf2e95692..e23132dbd84ec 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -1209,7 +1209,7 @@ pub mod test_helpers { client: &C, at: &BlockId, slot_number: u64, - key: &sr25519::Pair, + key: &AuthorityPair, c: (u64, u64), ) -> Option where B: BlockT, diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index b32497e1e6eab..9ae42fa2649d5 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -23,7 +23,9 @@ use std::path::PathBuf; use std::fs::{self, File}; use std::io::{self, Write}; -use substrate_primitives::crypto::{KeyTypeId, AppPublic, AppPair, Pair, Public, IsWrappedBy}; +use substrate_primitives::crypto::{ + KeyTypeId, AppPublic, AppKey, AppPair, Pair, Public, IsWrappedBy +}; /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] @@ -142,7 +144,7 @@ impl Store { /// Load a key file with given public key. pub fn load< Pair_: AppPair - >(&self, public: &Pair_::Public, password: &str) -> Result { + >(&self, public: &::Public, password: &str) -> Result { self.load_by_type::(IsWrappedBy::from_ref(public), password, Pair_::ID) .map(Into::into) } diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 6fd793a841895..796426a4ebe6d 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -44,6 +44,7 @@ test-client = { package = "substrate-test-runtime-client", path = "../../core/te erased-serde = "0.3.9" void = "1.0" zeroize = "0.9.0" +babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } [dev-dependencies] env_logger = { version = "0.6" } diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index 8f9fe7d097277..1a54a8ece77a5 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -57,7 +57,7 @@ use test_client::{self, AccountKeyring}; pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer}; pub use test_client::TestClient; -type AuthorityId = primitives::sr25519::Public; +type AuthorityId = babe_primitives::AuthorityId; #[cfg(any(test, feature = "test-helpers"))] /// A Verifier that accepts all blocks and passes them on with the configured diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 4348295aaba77..fe2612265bb1d 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -24,7 +24,7 @@ use std::convert::{TryFrom, TryInto}; use parking_lot::Mutex; #[cfg(feature = "std")] use rand::{RngCore, rngs::OsRng}; -use parity_codec::{Encode, Decode}; +use parity_codec::{Encode, Decode, Codec}; #[cfg(feature = "std")] use regex::Regex; #[cfg(feature = "std")] @@ -767,13 +767,14 @@ impl MaybeDebugHash for T {} pub trait MaybeDebugHash {} /// A application's public key. -pub trait AppPublic: AppKey + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash { +pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec { /// The wrapped type which is just a plain instance of `Public`. - type Generic: IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash; + type Generic: + IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec; } /// A application's public key. -pub trait AppPair: AppKey { +pub trait AppPair: AppKey + Pair::Public> { /// The wrapped type which is just a plain instance of `Pair`. type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; } @@ -1050,6 +1051,9 @@ pub type KeyTypeId = [u8; 4]; /// Known key types; this also functions as a global registry of key types for projects wishing to /// avoid collisions with each other. +/// +/// It's not universal in the sense that *all* key types need to be mentioned here, it's just a +/// handy place to put common key types. pub mod key_types { use super::KeyTypeId; @@ -1057,18 +1061,20 @@ pub mod key_types { pub const SR25519: KeyTypeId = *b"sr25"; /// Key type for generic Ed25519 key. pub const ED25519: KeyTypeId = *b"ed25"; - /// Key type for Aura module, build-in. - pub const AURA: KeyTypeId = *b"aura"; /// Key type for Babe module, build-in. pub const BABE: KeyTypeId = *b"babe"; /// Key type for Grandpa module, build-in. pub const GRANDPA: KeyTypeId = *b"gran"; + /// Key type for controlling an account in a Substrate runtime, built-in. + pub const ACCOUNT: KeyTypeId = *b"acco"; + /// Key type for Aura module, built-in. + pub const AURA: KeyTypeId = *b"acco"; /// A key type ID useful for tests. #[cfg(feature = "std")] pub const DUMMY: KeyTypeId = *b"dumy"; } -impl TryFrom for Kind { +/*impl TryFrom for Kind { type Error = (); fn try_from(kind: KeyTypeId) -> Result { @@ -1096,7 +1102,7 @@ impl TryFrom for KeyTypeId { Kind::Dummy => key_types::DUMMY, }) } -} +}*/ #[cfg(test)] mod tests { diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 08a4f0772b29d..5f88fcaa3eeaf 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -41,9 +41,9 @@ use keystore::Store as Keystore; use network::{NetworkState, NetworkStateInfo}; use log::{log, info, warn, debug, error, Level}; use parity_codec::{Encode, Decode}; -use primitives::{crypto::{self, AppPair}}; +use primitives::{crypto::{self, AppKey, AppPair}}; use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion}; +use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero}; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -172,7 +172,7 @@ impl Service { // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let mut keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { + let keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { match Keystore::open(keystore_path.clone()) { Ok(ks) => Some(ks), Err(err) => { @@ -506,7 +506,7 @@ impl Service { _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), }) } -/* + /// give the authority key, if we are an authority and have a key pub fn authority_key(&self) -> Option> { use offchain::AuthorityKeyProvider; @@ -520,7 +520,7 @@ impl Service { self.keystore.fg_authority_key(&BlockId::Number(Zero::zero())) } -*/ + /// return a shared instance of Telemetry (if enabled) pub fn telemetry(&self) -> Option { self._telemetry.as_ref().map(|t| t.clone()) @@ -926,10 +926,10 @@ where ConsensusPair: AppPair, FinalityPair: AppPair, { - type ConsensusPair = ConsensusPair::Generic; - type FinalityPair = FinalityPair::Generic; + type ConsensusPair = ConsensusPair; + type FinalityPair = FinalityPair; - fn authority_key(&self, _at: &BlockId) -> Option { + fn authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { return None } @@ -940,11 +940,10 @@ where }; let loaded_key = keystore - .contents::() + .contents::<::Public>() .map(|keys| keys.get(0) .map(|k| keystore.load::(k, self.password.as_ref()) - .map(Into::into) ) ); @@ -955,7 +954,7 @@ where } } - fn fg_authority_key(&self, _at: &BlockId) -> Option { + fn fg_authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { return None } @@ -966,11 +965,10 @@ where }; let loaded_key = keystore - .contents::() + .contents::<::Public>() .map(|keys| keys.get(0) .map(|k| keystore.load::(k, self.password.as_ref()) - .map(Into::into) ) ); diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index 4383a80e68cab..9752bbeb17a1a 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -26,6 +26,7 @@ pub use block_builder_ext::BlockBuilderExt; pub use generic_test_client::*; pub use runtime; +use primitives::sr25519; use runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash as HashT}; @@ -183,9 +184,9 @@ fn genesis_config(support_changes_trie: bool, heap_pages_override: Option) GenesisConfig::new( support_changes_trie, vec![ - Sr25519Keyring::Alice.into(), - Sr25519Keyring::Bob.into(), - Sr25519Keyring::Charlie.into(), + sr25519::Public::from(Sr25519Keyring::Alice).into(), + sr25519::Public::from(Sr25519Keyring::Bob).into(), + sr25519::Public::from(Sr25519Keyring::Charlie).into(), ], vec![ AccountKeyring::Alice.into(), AccountKeyring::Bob.into(), diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index 4c85ef38174ca..1ac994188b6f7 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -28,6 +28,8 @@ inherents = { package = "substrate-inherents", path = "../core/inherents" } transaction-pool = { package = "substrate-transaction-pool", path = "../core/transaction-pool" } network = { package = "substrate-network", path = "../core/network" } consensus = { package = "substrate-consensus-aura", path = "../core/consensus/aura" } +aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../core/consensus/aura/primitives" } +grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../core/finality-grandpa/primitives" } substrate-client = { path = "../core/client" } basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" } node-template-runtime = { path = "runtime" } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index aa9a017add62b..50b4d18b417a1 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -9,7 +9,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use rstd::prelude::*; -use primitives::{ed25519, sr25519, OpaqueMetadata}; +use primitives::{sr25519, OpaqueMetadata}; use sr_primitives::{ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str}; use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; @@ -30,10 +30,10 @@ pub use sr_primitives::{Permill, Perbill}; pub use support::{StorageValue, construct_runtime, parameter_types}; /// Alias to the signature scheme used for Aura authority signatures. -pub type AuraSignature = ed25519::Signature; +pub type AuraSignature = consensus_aura::sr25519::AuthoritySignature; /// The Ed25519 pub key of an session that belongs to an Aura authority of the chain. -pub type AuraId = ed25519::Public; +pub type AuraId = consensus_aura::sr25519::AuthorityId; /// Alias to pubkey that identifies an account on the chain. pub type AccountId = ::Signer; diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index 3970522b37ab5..65caab70dbe5f 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,8 +1,9 @@ -use primitives::{ed25519, sr25519, Pair}; +use primitives::{sr25519, Pair}; use node_template_runtime::{ AccountId, GenesisConfig, AuraConfig, BalancesConfig, SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, AuraId }; +use aura_primitives::sr25519::AuthorityPair as AuraPair; use substrate_service; // Note this is the URL for the telemetry server @@ -23,7 +24,7 @@ pub enum Alternative { } fn authority_key(s: &str) -> AuraId { - ed25519::Pair::from_string(&format!("//{}", s), None) + AuraPair::from_string(&format!("//{}", s), None) .expect("static values are valid; qed") .public() } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 2a981c3bcc348..bf6910b505064 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -15,7 +15,7 @@ use basic_authorship::ProposerFactory; use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration}; use futures::prelude::*; use substrate_client::{self as client, LongestChain}; -use primitives::{ed25519::Pair, Pair as PairT}; +use primitives::{Pair as PairT}; use inherents::InherentDataProviders; use network::{config::DummyFinalityProofRequestBuilder, construct_simple_protocol}; use substrate_executor::native_executor_instance; @@ -43,8 +43,8 @@ construct_simple_protocol! { construct_service_factory! { struct Factory { Block = Block, - ConsensusPair = Pair, - FinalityPair = Pair, + ConsensusPair = aura_primitives::sr25519::AuthorityPair, + FinalityPair = grandpa_primitives::AuthorityPair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = Executor, @@ -100,7 +100,7 @@ construct_service_factory! { Self::Block, > { |config: &mut FactoryFullConfiguration , client: Arc>, _select_chain: Self::SelectChain| { - import_queue::<_, _, Pair>( + import_queue::<_, _, aura_primitives::sr25519::AuthorityPair>( SlotDuration::get_or_compute(&*client)?, Box::new(client.clone()), None, @@ -115,7 +115,7 @@ construct_service_factory! { > { |config: &mut FactoryFullConfiguration, client: Arc>| { let fprb = Box::new(DummyFinalityProofRequestBuilder::default()) as Box<_>; - import_queue::<_, _, Pair>( + import_queue::<_, _, aura_primitives::sr25519::AuthorityPair>( SlotDuration::get_or_compute(&*client)?, Box::new(client.clone()), None, diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index a0f7ad6242429..2392a1d7d968b 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -53,8 +53,9 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; +use substrate_primitives::crypto::AppPublic; use primitives::{ - traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember, TypedKey}, + traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember}, generic::DigestItem, }; use timestamp::OnTimestampSet; @@ -156,7 +157,7 @@ pub trait Trait: timestamp::Trait { type HandleReport: HandleReport; /// The identifier type for an authority. - type AuthorityId: Member + Parameter + TypedKey + Default; + type AuthorityId: Member + Parameter + AppPublic + Default; } decl_storage! { From c9bb7d4b4e0a604e9b8c011a33db131bec2ae70f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Jul 2019 01:50:11 +0800 Subject: [PATCH 11/80] Introduce authority determinator for Babe. Experiment with modular consensus API. --- Cargo.lock | 1 + core/client/src/client.rs | 89 +++++++++++------------- core/consensus/babe/Cargo.toml | 11 +-- core/consensus/babe/src/lib.rs | 121 +++++++++++++++++++++++++++++++-- core/primitives/src/crypto.rs | 4 +- 5 files changed, 167 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a951d5da7bb41..dcb615fc199d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4349,6 +4349,7 @@ dependencies = [ "substrate-executor 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", diff --git a/core/client/src/client.rs b/core/client/src/client.rs index c572c39a73677..498c2c104d54b 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -20,67 +20,60 @@ use std::{ marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc, panic::UnwindSafe, result, cell::RefCell, rc::Rc, }; -use crate::error::Error; +use log::{info, trace, warn}; use futures::channel::mpsc; use parking_lot::{Mutex, RwLock}; -use primitives::NativeOrEncoded; -use runtime_primitives::{ - Justification, - generic::{BlockId, SignedBlock}, -}; -use consensus::{ - Error as ConsensusError, BlockImportParams, - ImportResult, BlockOrigin, ForkChoiceStrategy, - well_known_cache_keys::Id as CacheKeyId, - SelectChain, self, -}; -use runtime_primitives::traits::{ - Block as BlockT, Header as HeaderT, Zero, NumberFor, CurrentHeight, - BlockNumberToHash, ApiRef, ProvideRuntimeApi, - SaturatedConversion, One, DigestFor, -}; -use runtime_primitives::generic::DigestItem; -use runtime_primitives::BuildStorage; -use crate::runtime_api::{ - CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder, - InitializeBlock, -}; +use parity_codec::{Encode, Decode}; +use hash_db::Hasher; use primitives::{ Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, - NeverNativeValue, ExecutionContext + NeverNativeValue, ExecutionContext, + storage::{StorageKey, StorageData, well_known_keys}, NativeOrEncoded +}; +use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; +use runtime_primitives::{ + Justification, BuildStorage, + generic::{BlockId, SignedBlock, DigestItem}, + traits::{ + Block as BlockT, Header as HeaderT, Zero, NumberFor, CurrentHeight, + BlockNumberToHash, ApiRef, ProvideRuntimeApi, + SaturatedConversion, One, DigestFor, + }, }; -use primitives::storage::{StorageKey, StorageData}; -use primitives::storage::well_known_keys; -use parity_codec::{Encode, Decode}; use state_machine::{ DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage, key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt, }; -use hash_db::Hasher; - -use crate::backend::{ - self, BlockImportOperation, PrunableStateChangesTrieStorage, - StorageCollection, ChildStorageCollection -}; -use crate::blockchain::{ - self, Info as ChainInfo, Backend as ChainBackend, - HeaderBackend as ChainHeaderBackend, ProvideCache, Cache, -}; -use crate::call_executor::{CallExecutor, LocalCallExecutor}; use executor::{RuntimeVersion, RuntimeInfo}; -use crate::notifications::{StorageNotifications, StorageEventStream}; -use crate::light::{call_executor::prove_execution, fetcher::ChangesProof}; -use crate::cht; -use crate::error; -use crate::in_mem; -use crate::block_builder::{self, api::BlockBuilder as BlockBuilderAPI}; -use crate::genesis; -use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; - -use log::{info, trace, warn}; +use consensus::{ + Error as ConsensusError, BlockImportParams, + ImportResult, BlockOrigin, ForkChoiceStrategy, + well_known_cache_keys::Id as CacheKeyId, + SelectChain, self, +}; +use crate::{ + runtime_api::{ + CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder, + InitializeBlock, + }, + backend::{ + self, BlockImportOperation, PrunableStateChangesTrieStorage, + StorageCollection, ChildStorageCollection + }, + blockchain::{ + self, Info as ChainInfo, Backend as ChainBackend, + HeaderBackend as ChainHeaderBackend, ProvideCache, Cache, + }, + call_executor::{CallExecutor, LocalCallExecutor}, + notifications::{StorageNotifications, StorageEventStream}, + light::{call_executor::prove_execution, fetcher::ChangesProof}, + block_builder::{self, api::BlockBuilder as BlockBuilderAPI}, + error::Error, + cht, error, in_mem, genesis +}; /// Type that implements `futures::Stream` of block import events. pub type ImportNotifications = mpsc::UnboundedReceiver>; diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index deb716a7ffee6..fdfc21d9c03e8 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -12,16 +12,17 @@ primitives = { package = "substrate-primitives", path = "../../primitives" } num-bigint = "0.2" num-rational = "0.2" num-traits = "0.2" -runtime_support = { package = "srml-support", path = "../../../srml/support" } -runtime_version = { package = "sr-version", path = "../../sr-version" } -runtime_io = { package = "sr-io", path = "../../sr-io" } +runtime-support = { package = "srml-support", path = "../../../srml/support" } +runtime-version = { package = "sr-version", path = "../../sr-version" } +runtime-io = { package = "sr-io", path = "../../sr-io" } inherents = { package = "substrate-inherents", path = "../../inherents" } substrate-telemetry = { path = "../../telemetry" } +substrate-keystore = { path = "../../keystore" } srml-babe = { path = "../../../srml/babe" } client = { package = "substrate-client", path = "../../client" } -consensus_common = { package = "substrate-consensus-common", path = "../common" } +consensus-common = { package = "substrate-consensus-common", path = "../common" } slots = { package = "substrate-consensus-slots", path = "../slots" } -runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" } +runtime-primitives = { package = "sr-primitives", path = "../../sr-primitives" } fork-tree = { path = "../../utils/fork-tree" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } futures01 = { package = "futures", version = "0.1" } diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index e23132dbd84ec..0674bbad22b66 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -18,10 +18,11 @@ //! //! BABE (Blind Assignment for Blockchain Extension) consensus in Substrate. -#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)] -#![cfg_attr(not(test), forbid(dead_code))] +//#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)] +//#![cfg_attr(not(test), forbid(dead_code))] pub use babe_primitives::*; pub use consensus_common::SyncOracle; +use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}}; use babe_primitives; use consensus_common::ImportResult; use consensus_common::import_queue::{ @@ -33,7 +34,7 @@ use runtime_primitives::traits::{ Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi, SimpleBitOps, Zero, }; -use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}}; +use substrate_keystore::Store; use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; use parking_lot::{Mutex, MutexGuard}; @@ -66,8 +67,7 @@ use consensus_common::import_queue::{Verifier, BasicQueue}; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, blockchain::{self, HeaderBackend, ProvideCache}, - BlockchainEvents, - CallExecutor, Client, + BlockchainEvents, BlockOf, CallExecutor, Client, runtime_api::ApiExt, error::Result as ClientResult, backend::{AuxStore, Backend}, @@ -1198,6 +1198,117 @@ pub fn import_queue, I, RA, PRA>( Ok((queue, timestamp_core, block_import, pruning_task)) } +/// Provide a list of authority keys that is current as of a given block. +#[allow(deprecated)] +fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result, ConsensusError> +where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: BabeApi<::Type> +{ + client + .cache() + .and_then(|cache| cache + .get_at(&well_known_cache_keys::AUTHORITIES, at) + .and_then(|v| Decode::decode(&mut &v[..])) + ) + .or_else(|| BabeApi::epoch(&*client.runtime_api(), at).ok() + .map(|epoch| epoch.authorities.into_iter().map(|x| x.0).collect()) + ) + .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) +} + +/// Provide the authority key, if any, that is controlled by this node as of the given block. +fn authority(client: &C, keystore: Arc) -> Option where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: BabeApi<::Type> +{ + let owned = keystore.contents::().ok()?; + let at = BlockId::Number(client.info().best_number); + /// The list of authority keys that is current. By default this will just use the state of + /// the best block, but you might want it to use some other block's state instead if it's + /// more sophisticated. Grandpa, for example, will probably want to use the state of the last + /// finalised block. + let authorities = authorities_at::(client, &at).ok()?; + let maybe_pub = owned.into_iter() + .find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.load(&public, "").ok()) +} + +/// Type of source for block sealing. Different consensus algorithms have different sealing +/// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. +pub trait SealingSource { + /// Human-readable description of this general class. + /// + /// e.g. `"ProgPoW"`, `"S/R 25519 Key"`. + const SEALER_TYPE: &'static str; + /// Human-readable description of this specific instance. + /// + /// e.g. `"OpenCL GPU Radeon 8970 @ slot 1"`, `"5Gav1mbbo348grBREHTYgevvf4Gfe5GFE4"`. + fn format(&self) -> String; +} + +impl SealingSource for T { + const SEALER_TYPE: &'static str = "Key"; + fn format(&self) -> String { use primitives::crypto::Ss58Codec; self.to_ss58check() } +} + +/// A runtime service for a consensus worker. +/// +/// This is administered by the client service to help it spin up everything necessary. It can +/// provide API hooks for handling user-level/RPC events. It can return information regarding +/// the status of the service. +pub trait Service<'a>: 'a { + /// Instance of the source of sealing. Different consensus algorithms have different sealing + /// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. + type Sealer: SealingSource; + + /// The Client type. Different services can make different constraints on this. + type Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>; + + /// Initialize the consensus service. + fn initialize(client: &'a Self::Client, keystore: Arc) -> Self; + + /// Return status of the authoring/sealing instance. For PoA/PoS consensus mechanisms, this + /// will just be a public key. For PoW mechanisms, this could be the miner instance. + fn sealer(&self) -> Option; +} + +/// The Babe consensus service struct. This can be passed in to the main service as (one of) the +/// consensus modules if your chain uses Babe block production. +pub struct BabeService<'a, Client> where + Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + Client::Api: BabeApi<::Type>, +{ + /// The main client that lets us interact with the chain/state. + client: &'a Client, + /// The keystore. + keystore: Arc, +} + +impl<'a, Client> Service<'a> for BabeService<'a, Client> where + Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + Client::Api: BabeApi<::Type> +{ + type Sealer = AuthorityId; + type Client = Client; + + fn initialize(client: &'a Self::Client, keystore: Arc) -> Self { + // TODO: Put in any default/test keys into the keystore. + // TODO: Actually initialise the babe worker. + Self { client, keystore } + } + + fn sealer(&self) -> Option { + authority(self.client, self.keystore.clone()) + .map(|p| p.public()) + } +} + /// BABE test helpers. Utility methods for manually authoring blocks. #[cfg(feature = "test-helpers")] pub mod test_helpers { diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index fe2612265bb1d..6685479547155 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -456,7 +456,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } /// Trait suitable for typical cryptographic PKI key public type. -pub trait Public: AsRef<[u8]> + CryptoType + PartialEq + Eq + Clone + Send + Sync { +pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync { /// A new instance from the given slice that should be 32 bytes long. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if @@ -493,6 +493,8 @@ impl CryptoType for Dummy { type Pair = Dummy; } +impl Derive for Dummy {} + /// Trait suitable for typical cryptographic PKI key public type. impl Public for Dummy { fn from_slice(_: &[u8]) -> Self { Self } From b1eae508fbc17da0f99961ecccdff9efe08c39ee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Jul 2019 22:25:19 +0800 Subject: [PATCH 12/80] Work in progress to introduce KeyTypeId and avoid polluting API with validator IDs --- core/executor/src/wasm_executor.rs | 6 +- core/offchain/src/api.rs | 110 ++------ core/offchain/src/testing.rs | 3 +- core/primitives/src/crypto.rs | 41 ++- core/primitives/src/offchain.rs | 47 +--- core/sr-io/src/lib.rs | 9 +- core/sr-io/with_std.rs | 5 +- core/sr-io/without_std.rs | 13 +- core/state-machine/src/lib.rs | 1 + node/runtime/src/lib.rs | 7 +- srml/im-online/src/lib.rs | 403 +++++++++++++---------------- 11 files changed, 279 insertions(+), 366 deletions(-) diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 1b82b97d76871..e690384e9eb1d 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -711,12 +711,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(if res.is_ok() { 0 } else { 1 }) }, - ext_new_crypto_key(crypto: u32) -> u64 => { + ext_new_crypto_key(crypto: u32, app: u32) -> u64 => { let kind = offchain::CryptoKind::try_from(crypto) .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; + let key_type = offchain::KeyType::try_from(app) + .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; let res = this.ext.offchain() - .map(|api| api.new_crypto_key(kind)) + .map(|api| api.new_crypto_key(kind, key_type)) .ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?; match res { diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 6d9ad678e12e5..2681f3f0e113e 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -57,8 +57,8 @@ struct StoredKey { } impl StoredKey { - fn generate_with_phrase(kind: CryptoKind, password: Option<&str>) -> Self { - match kind { + fn generate_with_phrase(kind: CryptoKind, password: Option<&str>) -> Option { + Ok(match kind { CryptoKind::Ed25519 => { let phrase = ed25519::Pair::generate_with_phrase(password).1; Self { kind, phrase } @@ -68,7 +68,8 @@ impl StoredKey { Self { kind, phrase } } CryptoKind::Dummy => Self { kind, phrase: String::new() }, - } + CryptoKind::User => return None, + }) } fn to_local_key(&self, password: Option<&str>) -> Result { @@ -81,7 +82,7 @@ impl StoredKey { sr25519::Pair::from_phrase(&self.phrase, password) .map(|x| LocalKey::Sr25519(x.0)) } - CryptoKind::Dummy => Err(())?, + _ => Err(())?, } .map_err(|e| { warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); @@ -130,57 +131,6 @@ impl LocalKey { } } -/// A key. -enum Key { - LocalKey(LocalKey), - AuthorityKey(ConsensusPair), - FgAuthorityKey(FinalityPair), -} - -impl Key { - fn public(&self) -> Result, ()> { - match self { - Key::LocalKey(local) => { - local.public() - } - Key::AuthorityKey(pair) => { - Ok(pair.public().to_raw_vec()) - } - Key::FgAuthorityKey(pair) => { - Ok(pair.public().to_raw_vec()) - } - } - } - - fn sign(&self, data: &[u8]) -> Result, ()> { - match self { - Key::LocalKey(local) => { - local.sign(data) - } - Key::AuthorityKey(pair) => { - Ok(pair.sign(data).as_ref().to_vec()) - } - Key::FgAuthorityKey(pair) => { - Ok(pair.sign(data).as_ref().to_vec()) - } - } - } - - fn verify(&self, msg: &[u8], signature: &[u8]) -> Result { - match self { - Key::LocalKey(local) => { - local.verify(msg, signature) - } - Key::AuthorityKey(pair) => { - Ok(ConsensusPair::verify_weak(signature, msg, pair.public())) - } - Key::FgAuthorityKey(pair) => { - Ok(FinalityPair::verify_weak(signature, msg, pair.public())) - } - } - } -} - /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). @@ -217,36 +167,21 @@ impl Api where fn read_key( &self, key: CryptoKey, - ) -> Result, ()> { - match key { - CryptoKey::LocalKey { id, kind } => { - let key = self.db.get(KEYS_PREFIX, &id.encode()) - .and_then(|key| StoredKey::decode(&mut &*key)) - .ok_or(())?; - if key.kind != kind { - warn!( - "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", - key.kind, - kind, - id - ); - return Err(()) - } - Ok(Key::LocalKey(key.to_local_key(self.password())?)) - } - CryptoKey::AuthorityKey => { - let key = self.key_provider - .authority_key(&self.at) - .ok_or(())?; - Ok(Key::AuthorityKey(key)) - } - CryptoKey::FgAuthorityKey => { - let key = self.key_provider - .fg_authority_key(&self.at) - .ok_or(())?; - Ok(Key::FgAuthorityKey(key)) - } + ) -> Result { + let CryptoKey { id, kind } = key; + let key = id.using_encoded(|id| self.db.get(KEYS_PREFIX, id)) + .and_then(|key| StoredKey::decode(&mut &*key)) + .ok_or(())?; + if key.kind != kind { + warn!( + "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", + key.kind, + kind, + id + ); + return Err(()) } + Ok(key.to_local_key(self.password())?) } } @@ -263,8 +198,8 @@ where .map_err(|_| ()) } - fn new_crypto_key(&mut self, kind: CryptoKind) -> Result { - let key = StoredKey::generate_with_phrase(kind, self.password()); + fn new_crypto_key(&mut self, crypto: Kind, key_type: KeyTypeId) -> Result { + let key = StoredKey::generate_with_phrase(crypto, self.password()); let (id, id_encoded) = loop { let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); @@ -690,7 +625,8 @@ mod tests { let msg = b"Hello world!"; // when - let key = api.new_crypto_key(kind).unwrap(); + let key_type = primitives::crypto::key_types::DUMMY; + let key = api.new_crypto_key(kind, key_type).unwrap(); let signature = api.sign(key, msg).unwrap(); // then diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index f1c38007ea0e8..691bf3d681da6 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -29,6 +29,7 @@ use primitives::offchain::{ HttpRequestStatus as RequestStatus, Timestamp, CryptoKind, + KeyTypeId, CryptoKey, StorageKind, OpaqueNetworkState, @@ -148,7 +149,7 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result { + fn new_crypto_key(&mut self, _crypto: CryptoKind, _key_type: KeyTypeId) -> Result { unimplemented!("not needed in tests so far") } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 6685479547155..1565134b205c4 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -677,10 +677,12 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { #[cfg_attr(feature = "std", derive(Debug))] #[repr(u32)] pub enum Kind { + /// User-level crypto. We (core) can't handle it directly. + User = 0, /// SR25519 crypto (Schnorrkel) - Sr25519 = 0, + Sr25519 = 1, /// ED25519 crypto (Edwards) - Ed25519 = 1, + Ed25519 = 2, /// Dummy kind, just for testing. #[cfg(feature = "std")] @@ -692,8 +694,11 @@ impl TryFrom for Kind { fn try_from(kind: u32) -> Result { Ok(match kind { + e if e == Kind::User as usize as u32 => Kind::User, e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, + #[cfg(feature = "std")] + e if e == Kind::Dummy as usize as u32 => Kind::Dummy, _ => Err(())?, }) } @@ -1049,7 +1054,21 @@ pub trait CryptoType { /// /// Values whose first character is `_` are reserved for private use and won't conflict with any /// public modules. -pub type KeyTypeId = [u8; 4]; +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct KeyTypeId([u8; 4]); + +impl From for KeyTypeId { + fn from(x: u32) -> Self { + Self(x.to_le_bytes()) + } +} + +impl From for u32 { + fn from(x: KeyTypeId) -> Self { + u32::from_le_bytes(x.0) + } +} /// Known key types; this also functions as a global registry of key types for projects wishing to /// avoid collisions with each other. @@ -1060,20 +1079,22 @@ pub mod key_types { use super::KeyTypeId; /// Key type for generic S/R 25519 key. - pub const SR25519: KeyTypeId = *b"sr25"; + pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25"); /// Key type for generic Ed25519 key. - pub const ED25519: KeyTypeId = *b"ed25"; + pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25"); /// Key type for Babe module, build-in. - pub const BABE: KeyTypeId = *b"babe"; + pub const BABE: KeyTypeId = KeyTypeId(*b"babe"); /// Key type for Grandpa module, build-in. - pub const GRANDPA: KeyTypeId = *b"gran"; + pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran"); /// Key type for controlling an account in a Substrate runtime, built-in. - pub const ACCOUNT: KeyTypeId = *b"acco"; + pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco"); /// Key type for Aura module, built-in. - pub const AURA: KeyTypeId = *b"acco"; + pub const AURA: KeyTypeId = KeyTypeId(*b"aura"); + /// Key type for ImOnline module, built-in. + pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon"); /// A key type ID useful for tests. #[cfg(feature = "std")] - pub const DUMMY: KeyTypeId = *b"dumy"; + pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } /*impl TryFrom for Kind { diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 931597a6dde8f..ffd42285dacdf 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -20,7 +20,7 @@ use parity_codec::{Encode, Decode}; use rstd::prelude::{Vec, Box}; use rstd::convert::TryFrom; -pub use crate::crypto::Kind as CryptoKind; +pub use crate::crypto::{Kind as CryptoKind, KeyTypeId}; /// A type of supported crypto. #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] @@ -60,48 +60,27 @@ impl From for u32 { } /// Key to use in the offchain worker crypto api. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] -pub enum CryptoKey { - /// Use a key from the offchain workers local storage. - LocalKey { - /// The id of the key. - id: u16, - /// The kind of the key. - kind: CryptoKind, - }, - /// Use the key the block authoring algorithm uses. - AuthorityKey, - /// Use the key the finality gadget uses. - FgAuthorityKey, +pub struct CryptoKey { + /// The kind of the key. + key_type: KeyTypeId, + /// The id of the key. + id: u32, } impl TryFrom for CryptoKey { type Error = (); fn try_from(key: u64) -> Result { - match key & 0xFF { - 0 => { - let id = (key >> 8 & 0xFFFF) as u16; - let kind = CryptoKind::try_from((key >> 32) as u32)?; - Ok(CryptoKey::LocalKey { id, kind }) - } - 1 => Ok(CryptoKey::AuthorityKey), - 2 => Ok(CryptoKey::FgAuthorityKey), - _ => Err(()), - } + key.using_encoded(|d| Self::decode(&mut d)).ok_or(()) } } impl From for u64 { fn from(key: CryptoKey) -> u64 { - match key { - CryptoKey::LocalKey { id, kind } => { - ((kind as u64) << 32) | ((id as u64) << 8) - } - CryptoKey::AuthorityKey => 1, - CryptoKey::FgAuthorityKey => 2, - } + /// Should never fail since u64 is eight bytes and the `CryptoKey` is eight bytes. + key.using_encoded(|d| Self::decode(&mut d)).unwrap_or(0) } } @@ -289,7 +268,7 @@ pub trait Externalities { /// Create new key(pair) for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result; + fn new_crypto_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result; /// Returns the locally configured authority public key, if available. fn pubkey(&self, key: CryptoKey) -> Result, ()>; @@ -438,8 +417,8 @@ impl Externalities for Box { (&mut **self).submit_transaction(ex) } - fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result { - (&mut **self).new_crypto_key(crypto) + fn new_crypto_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result { + (&mut **self).new_crypto_key(crypto, key_type) } fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 4a65ecfefeb5a..6b4eeae19ddf8 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -36,7 +36,7 @@ pub use primitives::Blake2Hasher; use primitives::offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, - CryptoKind, CryptoKey, + CryptoKind, CryptoKey, KeyTypeId, StorageKind, OpaqueNetworkState, }; @@ -243,13 +243,16 @@ export_api! { /// Returns information about the local node's network state. fn network_state() -> Result; + /// Get the cryptokey whose pubkey and appkeys are those given. + fn find_key(pubkey: &[u8], app_id: KeyTypeId) -> Result; + /// Returns the currently configured authority public key, if available. fn pubkey(key: CryptoKey) -> Result, ()>; /// Create new key(pair) for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(crypto: CryptoKind) -> Result; + fn new_crypto_key(crypto: CryptoKind, app_id: KeyTypeId) -> Result; /// Encrypt a piece of data using given crypto key. /// @@ -267,8 +270,6 @@ export_api! { /// Sign a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key. - /// /// Returns an error if `key` is not available or does not exist. fn sign(key: CryptoKey, data: &[u8]) -> Result, ()>; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 8c70efdcd8197..aa14955e03847 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -281,10 +281,11 @@ impl OffchainApi for () { }, "authority_pubkey can be called only in the offchain worker context") } - fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { + fn new_crypto_key(crypto: offchain::CryptoKind, key_type: offchain::KeyTypeId) -> Result { with_offchain(|ext| { - ext.new_crypto_key(crypto) + ext.new_crypto_key(crypto, key_type) }, "new_crypto_key can be called only in the offchain worker context") + .and_then(|x| x.ok_or(())) } fn encrypt( diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 861f94ced5688..74bc1cc9f0394 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -416,9 +416,9 @@ pub mod ext { /// /// # Returns /// - /// - A crypto key id (if the value is less than u16::max_value) - /// - `u32::max_value` in case the crypto is not supported - fn ext_new_crypto_key(crypto: u32) -> u64; + /// - A crypto key id (if the value is less than u64::max_value) + /// - `u64::max_value` in case the crypto is not supported + fn ext_new_crypto_key(crypto: u32, key_type: u32) -> u64; /// Encrypt a piece of data using given crypto key. /// @@ -942,10 +942,13 @@ impl OffchainApi for () { } } - fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { + fn new_crypto_key( + crypto: offchain::CryptoKind, + key_type: offchain::KeyType, + ) -> Result { let crypto = crypto.into(); let ret = unsafe { - ext_new_crypto_key.get()(crypto) + ext_new_crypto_key.get()(crypto, key_type) }; offchain::CryptoKey::try_from(ret) } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 7b2eb07819e65..6d228398364e3 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -256,6 +256,7 @@ impl offchain::Externalities for NeverOffchainExt { fn new_crypto_key( &mut self, _crypto: offchain::CryptoKind, + _key_type: offchain::KeyTypeId, ) -> Result { unreachable!() } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a6c3b94a489ab..f024ae55275b4 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -47,6 +47,7 @@ use elections::VoteIndex; use version::NativeVersion; use substrate_primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use im_online::{AuthorityId as ImOnlineId}; use finality_tracker::{DEFAULT_REPORT_LATENCY, DEFAULT_WINDOW_SIZE}; #[cfg(any(feature = "std", test))] @@ -187,7 +188,7 @@ impl authorship::Trait for Runtime { type EventHandler = (); } -type SessionHandlers = (Grandpa, Babe); +type SessionHandlers = (Grandpa, Babe, ImOnline); impl_opaque_keys! { pub struct SessionKeys { @@ -195,6 +196,8 @@ impl_opaque_keys! { pub grandpa: GrandpaId, #[id(key_types::BABE)] pub babe: BabeId, + #[id(key_types::IM_ONLINE)] + pub babe: ImOnlineId, } } @@ -369,12 +372,10 @@ impl sudo::Trait for Runtime { } impl im_online::Trait for Runtime { - type AuthorityId = BabeId; type Call = Call; type Event = Event; type SessionsPerEra = SessionsPerEra; type UncheckedExtrinsic = UncheckedExtrinsic; - type IsValidAuthorityId = Babe; } impl grandpa::Trait for Runtime { diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index ec20c31722056..4b8500e10d3a7 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -87,6 +87,24 @@ use srml_support::{ traits::Get, StorageDoubleMap, print, }; use system::ensure_none; +use substrate_primitives::offchain::CryptoKind; + +mod app { + use substrate_primitives::{app_crypto, crypto::key_types::IM_ONLINE, sr25519}; + app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, IM_ONLINE); +} + +/// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in +/// the main Babe module. If that ever changes, then this must, too. +#[cfg(feature = "std")] +pub type AuthorityPair = app::Pair; + +/// A Babe authority signature. +pub type AuthoritySignature = app::Signature; + +/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in +/// the main Babe module. If that ever changes, then this must, too. +pub type AuthorityId = app::Public; // The local storage database key under which the worker progress status // is tracked. @@ -127,16 +145,18 @@ impl Printable for OffchainErr { } } -/// Heartbeat which is send/received. +pub type AuthIndex = u32; + +/// Heartbeat which is sent/received. #[derive(Encode, Decode, Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct Heartbeat +pub struct Heartbeat where BlockNumber: PartialEq + Eq + Decode + Encode, { block_number: BlockNumber, network_state: OpaqueNetworkState, session_index: session::SessionIndex, - authority_id: AuthorityId, + authority_index: AuthIndex, } pub trait Trait: system::Trait + session::Trait { @@ -149,39 +169,29 @@ pub trait Trait: system::Trait + session::Trait { /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. type UncheckedExtrinsic: ExtrinsicT::Call> + Encode + Decode; - - /// The identifier type for an authority. - type AuthorityId: Member + Parameter + Default + AppKey + Decode + Encode + AsRef<[u8]>; - - /// Number of sessions per era. - type SessionsPerEra: Get; - - /// Determine if an `AuthorityId` is a valid authority. - type IsValidAuthorityId: IsMember; } decl_event!( pub enum Event where ::BlockNumber, - ::AuthorityId { - /// A new heartbeat was received at this `BlockNumber` from `AuthorityId` - HeartbeatReceived(BlockNumber, AuthorityId), + /// A new heartbeat was received from `AuthorityId` + HeartbeatReceived(AuthorityId), } ); decl_storage! { trait Store for Module as ImOnline { - // The block number when we should gossip. + /// The block number when we should gossip. GossipAt get(gossip_at) config(): T::BlockNumber; - // The session index when the last new era started. - LastNewEraStart get(last_new_era_start) config(): Option; + /// The current set of keys that may issue a heartbeat. + Keys get(keys) config(): Vec; - // For each session index we keep a mapping of `AuthorityId` to - // `offchain::OpaqueNetworkState`. - ReceivedHeartbeats get(received_heartbeats): double_map session::SessionIndex, - blake2_256(T::AuthorityId) => Vec; + /// For each session index we keep a mapping of `AuthorityId` to + /// `offchain::OpaqueNetworkState`. + ReceivedHeartbeats get(received_heartbeats): + double_map session::SessionIndex, AuthIndex => Vec; } } @@ -194,205 +204,174 @@ decl_module! { fn heartbeat( origin, - heartbeat: Heartbeat, - _signature: Vec + heartbeat: Heartbeat, + _signature: AuthoritySignature, ) { ensure_none(origin)?; let current_session = >::current_index(); - let exists = >::exists(¤t_session, &heartbeat.authority_id); + let exists = >::exists( + ¤t_session, + &heartbeat.authority_index + ); if !exists { - let now = >::block_number(); - Self::deposit_event(RawEvent::HeartbeatReceived(now, heartbeat.authority_id.clone())); + Self::deposit_event(RawEvent::HeartbeatReceived(heartbeat.authority_id.clone())); let network_state = heartbeat.network_state.encode(); - >::insert(¤t_session, &heartbeat.authority_id, &network_state); + >::insert( + ¤t_session, + &heartbeat.authority_index, + &network_state + ); } } // Runs after every block. fn offchain_worker(now: T::BlockNumber) { - fn gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { - // we run only when a local authority key is configured - if let Ok(key) = sr_io::pubkey(CryptoKey::AuthorityKey) { - let authority_id = ::AuthorityId::decode(&mut &key[..]) - .ok_or(OffchainErr::DecodeAuthorityId)?; - let network_state = - sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; - let heartbeat_data = Heartbeat { - block_number, - network_state, - session_index: >::current_index(), - authority_id, - }; - - let signature = sr_io::sign(CryptoKey::AuthorityKey, &heartbeat_data.encode()) - .map_err(|_| OffchainErr::FailedSigning)?; - let call = Call::heartbeat(heartbeat_data, signature); - let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) - .ok_or(OffchainErr::ExtrinsicCreation)?; - sr_io::submit_transaction(&ex) - .map_err(|_| OffchainErr::SubmitTransaction)?; - - // once finished we set the worker status without comparing - // if the existing value changed in the meantime. this is - // because at this point the heartbeat was definitely submitted. - set_worker_status::(block_number, true); - } - Ok(()) - } + Self::offchain(now); + } + } +} - fn compare_and_set_worker_status( - gossipping_at: T::BlockNumber, - done: bool, - curr_worker_status: Option>, - ) -> bool { - let enc = WorkerStatus { - done, - gossipping_at, - }; - sr_io::local_storage_compare_and_set( - StorageKind::PERSISTENT, - DB_KEY, - curr_worker_status.as_ref().map(Vec::as_slice), - &enc.encode() - ) - } +impl Module { + /// Returns `true` if a heartbeat has been received for the authority at `authority_index` in + /// the authorities series, during the current session. Otherwise `false`. + pub fn is_online_in_current_session(authority_index: AuthIndex) -> bool { + let current_session = >::current_index(); + >::exists(¤t_session, authority_index) + } - fn set_worker_status( - gossipping_at: T::BlockNumber, - done: bool, - ) { - let enc = WorkerStatus { - done, - gossipping_at, + fn offchain(new: T::BlockNumber) { + fn gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { + // we run only when a local authority key is configured + let authorities = Keys::get(); + let authority = authorities.into_iter().find(|id| ) + if let Ok(key) = sr_io::pubkey(CryptoKey { key_type: b"imon".into(), id: CryptoKind::Ed25519 }) { + let authority_id = ::AuthorityId::decode(&mut &key[..]) + .ok_or(OffchainErr::DecodeAuthorityId)?; + let network_state = + sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; + let heartbeat_data = Heartbeat { + block_number, + network_state, + session_index: >::current_index(), + authority_id, }; - sr_io::local_storage_set( - StorageKind::PERSISTENT, DB_KEY, &enc.encode()); - } - // Checks if a heartbeat gossip already occurred at this block number. - // Returns a tuple of `(current worker status, bool)`, whereby the bool - // is true if not yet gossipped. - fn check_not_yet_gossipped( - now: T::BlockNumber, - next_gossip: T::BlockNumber, - ) -> Result<(Option>, bool), OffchainErr> { - let last_gossip = sr_io::local_storage_get(StorageKind::PERSISTENT, DB_KEY); - match last_gossip { - Some(last) => { - let worker_status: WorkerStatus = Decode::decode(&mut &last[..]) - .ok_or(OffchainErr::DecodeWorkerStatus)?; - - let was_aborted = !worker_status.done && worker_status.gossipping_at < now; - - // another off-chain worker is currently in the process of submitting - let already_submitting = - !worker_status.done && worker_status.gossipping_at == now; - - let not_yet_gossipped = - worker_status.done && worker_status.gossipping_at < next_gossip; - - let ret = (was_aborted && !already_submitting) || not_yet_gossipped; - Ok((Some(last), ret)) - }, - None => Ok((None, true)), - } + let signature = sr_io::sign(CryptoKey::AuthorityKey, &heartbeat_data.encode()) + .map_err(|_| OffchainErr::FailedSigning)?; + let call = Call::heartbeat(heartbeat_data, signature); + let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) + .ok_or(OffchainErr::ExtrinsicCreation)?; + sr_io::submit_transaction(&ex) + .map_err(|_| OffchainErr::SubmitTransaction)?; + + // once finished we set the worker status without comparing + // if the existing value changed in the meantime. this is + // because at this point the heartbeat was definitely submitted. + set_worker_status::(block_number, true); } + Ok(()) + } - let next_gossip = >::get(); - let check = check_not_yet_gossipped::(now, next_gossip); - let (curr_worker_status, not_yet_gossipped) = match check { - Ok((s, v)) => (s, v), - Err(err) => { - print(err); - return; - }, + fn compare_and_set_worker_status( + gossipping_at: T::BlockNumber, + done: bool, + curr_worker_status: Option>, + ) -> bool { + let enc = WorkerStatus { + done, + gossipping_at, }; - if next_gossip < now && not_yet_gossipped { - let value_set = compare_and_set_worker_status::(now, false, curr_worker_status); - if !value_set { - // value could not be set in local storage, since the value was - // different from `curr_worker_status`. this indicates that - // another worker was running in parallel. - return; - } - - match gossip_at::(now) { - Ok(_) => {}, - Err(err) => print(err), - } - } + sr_io::local_storage_compare_and_set( + StorageKind::PERSISTENT, + DB_KEY, + curr_worker_status.as_ref().map(Vec::as_slice), + &enc.encode() + ) } - } -} -impl Module { - /// Returns `true` if a heartbeat has been received for `AuthorityId` - /// during the current era. Otherwise `false`. - pub fn is_online_in_current_era(authority_id: &T::AuthorityId) -> bool { - let curr = >::current_index(); - match LastNewEraStart::get() { - Some(start) => { - // iterate over every session - for index in start..curr { - if >::exists(&index, authority_id) { - return true; - } - } - false - }, - None => >::exists(&curr, authority_id), + fn set_worker_status( + gossipping_at: T::BlockNumber, + done: bool, + ) { + let enc = WorkerStatus { + done, + gossipping_at, + }; + sr_io::local_storage_set( + StorageKind::PERSISTENT, DB_KEY, &enc.encode()); } - } - - /// Returns `true` if a heartbeat has been received for `AuthorityId` - /// during the current session. Otherwise `false`. - pub fn is_online_in_current_session(authority_id: &T::AuthorityId) -> bool { - let current_session = >::current_index(); - >::exists(¤t_session, authority_id) - } - - /// Session has just changed. - fn new_session() { - let now = >::block_number(); - >::put(now); - - let current_session = >::current_index(); - match LastNewEraStart::get() { - Some(last_new_era_start) => { - let sessions_per_era = T::SessionsPerEra::get(); + // Checks if a heartbeat gossip already occurred at this block number. + // Returns a tuple of `(current worker status, bool)`, whereby the bool + // is true if not yet gossipped. + fn check_not_yet_gossipped( + now: T::BlockNumber, + next_gossip: T::BlockNumber, + ) -> Result<(Option>, bool), OffchainErr> { + let last_gossip = sr_io::local_storage_get(StorageKind::PERSISTENT, DB_KEY); + match last_gossip { + Some(last) => { + let worker_status: WorkerStatus = Decode::decode(&mut &last[..]) + .ok_or(OffchainErr::DecodeWorkerStatus)?; + + let was_aborted = !worker_status.done && worker_status.gossipping_at < now; + + // another off-chain worker is currently in the process of submitting + let already_submitting = + !worker_status.done && worker_status.gossipping_at == now; + + let not_yet_gossipped = + worker_status.done && worker_status.gossipping_at < next_gossip; + + let ret = (was_aborted && !already_submitting) || not_yet_gossipped; + Ok((Some(last), ret)) + }, + None => Ok((None, true)), + } + } - let new_era = current_session - last_new_era_start > sessions_per_era; - if new_era { - LastNewEraStart::put(current_session); - Self::remove_heartbeats(); - } + let next_gossip = >::get(); + let check = check_not_yet_gossipped::(now, next_gossip); + let (curr_worker_status, not_yet_gossipped) = match check { + Ok((s, v)) => (s, v), + Err(err) => { + print(err); + return; }, - None => LastNewEraStart::put(current_session), }; - } + if next_gossip < now && not_yet_gossipped { + let value_set = compare_and_set_worker_status::(now, false, curr_worker_status); + if !value_set { + // value could not be set in local storage, since the value was + // different from `curr_worker_status`. this indicates that + // another worker was running in parallel. + return; + } - // Remove all stored heartbeats. - fn remove_heartbeats() { - let curr = >::current_index(); - match LastNewEraStart::get() { - Some(start) => { - for index in start..curr { - >::remove_prefix(&index); - } - }, - None => >::remove_prefix(&curr), + match gossip_at::(now) { + Ok(_) => {}, + Err(err) => print(err), + } } } } impl session::OneSessionHandler for Module { - type Key = ::AuthorityId; + type Key = AuthorityId; + + fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, next_validators: I) + where I: Iterator + { + /// Reset heartbeats + >::remove_prefix(>::current_index()); + + /// Tell the offchain worker to start making the next session's heartbeats. + >::put(>::block_number()); - fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, _next_validators: I) { - Self::new_session(); + /// Remember who the authorities are for the new session. + Keys::put(next_validators.map(|x| x.1).collect()); } fn on_disabled(_i: usize) { @@ -405,47 +384,35 @@ impl srml_support::unsigned::ValidateUnsigned for Module { fn validate_unsigned(call: &Self::Call) -> srml_support::unsigned::TransactionValidity { if let Call::heartbeat(heartbeat, signature) = call { - // verify that the incoming (unverified) pubkey is actually an authority id - let is_authority = T::IsValidAuthorityId::is_member(&heartbeat.authority_id); - if !is_authority { - return TransactionValidity::Invalid(ApplyError::BadSignature as i8); - } - - if >::is_online_in_current_session(&heartbeat.authority_id) { + if >::is_online_in_current_session(&heartbeat.authority_index) { // we already received a heartbeat for this authority - return TransactionValidity::Invalid(ApplyError::BadSignature as i8); + return TransactionValidity::Invalid(ApplyError::Stale as i8); } - if signature.len() != 64 { - return TransactionValidity::Invalid(ApplyError::BadSignature as i8); + // check if session index from heartbeat is recent + let current_session = >::current_index(); + if heartbeat.session_index != current_session { + return TransactionValidity::Invalid(ApplyError::Stale as i8); } - let signature = { - let mut array = [0; 64]; - array.copy_from_slice(&signature); // panics if not enough, hence the check above - array - }; - - let encoded_heartbeat = heartbeat.encode(); - - let signature_valid = match ::KIND { - ed25519::Public::KIND => - sr_io::ed25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), - sr25519::Public::KIND => - sr_io::sr25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), - _ => return TransactionValidity::Invalid(ApplyError::BadSignature as i8), + // verify that the incoming (unverified) pubkey is actually an authority id + let authority_id = match Keys::get().get(heartbeat.authority_index as usize) { + Some(id) => id, + None => return TransactionValidity::Invalid(ApplyError::BadSignature as i8), }; + // check signature (this is expensive so we do it last). + let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| + sr_io::sr25519_verify( + signature.as_ref(), + encoded_heartbeat, + &authority_id + ) + ); if !signature_valid { return TransactionValidity::Invalid(ApplyError::BadSignature as i8); } - // check if session index from heartbeat is recent - let current_session = >::current_index(); - if heartbeat.session_index < current_session { - return TransactionValidity::Invalid(ApplyError::BadSignature as i8); - } - return TransactionValidity::Valid(ValidTransaction { priority: 0, requires: vec![], From 4715da3fd4b1838723fb7231227e97e9b4cf18af Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Jul 2019 22:48:08 +0800 Subject: [PATCH 13/80] Finish up drafting imonline --- core/sr-io/src/lib.rs | 2 +- srml/im-online/src/lib.rs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 6b4eeae19ddf8..32793be2e7127 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -244,7 +244,7 @@ export_api! { fn network_state() -> Result; /// Get the cryptokey whose pubkey and appkeys are those given. - fn find_key(pubkey: &[u8], app_id: KeyTypeId) -> Result; + fn find_key(pubkey: &[u8], app_id: KeyTypeId) -> Result { Err(()) } // TODO: implement this. /// Returns the currently configured authority public key, if available. fn pubkey(key: CryptoKey) -> Result, ()>; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 4b8500e10d3a7..5a204f552cfac 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -244,21 +244,22 @@ impl Module { fn offchain(new: T::BlockNumber) { fn gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { // we run only when a local authority key is configured + let key_type: KeyTypeId = b"imon".into(); let authorities = Keys::get(); - let authority = authorities.into_iter().find(|id| ) - if let Ok(key) = sr_io::pubkey(CryptoKey { key_type: b"imon".into(), id: CryptoKind::Ed25519 }) { - let authority_id = ::AuthorityId::decode(&mut &key[..]) - .ok_or(OffchainErr::DecodeAuthorityId)?; + let maybe_key = authorities.into_iter() + .enumerate() + .filter_map(|(i, id)| sr_io::find_key(id, key_type).ok().map(|x| (i, x))); + if let Some((authority_index, key)) = maybe_key { let network_state = sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; let heartbeat_data = Heartbeat { block_number, network_state, session_index: >::current_index(), - authority_id, + authority_index, }; - let signature = sr_io::sign(CryptoKey::AuthorityKey, &heartbeat_data.encode()) + let signature = sr_io::sign(CryptoKey { key_type, id }, &heartbeat_data.encode()) .map_err(|_| OffchainErr::FailedSigning)?; let call = Call::heartbeat(heartbeat_data, signature); let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) From ca53ad6936a8a05aba404fce3c3f5636f842d267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 13:09:24 +0200 Subject: [PATCH 14/80] Rework offchain workers API. --- Cargo.lock | 1 + core/client/src/client.rs | 2 +- core/consensus/babe/primitives/src/lib.rs | 3 +- core/executor/src/wasm_executor.rs | 147 +++++++++++++--------- core/keystore/src/lib.rs | 4 +- core/offchain/Cargo.toml | 1 + core/offchain/src/api.rs | 40 +++--- core/primitives/src/crypto.rs | 8 +- core/primitives/src/offchain.rs | 90 ++++++------- core/sr-io/src/lib.rs | 19 ++- core/sr-io/with_std.rs | 13 +- core/sr-io/without_std.rs | 92 +++++++++----- core/sr-primitives/src/traits.rs | 1 - core/state-machine/src/lib.rs | 23 ++-- srml/session/src/lib.rs | 6 +- 15 files changed, 239 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d05223218f6e4..872dbc25e1e19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4608,6 +4608,7 @@ dependencies = [ "sr-primitives 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 01403e81134cc..50afb2b4448b4 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -31,7 +31,7 @@ use primitives::{ storage::{StorageKey, StorageData, well_known_keys}, NativeOrEncoded }; use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; -use runtime_primitives::{ +use sr_primitives::{ Justification, BuildStorage, generic::{BlockId, SignedBlock, DigestItem}, traits::{ diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index dfa464875ea7a..d05688896775c 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -22,7 +22,6 @@ mod digest; use parity_codec::{Encode, Decode}; -use primitives::sr25519; use rstd::vec::Vec; use sr_primitives::ConsensusEngineId; use substrate_client::decl_runtime_apis; @@ -32,7 +31,7 @@ pub use digest::{BabePreDigest, CompatibleDigestItem}; pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest}; mod app { - use substrate_primitives::{app_crypto, crypto::key_types::BABE, sr25519}; + use primitives::{app_crypto, crypto::key_types::BABE, sr25519}; app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, BABE); } diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 5b1a92bb97d89..c5ec9b2152578 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -711,29 +711,82 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(if res.is_ok() { 0 } else { 1 }) }, - ext_new_crypto_key(crypto: u32, app: u32) -> u64 => { + ext_network_state(written_out: *mut u32) -> *mut u8 => { + let res = this.ext.offchain() + .map(|api| api.network_state()) + .ok_or_else(|| "Calling unavailable API ext_network_state: wasm")?; + + let encoded = res.encode(); + let len = encoded.len() as u32; + let offset = this.heap.allocate(len)? as u32; + this.memory.set(offset, &encoded) + .map_err(|_| "Invalid attempt to set memory in ext_network_state")?; + + this.memory.write_primitive(written_out, len) + .map_err(|_| "Invalid attempt to write written_out in ext_network_state")?; + + Ok(offset) + }, + ext_new_key( + crypto: u32, + key_type: u32, + written_out: *mut u32 + ) -> *mut u8 => { let kind = offchain::CryptoKind::try_from(crypto) - .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; - let key_type = offchain::KeyType::try_from(app) - .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; + .map_err(|_| "crypto kind OOB while ext_new_key: wasm")?; + let key_type = offchain::KeyTypeId::try_from(key_type) + .map_err(|_| "crypto kind OOB while ext_new_key: wasm")?; let res = this.ext.offchain() - .map(|api| api.new_crypto_key(kind, key_type)) - .ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?; + .map(|api| api.new_key(kind, key_type)) + .ok_or_else(|| "Calling unavailable API ext_new_key: wasm")?; - match res { - Ok(key) => Ok(key.into()), - Err(()) => Ok(u64::max_value()), - } + let encoded = res.encode(); + let len = encoded.len() as u32; + let offset = this.heap.allocate(len)? as u32; + this.memory.set(offset, &encoded) + .map_err(|_| "Invalid attempt to set memory in ext_new_key")?; + this.memory.write_primitive(written_out, len) + .map_err(|_| "Invalid attempt to write written_out in ext_new_key")?; + Ok(offset) }, + ext_public_keys( + crypto: u32, + key_type: u32, + written_out: *mut u32 + ) -> *mut u8 => { + let kind = offchain::CryptoKind::try_from(crypto) + .map_err(|_| "crypto kind OOB while ext_public_keys: wasm")?; + let key_type = offchain::KeyTypeId::try_from(key_type) + .map_err(|_| "crypto kind OOB while ext_public_keys: wasm")?; + + let res = this.ext.offchain() + .map(|api| api.public_keys(kind, key_type)) + .ok_or_else(|| "Calling unavailable API ext_public_keys: wasm")?; + + let encoded = res.encode(); + let len = encoded.len() as u32; + let offset = this.heap.allocate(len)? as u32; + this.memory.set(offset, &encoded) + .map_err(|_| "Invalid attempt to set memory in ext_public_keys")?; + this.memory.write_primitive(written_out, len) + .map_err(|_| "Invalid attempt to write written_out in ext_public_keys")?; + Ok(offset) + }, + ext_encrypt( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, msg_len: *mut u32 ) -> *mut u8 => { - let key = offchain::CryptoKey::try_from(key) - .map_err(|_| "Key OOB while ext_encrypt: wasm")?; + use parity_codec::Decode; + + let key = this.memory.get(key, key_len as usize) + .ok() + .and_then(|x| offchain::CryptoKey::decode(&mut &*x)) + .ok_or("Key OOB while ext_encrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_encrypt: wasm")?; @@ -757,49 +810,19 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, - ext_network_state(written_out: *mut u32) -> *mut u8 => { - let res = this.ext.offchain() - .map(|api| api.network_state()) - .ok_or_else(|| "Calling unavailable API ext_network_state: wasm")?; - - let encoded = res.encode(); - let len = encoded.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &encoded) - .map_err(|_| "Invalid attempt to set memory in ext_network_state")?; - - this.memory.write_primitive(written_out, len) - .map_err(|_| "Invalid attempt to write written_out in ext_network_state")?; - - Ok(offset) - }, - ext_pubkey( - key: u64, - written_out: *mut u32 - ) -> *mut u8 => { - let key = offchain::CryptoKey::try_from(key) - .map_err(|_| "Key OOB while ext_decrypt: wasm")?; - let res = this.ext.offchain() - .map(|api| api.pubkey(key)) - .ok_or_else(|| "Calling unavailable API ext_authority_pubkey: wasm")?; - - let encoded = res.encode(); - let len = encoded.len() as u32; - let offset = this.heap.allocate(len)? as u32; - this.memory.set(offset, &encoded) - .map_err(|_| "Invalid attempt to set memory in ext_authority_pubkey")?; - this.memory.write_primitive(written_out, len) - .map_err(|_| "Invalid attempt to write written_out in ext_authority_pubkey")?; - Ok(offset) - }, ext_decrypt( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, msg_len: *mut u32 ) -> *mut u8 => { - let key = offchain::CryptoKey::try_from(key) - .map_err(|_| "Key OOB while ext_decrypt: wasm")?; + use parity_codec::Decode; + + let key = this.memory.get(key, key_len as usize) + .ok() + .and_then(|x| offchain::CryptoKey::decode(&mut &*x)) + .ok_or("Key OOB while ext_decrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_decrypt: wasm")?; @@ -824,13 +847,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, ext_sign( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, sig_data_len: *mut u32 ) -> *mut u8 => { - let key = offchain::CryptoKey::try_from(key) - .map_err(|_| "Key OOB while ext_sign: wasm")?; + use parity_codec::Decode; + + let key = this.memory.get(key, key_len as usize) + .ok() + .and_then(|x| offchain::CryptoKey::decode(&mut &*x)) + .ok_or("Key OOB while ext_sign: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_sign: wasm")?; @@ -855,14 +883,19 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, ext_verify( - key: u64, + key: *const u8, + key_len: u32, msg: *const u8, msg_len: u32, signature: *const u8, signature_len: u32 ) -> u32 => { - let key = offchain::CryptoKey::try_from(key) - .map_err(|_| "Key OOB while ext_verify: wasm")?; + use parity_codec::Decode; + + let key = this.memory.get(key, key_len as usize) + .ok() + .and_then(|x| offchain::CryptoKey::decode(&mut &*x)) + .ok_or("Key OOB while ext_verify: wasm")?; let message = this.memory.get(msg, msg_len as usize) .map_err(|_| "OOB while ext_verify: wasm")?; let signature = this.memory.get(signature, signature_len as usize) diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index bde23e422f32a..b7ef99a65ea4d 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -168,7 +168,7 @@ impl Store { if let Some(name) = path.file_name().and_then(|n| n.to_str()) { match hex::decode(name) { Ok(ref hex) => { - if hex[0..4] != key_type { continue } + if &hex[0..4] != &key_type.0 { continue } let public = TPublic::from_slice(&hex[4..]); public_keys.push(public); } @@ -195,7 +195,7 @@ impl Store { fn key_file_path(&self, public: &TPair::Public, key_type: KeyTypeId) -> PathBuf { let mut buf = self.path.clone(); - let key_type = hex::encode(key_type); + let key_type = hex::encode(key_type.0); let key = hex::encode(public.as_slice()); buf.push(key_type + key.as_str()); buf diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index 694ce38663aec..bcf5b0068dc9e 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -17,6 +17,7 @@ primitives = { package = "substrate-primitives", path = "../../core/primitives" sr-primitives = { path = "../../core/sr-primitives" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } network = { package = "substrate-network", path = "../../core/network" } +keystore = { package = "substrate-keystore", path = "../keystore" } [dev-dependencies] env_logger = "0.6" diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 855867d81513e..ce73fb431f330 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -198,27 +198,29 @@ where .map_err(|_| ()) } - fn new_crypto_key(&mut self, crypto: Kind, key_type: KeyTypeId) -> Result { - let key = StoredKey::generate_with_phrase(crypto, self.password()); - let (id, id_encoded) = loop { - let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); - let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); - let new_id = encoded_slice.and_then(|mut x| u16::decode(&mut x)).unwrap_or_default() - .checked_add(1) - .ok_or(())?; - let new_id_encoded = new_id.encode(); - - if self.db.compare_and_set(KEYS_PREFIX, NEXT_ID, encoded_slice, &new_id_encoded) { - break (new_id, new_id_encoded); - } - }; - - self.db.set(KEYS_PREFIX, &id_encoded, &key.encode()); - - Ok(CryptoKey::LocalKey { id, kind }) + fn new_key(&self, crypto: Kind, key_type: KeyTypeId) -> Result { + // let key = StoredKey::generate_with_phrase(crypto, self.password()); + // let (id, id_encoded) = loop { + // let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); + // let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); + // let new_id = encoded_slice.and_then(|mut x| u16::decode(&mut x)).unwrap_or_default() + // .checked_add(1) + // .ok_or(())?; + // let new_id_encoded = new_id.encode(); + // + // if self.db.compare_and_set(KEYS_PREFIX, NEXT_ID, encoded_slice, &new_id_encoded) { + // break (new_id, new_id_encoded); + // } + // }; + // + // self.db.set(KEYS_PREFIX, &id_encoded, &key.encode()); + // + // Ok(CryptoKey::LocalKey { id, kind }) + unavailable_yet::<()>("new_key"); + Err(()) } - fn pubkey(&self, key: CryptoKey) -> Result, ()> { + fn public_key(&self, crypto: Kind, key_type: KeyTypeId) -> Result { self.read_key(key)?.public() } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 1565134b205c4..97c11654c2183 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -1056,7 +1056,7 @@ pub trait CryptoType { /// public modules. #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct KeyTypeId([u8; 4]); +pub struct KeyTypeId(pub [u8; 4]); impl From for KeyTypeId { fn from(x: u32) -> Self { @@ -1160,9 +1160,6 @@ mod tests { vec![] } } - impl TypedKey for TestPublic { - const KEY_TYPE: KeyTypeId = TEST_KEY_TYPE; - } impl Pair for TestPair { type Public = TestPublic; type Seed = [u8; 0]; @@ -1219,9 +1216,6 @@ mod tests { vec![] } } - impl TypedKey for TestPair { - const KEY_TYPE: u32 = 4242; - } #[test] fn interpret_std_seed_should_work() { diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index ffd42285dacdf..a3aa06b7ded78 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -60,28 +60,15 @@ impl From for u32 { } /// Key to use in the offchain worker crypto api. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] +#[derive(Clone, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] pub struct CryptoKey { - /// The kind of the key. - key_type: KeyTypeId, - /// The id of the key. - id: u32, -} - -impl TryFrom for CryptoKey { - type Error = (); - - fn try_from(key: u64) -> Result { - key.using_encoded(|d| Self::decode(&mut d)).ok_or(()) - } -} - -impl From for u64 { - fn from(key: CryptoKey) -> u64 { - /// Should never fail since u64 is eight bytes and the `CryptoKey` is eight bytes. - key.using_encoded(|d| Self::decode(&mut d)).unwrap_or(0) - } + /// Used cryptography. + pub kind: CryptoKind, + /// The app_id of the key. + pub key_type: KeyTypeId, + /// The public key. + pub public: Vec, } /// Opaque type for offchain http requests. @@ -265,44 +252,37 @@ pub trait Externalities { /// Returns information about the local node's network state. fn network_state(&self) -> Result; - /// Create new key(pair) for signing/encryption/decryption. + /// Create new key pair for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result; + fn new_key(&mut self, crypto: CryptoKind, app_id: KeyTypeId) -> Result; - /// Returns the locally configured authority public key, if available. - fn pubkey(&self, key: CryptoKey) -> Result, ()>; + /// Get existing public keys for given `crypto` and `app_id`. + /// + /// Return keys if they are available or an error if given `crypto` or `app_id` is not supported. + fn public_keys(&self, crypto: CryptoKind, app_id: KeyTypeId) -> Result, ()>; /// Encrypt a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. - /// - /// Returns an error if `key` is not available or does not exist, - /// or the expected `CryptoKind` does not match. - fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; + /// Returns an error if `key` is not available or does not exist. + fn encrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. - /// - /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist, - /// or the expected `CryptoKind` does not match. - fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; + /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. + fn decrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Sign a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`. - /// - /// Returns an error if `key` is not available or does not exist, - /// or the expected `CryptoKind` does not match. - fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; + /// Returns an error if `key` is not available or does not exist. + fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Verifies that `signature` for `msg` matches given `key`. /// /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. /// Returns an error in case the key is not available or does not exist or the parameters - /// lengths are incorrect or `CryptoKind` does not match. - fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; + /// lengths are incorrect. + fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; /// Returns current UNIX timestamp (in millis) fn timestamp(&mut self) -> Timestamp; @@ -417,32 +397,32 @@ impl Externalities for Box { (&mut **self).submit_transaction(ex) } - fn new_crypto_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result { - (&mut **self).new_crypto_key(crypto, key_type) + fn network_state(&self) -> Result { + (& **self).network_state() } - fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&mut **self).encrypt(key, data) + fn new_key(&mut self, crypto: CryptoKind, key_type: KeyTypeId) -> Result { + (&mut **self).new_key(crypto, key_type) } - fn network_state(&self) -> Result { - (& **self).network_state() + fn public_keys(&self, crypto: CryptoKind, key_type: KeyTypeId) -> Result, ()> { + (&**self).public_keys(crypto, key_type) } - fn pubkey(&self, key: CryptoKey) -> Result, ()> { - (&**self).pubkey(key) + fn encrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&**self).encrypt(key, data) } - fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&mut **self).decrypt(key, data) + fn decrypt(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&**self).decrypt(key, data) } - fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { - (&mut **self).sign(key, data) + fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&**self).sign(key, data) } - fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { - (&mut **self).verify(key, msg, signature) + fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { + (&**self).verify(key, msg, signature) } fn timestamp(&mut self) -> Timestamp { diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 854f3d53709ee..f321cae68c75c 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -245,28 +245,23 @@ export_api! { /// Returns information about the local node's network state. fn network_state() -> Result; - /// Get the cryptokey whose pubkey and appkeys are those given. - fn find_key(pubkey: &[u8], app_id: KeyTypeId) -> Result { Err(()) } // TODO: implement this. - - /// Returns the currently configured authority public key, if available. - fn pubkey(key: CryptoKey) -> Result, ()>; - - /// Create new key(pair) for signing/encryption/decryption. + /// Create new key pair for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(crypto: CryptoKind, app_id: KeyTypeId) -> Result; + fn new_key(crypto: CryptoKind, app_id: KeyTypeId) -> Result; - /// Encrypt a piece of data using given crypto key. + /// Get existing public keys for given `crypto` and `app_id`. /// - /// If `key` is `None`, it will attempt to use current authority key. + /// Return keys if they are available or an error if given `crypto` or `app_id` is not supported. + fn public_keys(crypto: CryptoKind, app_id: KeyTypeId) -> Result, ()>; + + /// Encrypt a piece of data using given crypto key. /// /// Returns an error if `key` is not available or does not exist. fn encrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// - /// If `key` is `None`, it will attempt to use current authority key. - /// /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. fn decrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index aa14955e03847..f34f3d449edeb 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -275,17 +275,16 @@ impl OffchainApi for () { }, "network_state can be called only in the offchain worker context") } - fn pubkey(key: offchain::CryptoKey) -> Result, ()> { + fn public_keys(crypto: offchain::CryptoKind, app_id: offchain::KeyTypeId) -> Result, ()> { with_offchain(|ext| { - ext.pubkey(key) - }, "authority_pubkey can be called only in the offchain worker context") + ext.public_keys(crypto, app_id) + }, "public_keys can be called only in the offchain worker context") } - fn new_crypto_key(crypto: offchain::CryptoKind, key_type: offchain::KeyTypeId) -> Result { + fn new_key(crypto: offchain::CryptoKind, key_type: offchain::KeyTypeId) -> Result { with_offchain(|ext| { - ext.new_crypto_key(crypto, key_type) - }, "new_crypto_key can be called only in the offchain worker context") - .and_then(|x| x.ok_or(())) + ext.new_key(crypto, key_type) + }, "new_key can be called only in the offchain worker context") } fn encrypt( diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 74bc1cc9f0394..31433441f36ce 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -398,39 +398,42 @@ pub mod ext { /// runtime code can always rely on it. fn ext_network_state(written_out: *mut u32) -> *mut u8; - /// Returns the locally configured authority public key, if available. - /// The `crypto` argument is `offchain::CryptoKind` converted to `u32`. + /// Create new key pair for signing/encryption/decryption. /// /// # Returns /// - /// The encoded `Result, ()>`. + /// The encoded `Result, ()>`. /// `written_out` contains the length of the message. /// /// The ownership of the returned buffer is transferred to the runtime /// code and the runtime is responsible for freeing it. This is always /// a properly allocated pointer (which cannot be NULL), hence the /// runtime code can always rely on it. - fn ext_pubkey(key: u64, written_out: *mut u32) -> *mut u8; + fn ext_new_key(crypto: u32, key_type: u32, written_out: *mut u32) -> *mut u8; - /// Create new key(pair) for signing/encryption/decryption. + /// Get a list of public keys matching given `crypto` and `key_type`. /// /// # Returns /// - /// - A crypto key id (if the value is less than u64::max_value) - /// - `u64::max_value` in case the crypto is not supported - fn ext_new_crypto_key(crypto: u32, key_type: u32) -> u64; + /// The encoded `Result>, ()>`. + /// `written_out` contains the length of the message. + /// + /// The ownership of the returned buffer is transferred to the runtime + /// code and the runtime is responsible for freeing it. This is always + /// a properly allocated pointer (which cannot be NULL), hence the + /// runtime code can always rely on it. + fn ext_public_keys(crypto: u32, key_type: u32, written_out: *mut u32) -> *mut u8; /// Encrypt a piece of data using given crypto key. /// - /// If `key` is `0`, it will attempt to use current authority key of given `kind`. - /// /// # Returns /// /// - `0` in case the key is invalid, `msg_len` is set to `u32::max_value` /// - Otherwise, pointer to the encrypted message in memory, /// `msg_len` contains the length of the message. fn ext_encrypt( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, msg_len: *mut u32 @@ -438,8 +441,6 @@ pub mod ext { /// Decrypt a piece of data using given crypto key. /// - /// If `key` is `0`, it will attempt to use current authority key of given `kind`. - /// /// # Returns /// /// - `0` in case the key is invalid or data couldn't be decrypted, @@ -447,7 +448,8 @@ pub mod ext { /// - Otherwise, pointer to the decrypted message in memory, /// `msg_len` contains the length of the message. fn ext_decrypt( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, msg_len: *mut u32 @@ -455,8 +457,6 @@ pub mod ext { /// Sign a piece of data using given crypto key. /// - /// If `key` is `0`, it will attempt to use current authority key of given `kind`. - /// /// # Returns /// /// - `0` in case the key is invalid, @@ -464,7 +464,8 @@ pub mod ext { /// - Otherwise, pointer to the signature in memory, /// `sig_data_len` contains the length of the signature. fn ext_sign( - key: u64, + key: *const u8, + key_len: u32, data: *const u8, data_len: u32, sig_data_len: *mut u32 @@ -472,14 +473,13 @@ pub mod ext { /// Verifies that `signature` for `msg` matches given `key`. /// - /// If `key` is `0`, it will attempt to use current authority key of given `kind`. - /// /// # Returns /// - `0` in case the signature is correct /// - `1` in case it doesn't match the key /// - `u32::max_value` if the key is invalid. fn ext_verify( - key: u64, + key: *const u8, + key_len: u32, msg: *const u8, msg_len: u32, signature: *const u8, @@ -925,12 +925,17 @@ impl OffchainApi for () { } } - fn pubkey(key: CryptoKey) -> Result, ()> { - let mut len = 0u32; + fn new_key( + crypto: offchain::CryptoKind, + key_type: offchain::KeyType, + ) -> Result { + let crypto = crypto.into(); + let mut len = 0_u32; let raw_result = unsafe { - let ptr = ext_pubkey.get()( - key.into(), - &mut len, + let ptr = ext_new_key.get()( + crypto, + key_type, + &mut len ); from_raw_parts(ptr, len) @@ -942,25 +947,38 @@ impl OffchainApi for () { } } - fn new_crypto_key( + fn public_keys( crypto: offchain::CryptoKind, key_type: offchain::KeyType, - ) -> Result { + ) -> Result, ()> { let crypto = crypto.into(); - let ret = unsafe { - ext_new_crypto_key.get()(crypto, key_type) + let mut len = 0u32; + let raw_result = unsafe { + let ptr = ext_public_keys.get()( + crypto, + key_type, + &mut len, + ); + + from_raw_parts(ptr, len) }; - offchain::CryptoKey::try_from(ret) + + match raw_result { + Some(raw_result) => codec::Decode::decode(&mut &*raw_result).unwrap_or(Err(())), + None => Err(()) + } } fn encrypt( key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { + let key = key.encode(); let mut len = 0_u32; unsafe { let ptr = ext_encrypt.get()( - key.into(), + key.as_ptr(), + key.len() as u32, data.as_ptr(), data.len() as u32, &mut len @@ -974,10 +992,12 @@ impl OffchainApi for () { key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { + let key = key.encode(); let mut len = 0_u32; unsafe { let ptr = ext_decrypt.get()( - key.into(), + key.as_ptr(), + key.len() as u32, data.as_ptr(), data.len() as u32, &mut len @@ -991,10 +1011,12 @@ impl OffchainApi for () { key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { + let key = key.encode(); let mut len = 0_u32; unsafe { let ptr = ext_sign.get()( - key.into(), + key.as_ptr(), + key.len() as u32, data.as_ptr(), data.len() as u32, &mut len @@ -1009,9 +1031,11 @@ impl OffchainApi for () { msg: &[u8], signature: &[u8], ) -> Result { + let key = key.encode(); let val = unsafe { ext_verify.get()( - key.into(), + key.as_ptr(), + key.len() as u32, msg.as_ptr(), msg.len() as u32, signature.as_ptr(), diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index effbbb26dd12c..215c96778e17d 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -26,7 +26,6 @@ use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::{ValidTransaction, TransactionValidity}; use crate::generic::{Digest, DigestItem}; use crate::weights::DispatchInfo; -pub use primitives::crypto::TypedKey; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 6d228398364e3..7bd9c75c9a141 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -246,23 +246,24 @@ impl offchain::Externalities for NeverOffchainExt { unreachable!() } - fn pubkey( - &self, - _key: offchain::CryptoKey, - ) -> Result, ()> { + fn new_key( + &mut self, + _crypto: offchain::CryptoKind, + _key_type: offchain::KeyTypeId, + ) -> Result { unreachable!() } - fn new_crypto_key( - &mut self, + fn public_keys( + &self, _crypto: offchain::CryptoKind, _key_type: offchain::KeyTypeId, - ) -> Result { + ) -> Result, ()> { unreachable!() } fn encrypt( - &mut self, + &self, _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -270,7 +271,7 @@ impl offchain::Externalities for NeverOffchainExt { } fn decrypt( - &mut self, + &self, _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -278,7 +279,7 @@ impl offchain::Externalities for NeverOffchainExt { } fn sign( - &mut self, + &self, _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -286,7 +287,7 @@ impl offchain::Externalities for NeverOffchainExt { } fn verify( - &mut self, + &self, _key: offchain::CryptoKey, _msg: &[u8], _signature: &[u8], diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 1df9bc5873933..f33e082d03bf5 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -614,12 +614,12 @@ mod tests { assert_eq!(Session::validators(), vec![1, 2, 3]); assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1))); - let id = ::KEY_TYPE; - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); + let id = ::ID; + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(&id.0)), Some(1)); Session::on_free_balance_zero(&1); assert_eq!(Session::load_keys(&1), None); - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None); + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(&id.0)), None); assert!(Changed::get()); }) From ac419a45de83e3dcb86d040dcc23c6909a86f7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 13:42:16 +0200 Subject: [PATCH 15/80] Rework API implementation. --- core/offchain/src/api.rs | 198 +++++++++++++--------------------- core/offchain/src/lib.rs | 85 +++------------ core/offchain/src/testing.rs | 20 ++-- core/primitives/src/crypto.rs | 2 +- 4 files changed, 105 insertions(+), 200 deletions(-) diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index ce73fb431f330..96f12a58bbfeb 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -21,97 +21,55 @@ use std::{ time::{SystemTime, Duration}, thread::sleep, }; + use client::backend::OffchainStorage; -use crate::AuthorityKeyProvider; use futures::{Stream, Future, sync::mpsc}; +use keystore::Store as Keystore; use log::{info, debug, warn, error}; +use network::{PeerId, Multiaddr, NetworkStateInfo}; use parity_codec::{Encode, Decode}; +use primitives::crypto::{Pair, Public}; use primitives::offchain::{ - Timestamp, - HttpRequestId, HttpRequestStatus, HttpError, + CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, - CryptoKind, CryptoKey, - StorageKind, + HttpRequestId, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, + StorageKind, + Timestamp, }; -use primitives::crypto::{Pair, Public, Protected}; use primitives::{ed25519, sr25519}; use sr_primitives::{ generic::BlockId, traits::{self, Extrinsic}, }; use transaction_pool::txpool::{Pool, ChainApi}; -use network::NetworkStateInfo; -use network::{PeerId, Multiaddr}; /// A message between the offchain extension and the processing thread. enum ExtMessage { SubmitExtrinsic(Vec), } -/// A persisted key seed. -#[derive(Encode, Decode)] -struct StoredKey { - kind: CryptoKind, - phrase: String, -} - -impl StoredKey { - fn generate_with_phrase(kind: CryptoKind, password: Option<&str>) -> Option { - Ok(match kind { - CryptoKind::Ed25519 => { - let phrase = ed25519::Pair::generate_with_phrase(password).1; - Self { kind, phrase } - } - CryptoKind::Sr25519 => { - let phrase = sr25519::Pair::generate_with_phrase(password).1; - Self { kind, phrase } - } - CryptoKind::Dummy => Self { kind, phrase: String::new() }, - CryptoKind::User => return None, - }) - } - - fn to_local_key(&self, password: Option<&str>) -> Result { - match self.kind { - CryptoKind::Ed25519 => { - ed25519::Pair::from_phrase(&self.phrase, password) - .map(|x| LocalKey::Ed25519(x.0)) - } - CryptoKind::Sr25519 => { - sr25519::Pair::from_phrase(&self.phrase, password) - .map(|x| LocalKey::Sr25519(x.0)) - } - _ => Err(())?, - } - .map_err(|e| { - warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); - () - }) - } -} - -enum LocalKey { +enum KnownCryptoKey { Ed25519(ed25519::Pair), Sr25519(sr25519::Pair), } -impl LocalKey { +impl KnownCryptoKey { fn public(&self) -> Result, ()> { match self { - LocalKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()), - LocalKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()), + KnownCryptoKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()), + KnownCryptoKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()), } } fn sign(&self, data: &[u8]) -> Result, ()> { match self { - LocalKey::Ed25519(pair) => { + KnownCryptoKey::Ed25519(pair) => { let sig = pair.sign(data); let bytes: &[u8] = sig.as_ref(); Ok(bytes.to_vec()) } - LocalKey::Sr25519(pair) => { + KnownCryptoKey::Sr25519(pair) => { let sig = pair.sign(data); let bytes: &[u8] = sig.as_ref(); Ok(bytes.to_vec()) @@ -121,24 +79,24 @@ impl LocalKey { fn verify(&self, msg: &[u8], signature: &[u8]) -> Result { match self { - LocalKey::Ed25519(pair) => { + KnownCryptoKey::Ed25519(pair) => { Ok(ed25519::Pair::verify_weak(signature, msg, pair.public())) } - LocalKey::Sr25519(pair) => { + KnownCryptoKey::Sr25519(pair) => { Ok(sr25519::Pair::verify_weak(signature, msg, pair.public())) } } } } + /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). -pub(crate) struct Api { +pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, - keys_password: Protected, - key_provider: KeyProvider, + keystore: Arc, network_state: Arc, at: BlockId, } @@ -151,44 +109,54 @@ fn unavailable_yet(name: &str) -> R { const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; const STORAGE_PREFIX: &[u8] = b"storage"; -const KEYS_PREFIX: &[u8] = b"keys"; -const NEXT_ID: &[u8] = b"crypto_key_id"; - -impl Api where +impl Api where Storage: OffchainStorage, - KeyProvider: AuthorityKeyProvider, Block: traits::Block, { - fn password(&self) -> Option<&str> { - Some(self.keys_password.as_ref().as_str()) + fn check_allowed(&self, key_type: &KeyTypeId) -> Result<(), ()> { + // TODO [ToDr] whitelist or blacklist? + Ok(()) } - fn read_key( + fn keys( &self, - key: CryptoKey, - ) -> Result { - let CryptoKey { id, kind } = key; - let key = id.using_encoded(|id| self.db.get(KEYS_PREFIX, id)) - .and_then(|key| StoredKey::decode(&mut &*key)) - .ok_or(())?; - if key.kind != kind { - warn!( - "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", - key.kind, - kind, - id - ); - return Err(()) + kind: CryptoKind, + key_type: KeyTypeId, + ) -> Result { + self.check_allowed(&key_type)?; + + match kind { + CryptoKind::Sr25519 => { + //self.keystore.contents_by_type(key_type) + unimplemented!() + }, + CryptoKind::Ed25519 => { + //self.keystore.contents_by_type(key_type) + unimplemented!() + }, + CryptoKind::User => { + unavailable_yet::<()>("custom crypto"); + Err(()) + }, + CryptoKind::Dummy => { + unavailable_yet::<()>("dummy crypto"); + Err(()) + }, } - Ok(key.to_local_key(self.password())?) + } + + fn get_key( + &self, + key: CryptoKey, + ) -> Result { + unimplemented!() } } -impl OffchainExt for Api +impl OffchainExt for Api where Storage: OffchainStorage, - KeyProvider: AuthorityKeyProvider, Block: traits::Block, { fn submit_transaction(&mut self, ext: Vec) -> Result<(), ()> { @@ -198,32 +166,6 @@ where .map_err(|_| ()) } - fn new_key(&self, crypto: Kind, key_type: KeyTypeId) -> Result { - // let key = StoredKey::generate_with_phrase(crypto, self.password()); - // let (id, id_encoded) = loop { - // let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); - // let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); - // let new_id = encoded_slice.and_then(|mut x| u16::decode(&mut x)).unwrap_or_default() - // .checked_add(1) - // .ok_or(())?; - // let new_id_encoded = new_id.encode(); - // - // if self.db.compare_and_set(KEYS_PREFIX, NEXT_ID, encoded_slice, &new_id_encoded) { - // break (new_id, new_id_encoded); - // } - // }; - // - // self.db.set(KEYS_PREFIX, &id_encoded, &key.encode()); - // - // Ok(CryptoKey::LocalKey { id, kind }) - unavailable_yet::<()>("new_key"); - Err(()) - } - - fn public_key(&self, crypto: Kind, key_type: KeyTypeId) -> Result { - self.read_key(key)?.public() - } - fn network_state(&self) -> Result { let external_addresses = self.network_state.external_addresses(); @@ -234,23 +176,33 @@ where Ok(OpaqueNetworkState::from(state)) } - fn encrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { + fn new_key(&mut self, _crypto: CryptoKind, _key_type: KeyTypeId) -> Result { + unavailable_yet::<()>("new_key"); + Err(()) + } + + fn public_keys(&self, crypto: CryptoKind, key_type: KeyTypeId) -> Result, ()> { + // TODO + unimplemented!() + } + + fn encrypt(&self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("encrypt"); Err(()) } - fn decrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { + fn decrypt(&self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("decrypt"); Err(()) } - fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { - self.read_key(key)?.sign(data) + fn sign(&self, key: CryptoKey, data: &[u8]) -> Result, ()> { + self.get_key(key)?.sign(data) } - fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { - self.read_key(key)?.verify(msg, signature) + fn verify(&self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { + self.get_key(key)?.verify(msg, signature) } fn timestamp(&mut self) -> Timestamp { @@ -445,21 +397,19 @@ pub(crate) struct AsyncApi { impl AsyncApi { /// Creates new Offchain extensions API implementation an the asynchronous processing part. - pub fn new>( + pub fn new( transaction_pool: Arc>, db: S, - keys_password: Protected, - key_provider: P, + keystore: Arc, at: BlockId, network_state: Arc, - ) -> (Api, AsyncApi) { + ) -> (Api, AsyncApi) { let (sender, rx) = mpsc::unbounded(); let api = Api { sender, db, - keys_password, - key_provider, + keystore, network_state, at, }; diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index feacb535aac6a..a70c06f6de392 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -40,18 +40,16 @@ use std::{ }; use client::runtime_api::ApiExt; +use futures::future::Future; +use keystore::Store as Keystore; use log::{debug, warn}; -use primitives::{ - ExecutionContext, - crypto, -}; +use network::NetworkStateInfo; +use primitives::{ExecutionContext, crypto,}; use sr_primitives::{ generic::BlockId, traits::{self, ProvideRuntimeApi}, }; -use futures::future::Future; use transaction_pool::txpool::{Pool, ChainApi}; -use network::NetworkStateInfo; mod api; @@ -59,61 +57,41 @@ pub mod testing; pub use offchain_primitives::OffchainWorkerApi; -/// Provides currently configured authority key. -pub trait AuthorityKeyProvider: Clone + 'static { - /// The crypto used by the block authoring algorithm. - type ConsensusPair: crypto::Pair; - /// The crypto used by the finality gadget. - type FinalityPair: crypto::Pair; - - /// Returns currently configured authority key. - fn authority_key(&self, block_id: &BlockId) -> Option; - - /// Returns currently configured finality gadget authority key. - fn fg_authority_key(&self, block_id: &BlockId) -> Option; -} - /// An offchain workers manager. pub struct OffchainWorkers< Client, Storage, - KeyProvider, Block: traits::Block, > { client: Arc, db: Storage, - authority_key: KeyProvider, - keys_password: crypto::Protected, + keystore: Arc, _block: PhantomData, } -impl OffchainWorkers< +impl OffchainWorkers< Client, Storage, - KeyProvider, Block, > { /// Creates new `OffchainWorkers`. pub fn new( client: Arc, db: Storage, - authority_key: KeyProvider, - keys_password: crypto::Protected, + keystore: Arc, ) -> Self { Self { client, db, - authority_key, - keys_password, + keystore, _block: PhantomData, } } } -impl fmt::Debug for OffchainWorkers< +impl fmt::Debug for OffchainWorkers< Client, Storage, - KeyProvider, Block, > { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -121,16 +99,14 @@ impl fmt::Debug for Offchain } } -impl OffchainWorkers< +impl OffchainWorkers< Client, Storage, - KeyProvider, Block, > where Block: traits::Block, Client: ProvideRuntimeApi + Send + Sync + 'static, Client::Api: OffchainWorkerApi, - KeyProvider: AuthorityKeyProvider + Send, Storage: client::backend::OffchainStorage + 'static, { /// Start the offchain workers after given block. @@ -152,8 +128,7 @@ impl OffchainWorkers< let (api, runner) = api::AsyncApi::new( pool.clone(), self.db.clone(), - self.keys_password.clone(), - self.authority_key.clone(), + self.keystore.clone(), at.clone(), network_state.clone(), ); @@ -212,36 +187,6 @@ mod tests { } } - #[derive(Clone)] - pub(crate) struct TestProvider { - _marker: PhantomData, - pub(crate) sr_key: Option, - pub(crate) ed_key: Option, - } - - impl Default for TestProvider { - fn default() -> Self { - Self { - _marker: PhantomData, - sr_key: None, - ed_key: None, - } - } - } - - impl AuthorityKeyProvider for TestProvider { - type ConsensusPair = ed25519::Pair; - type FinalityPair = sr25519::Pair; - - fn authority_key(&self, _: &BlockId) -> Option { - self.ed_key.clone() - } - - fn fg_authority_key(&self, _: &BlockId) -> Option { - self.sr_key.clone() - } - } - #[test] fn should_call_into_runtime_and_produce_extrinsic() { // given @@ -250,11 +195,13 @@ mod tests { let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone()))); let db = client_db::offchain::LocalStorage::new_test(); - let mock = Arc::new(MockNetworkStateInfo()); + let network_state = Arc::new(MockNetworkStateInfo()); + // TODO Test keystore + let keystore = unimplemented!(); // when - let offchain = OffchainWorkers::new(client, db, TestProvider::default(), "".to_owned().into()); - runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, mock.clone())); + let offchain = OffchainWorkers::new(client, db, keystore, "".to_owned().into()); + runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone())); // then runtime.shutdown_on_idle().wait().unwrap(); diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index 691bf3d681da6..69f4aeded0d1c 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -145,16 +145,24 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn pubkey(&self, _key: CryptoKey) -> Result, ()> { + fn new_key( + &mut self, + _crypto: CryptoKind, + _key_type: KeyTypeId + ) -> Result { unimplemented!("not needed in tests so far") } - fn new_crypto_key(&mut self, _crypto: CryptoKind, _key_type: KeyTypeId) -> Result { + fn public_keys( + &self, + _crypto: CryptoKind, + _key_type: KeyTypeId, + ) -> Result, ()> { unimplemented!("not needed in tests so far") } fn encrypt( - &mut self, + &self, _key: CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -162,7 +170,7 @@ impl offchain::Externalities for TestOffchainExt { } fn decrypt( - &mut self, + &self, _key: CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -170,7 +178,7 @@ impl offchain::Externalities for TestOffchainExt { } fn sign( - &mut self, + &self, _key: CryptoKey, _data: &[u8], ) -> Result, ()> { @@ -178,7 +186,7 @@ impl offchain::Externalities for TestOffchainExt { } fn verify( - &mut self, + &self, _key: CryptoKey, _msg: &[u8], _signature: &[u8], diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 97c11654c2183..263b2e10e0850 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -278,7 +278,7 @@ pub trait Ss58Codec: Sized { } } -#[cfg(feature = "std")] +//#[cfg(feature = "std")] /// Derivable key trait. pub trait Derive: Sized { /// Derive a child key from a series of given junctions. From e1402128554f63b0100877294b0d2d47fafb5be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 14:52:15 +0200 Subject: [PATCH 16/80] Make it compile for wasm, simplify app_crypto. --- core/consensus/aura/primitives/src/lib.rs | 6 +- core/consensus/babe/primitives/src/lib.rs | 2 +- core/finality-grandpa/primitives/src/lib.rs | 4 +- core/primitives/src/crypto.rs | 285 +++++++++++--------- core/primitives/src/ed25519.rs | 12 +- core/primitives/src/sr25519.rs | 13 +- core/sr-io/without_std.rs | 16 +- srml/im-online/src/lib.rs | 2 +- 8 files changed, 186 insertions(+), 154 deletions(-) diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 974fb9187c632..1bc6a1e4f6a3b 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -24,8 +24,8 @@ use rstd::vec::Vec; use sr_primitives::ConsensusEngineId; mod app_sr25519 { - use substrate_primitives::{app_crypto, crypto::key_types::AURA, sr25519}; - app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, AURA); + use primitives::{app_crypto, crypto::key_types::AURA, sr25519}; + app_crypto!(sr25519, AURA); } pub mod sr25519 { @@ -42,7 +42,7 @@ pub mod sr25519 { mod app_ed25519 { use substrate_primitives::{app_crypto, crypto::key_types::AURA, ed25519}; - app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, AURA); + app_crypto!(ed25519, AURA); } pub mod ed25519 { diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index d05688896775c..38d7a9c934fcd 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -32,7 +32,7 @@ pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest}; mod app { use primitives::{app_crypto, crypto::key_types::BABE, sr25519}; - app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, BABE); + app_crypto!(sr25519, BABE); } /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 59109035ba94d..009b8dcfa85e9 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -29,8 +29,8 @@ use client::decl_runtime_apis; use rstd::vec::Vec; mod app { - use substrate_primitives::{app_crypto, crypto::key_types::GRANDPA, ed25519}; - app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, GRANDPA); + use primitives::{app_crypto, crypto::key_types::GRANDPA, ed25519}; + app_crypto!(ed25519, GRANDPA); } /// The grandpa crypto scheme defined via the keypair type. diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 263b2e10e0850..029c7aa2fd4da 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -278,12 +278,12 @@ pub trait Ss58Codec: Sized { } } -//#[cfg(feature = "std")] /// Derivable key trait. pub trait Derive: Sized { /// Derive a child key from a series of given junctions. /// /// Will be `None` for public keys if there are any hard junctions in there. + #[cfg(feature = "std")] fn derive>(&self, _path: Iter) -> Option { None } @@ -471,74 +471,81 @@ pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + Pa fn as_slice(&self) -> &[u8] { self.as_ref() } } -/// Dummy cryptography. Doesn't do anything. -#[derive(Clone, Hash, Default, Eq, PartialEq)] -pub struct Dummy; +#[cfg(feature = "std")] +pub use self::dummy::*; -impl AsRef<[u8]> for Dummy { - fn as_ref(&self) -> &[u8] { &b""[..] } -} +#[cfg(feature = "std")] +mod dummy { + use super::*; + + /// Dummy cryptography. Doesn't do anything. + #[derive(Clone, Hash, Default, Eq, PartialEq)] + pub struct Dummy; -impl AsMut<[u8]> for Dummy { - fn as_mut(&mut self) -> &mut[u8] { - unsafe { - #[allow(mutable_transmutes)] - rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..]) + impl AsRef<[u8]> for Dummy { + fn as_ref(&self) -> &[u8] { &b""[..] } + } + + impl AsMut<[u8]> for Dummy { + fn as_mut(&mut self) -> &mut[u8] { + unsafe { + #[allow(mutable_transmutes)] + rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..]) + } } } -} -impl CryptoType for Dummy { - const KIND: Kind = Kind::Dummy; - type Pair = Dummy; -} + impl CryptoType for Dummy { + const KIND: Kind = Kind::Dummy; + type Pair = Dummy; + } -impl Derive for Dummy {} + impl Derive for Dummy {} -/// Trait suitable for typical cryptographic PKI key public type. -impl Public for Dummy { - fn from_slice(_: &[u8]) -> Self { Self } - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { vec![] } - fn as_slice(&self) -> &[u8] { b"" } -} -#[cfg(feature = "std")] -impl Pair for Dummy { - type Public = Dummy; - type Seed = Dummy; - type Signature = Dummy; - type DeriveError = (); - fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() } - fn from_phrase(_: &str, _: Option<&str>) - -> Result<(Self, Self::Seed), SecretStringError> - { - Ok(Default::default()) + impl Public for Dummy { + fn from_slice(_: &[u8]) -> Self { Self } + #[cfg(feature = "std")] + fn to_raw_vec(&self) -> Vec { vec![] } + fn as_slice(&self) -> &[u8] { b"" } + } + + impl Pair for Dummy { + type Public = Dummy; + type Seed = Dummy; + type Signature = Dummy; + type DeriveError = (); + fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() } + fn from_phrase(_: &str, _: Option<&str>) + -> Result<(Self, Self::Seed), SecretStringError> + { + Ok(Default::default()) + } + fn derive< + Iter: Iterator + >(&self, _: Iter) -> Result { Ok(Self) } + fn from_seed(_: &Self::Seed) -> Self { Self } + fn from_seed_slice(_: &[u8]) -> Result { Ok(Self) } + fn from_standard_components< + I: Iterator + >( + _: &str, + _: Option<&str>, + _: I + ) -> Result { Ok(Self) } + fn sign(&self, _: &[u8]) -> Self::Signature { Self } + fn verify, M: AsRef<[u8]>>( + _: &Self::Signature, + _: M, + _: P + ) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>( + _: &[u8], + _: M, + _: P + ) -> bool { true } + fn public(&self) -> Self::Public { Self } + fn to_raw_vec(&self) -> Vec { vec![] } } - fn derive< - Iter: Iterator - >(&self, _: Iter) -> Result { Ok(Self) } - fn from_seed(_: &Self::Seed) -> Self { Self } - fn from_seed_slice(_: &[u8]) -> Result { Ok(Self) } - fn from_standard_components< - I: Iterator - >( - _: &str, - _: Option<&str>, - _: I - ) -> Result { Ok(Self) } - fn sign(&self, _: &[u8]) -> Self::Signature { Self } - fn verify, M: AsRef<[u8]>>( - _: &Self::Signature, - _: M, - _: P - ) -> bool { true } - fn verify_weak, M: AsRef<[u8]>>( - _: &[u8], - _: M, - _: P - ) -> bool { true } - fn public(&self) -> Self::Public { Self } - fn to_raw_vec(&self) -> Vec { vec![] } } /// Trait suitable for typical cryptographic PKI key pair type. @@ -689,6 +696,7 @@ pub enum Kind { Dummy = !0, } +#[cfg(feature = "std")] impl TryFrom for Kind { type Error = (); @@ -697,7 +705,6 @@ impl TryFrom for Kind { e if e == Kind::User as usize as u32 => Kind::User, e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, - #[cfg(feature = "std")] e if e == Kind::Dummy as usize as u32 => Kind::Dummy, _ => Err(())?, }) @@ -754,6 +761,7 @@ pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { type Public: AppPublic; /// The corresponding key pair type in this application scheme. + #[cfg(feature="std")] type Pair: AppPair; /// The corresponding signature type in this application scheme. @@ -772,6 +780,8 @@ impl MaybeDebugHash for T {} /// Type which implements Debug and Hash in std, not when no-std (no-std variant). #[cfg(not(feature = "std"))] pub trait MaybeDebugHash {} +#[cfg(not(feature = "std"))] +impl MaybeDebugHash for T {} /// A application's public key. pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec { @@ -781,6 +791,7 @@ pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + Maybe } /// A application's public key. +#[cfg(feature = "std")] pub trait AppPair: AppKey + Pair::Public> { /// The wrapped type which is just a plain instance of `Pair`. type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; @@ -866,74 +877,14 @@ macro_rules! wrap { /// ``` #[macro_export] macro_rules! app_crypto { + ($module:ident, $key_type:expr) => { + #[cfg(feature="std")] + $crate::app_crypto!($module::Pair, $module::Public, $module::Signature, $key_type); + #[cfg(not(feature="std"))] + $crate::app_crypto!($module::Public, $module::Signature, $key_type); + }; ($pair:ty, $public:ty, $sig:ty, $key_type:expr) => { - $crate::wrap!{ - /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)] - #[cfg_attr(feature = "std", derive(Debug, Hash))] - pub struct Public($public); - } - // TODO: needed for verify since it takes an AsRef, but should be removed once that is - // refactored. - $crate::impl_as_ref_mut!(Public); - - #[cfg(feature = "std")] - impl $crate::crypto::Derive for Public { - fn derive>(&self, - path: Iter - ) -> Option { - self.0.derive(path).map(Self) - } - } - #[cfg(feature = "std")] - impl ::std::fmt::Display for Public { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - use $crate::crypto::Ss58Codec; - write!(f, "{}", self.0.to_ss58check()) - } - } - #[cfg(feature = "std")] - impl $crate::serde::Serialize for Public { - fn serialize(&self, serializer: S) -> std::result::Result where - S: $crate::serde::Serializer - { - use $crate::crypto::Ss58Codec; - serializer.serialize_str(&self.to_ss58check()) - } - } - #[cfg(feature = "std")] - impl<'de> $crate::serde::Deserialize<'de> for Public { - fn deserialize(deserializer: D) -> std::result::Result where - D: $crate::serde::Deserializer<'de> - { - use $crate::crypto::Ss58Codec; - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) - } - } - impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { self.0.as_ref() } - } - impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } - } - impl $crate::crypto::CryptoType for Public { - const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; - type Pair = Pair; - } - impl $crate::crypto::Public for Public { - fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } - } - impl $crate::crypto::AppKey for Public { - type UntypedGeneric = $public; - type Public = Public; - type Pair = Pair; - type Signature = Signature; - const ID: $crate::crypto::KeyTypeId = $key_type; - } - impl $crate::crypto::AppPublic for Public { - type Generic = $public; - } + $crate::app_crypto!($public, $sig, $key_type); $crate::wrap!{ /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. @@ -1008,6 +959,77 @@ macro_rules! app_crypto { impl $crate::crypto::AppPair for Pair { type Generic = $pair; } + }; + ($public:ty, $sig:ty, $key_type:expr) => { + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Public($public); + } + // TODO: needed for verify since it takes an AsRef, but should be removed once that is + // refactored. + $crate::impl_as_ref_mut!(Public); + + impl $crate::crypto::Derive for Public { + #[cfg(feature = "std")] + fn derive>(&self, + path: Iter + ) -> Option { + self.0.derive(path).map(Self) + } + } + #[cfg(feature = "std")] + impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use $crate::crypto::Ss58Codec; + write!(f, "{}", self.0.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl $crate::serde::Serialize for Public { + fn serialize(&self, serializer: S) -> std::result::Result where + S: $crate::serde::Serializer + { + use $crate::crypto::Ss58Codec; + serializer.serialize_str(&self.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl<'de> $crate::serde::Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> std::result::Result where + D: $crate::serde::Deserializer<'de> + { + use $crate::crypto::Ss58Codec; + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) + } + } + impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } + } + impl $crate::crypto::CryptoType for Public { + const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; + #[cfg(feature="std")] + type Pair = Pair; + } + impl $crate::crypto::Public for Public { + fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } + } + impl $crate::crypto::AppKey for Public { + type UntypedGeneric = $public; + type Public = Public; + #[cfg(feature="std")] + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppPublic for Public { + type Generic = $public; + } $crate::wrap!{ /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. @@ -1020,12 +1042,14 @@ macro_rules! app_crypto { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl $crate::crypto::CryptoType for Signature { - const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; + #[cfg(feature="std")] type Pair = Pair; } impl $crate::crypto::AppKey for Signature { type UntypedGeneric = $sig; type Public = Public; + #[cfg(feature="std")] type Pair = Pair; type Signature = Signature; const ID: $crate::crypto::KeyTypeId = $key_type; @@ -1044,6 +1068,7 @@ pub trait CryptoType { const KIND: Kind; /// The pair key type of this crypto. + #[cfg(feature="std")] type Pair: Pair; } diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 4e34c53fd7230..213bfa8843ffb 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -29,11 +29,11 @@ use substrate_bip39::seed_from_entropy; #[cfg(feature = "std")] use bip39::{Mnemonic, Language, MnemonicType}; #[cfg(feature = "std")] -use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec}; +use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec}; #[cfg(feature = "std")] use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; use crate::{impl_as_ref_mut, crypto::{ - Public as TraitPublic, UncheckedFrom, CryptoType, Kind + Public as TraitPublic, UncheckedFrom, CryptoType, Kind, Derive }}; /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys @@ -306,7 +306,6 @@ impl TraitPublic for Public { } } -#[cfg(feature = "std")] impl Derive for Public {} /// Derive a single hard junction. @@ -468,11 +467,13 @@ impl Pair { impl CryptoType for Public { const KIND: Kind = Kind::Ed25519; + #[cfg(feature="std")] type Pair = Pair; } impl CryptoType for Signature { const KIND: Kind = Kind::Ed25519; + #[cfg(feature="std")] type Pair = Pair; } @@ -484,12 +485,13 @@ impl CryptoType for Pair { mod app { use crate::crypto::key_types::ED25519; - crate::app_crypto!(super::Pair, super::Public, super::Signature, ED25519); + crate::app_crypto!(super, ED25519); } pub use app::Public as AppPublic; -pub use app::Pair as AppPair; pub use app::Signature as AppSignature; +#[cfg(feature="std")] +pub use app::Pair as AppPair; #[cfg(test)] mod test { diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 37263ce982403..7265e59c9db7b 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -31,9 +31,9 @@ use substrate_bip39::mini_secret_from_entropy; use bip39::{Mnemonic, Language, MnemonicType}; #[cfg(feature = "std")] use crate::crypto::{ - Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec + Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Ss58Codec }; -use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Kind}}; +use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Kind, Derive}}; use crate::hash::{H256, H512}; use parity_codec::{Encode, Decode}; @@ -266,11 +266,11 @@ impl Signature { } } -#[cfg(feature = "std")] impl Derive for Public { /// Derive a child key from a series of given junctions. /// /// `None` if there are any hard junctions in there. + #[cfg(feature = "std")] fn derive>(&self, path: Iter) -> Option { let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?; for j in path { @@ -505,11 +505,13 @@ impl Pair { impl CryptoType for Public { const KIND: Kind = Kind::Sr25519; + #[cfg(feature="std")] type Pair = Pair; } impl CryptoType for Signature { const KIND: Kind = Kind::Sr25519; + #[cfg(feature="std")] type Pair = Pair; } @@ -521,12 +523,13 @@ impl CryptoType for Pair { mod app { use crate::crypto::key_types::SR25519; - crate::app_crypto!(super::Pair, super::Public, super::Signature, SR25519); + crate::app_crypto!(super, SR25519); } pub use app::Public as AppPublic; -pub use app::Pair as AppPair; pub use app::Signature as AppSignature; +#[cfg(feature = "std")] +pub use app::Pair as AppPair; #[cfg(test)] mod test { diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 31433441f36ce..3b38045818e48 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -19,7 +19,7 @@ pub use rstd; pub use rstd::{mem, slice}; use core::{intrinsics, panic::PanicInfo}; -use rstd::{vec::Vec, cell::Cell, convert::TryInto, convert::TryFrom}; +use rstd::{vec::Vec, cell::Cell, convert::TryInto}; use primitives::{offchain, Blake2Hasher}; #[cfg(not(feature = "no_panic_handler"))] @@ -927,9 +927,10 @@ impl OffchainApi for () { fn new_key( crypto: offchain::CryptoKind, - key_type: offchain::KeyType, + key_type: offchain::KeyTypeId, ) -> Result { let crypto = crypto.into(); + let key_type = key_type.into(); let mut len = 0_u32; let raw_result = unsafe { let ptr = ext_new_key.get()( @@ -949,9 +950,10 @@ impl OffchainApi for () { fn public_keys( crypto: offchain::CryptoKind, - key_type: offchain::KeyType, + key_type: offchain::KeyTypeId, ) -> Result, ()> { let crypto = crypto.into(); + let key_type = key_type.into(); let mut len = 0u32; let raw_result = unsafe { let ptr = ext_public_keys.get()( @@ -973,7 +975,7 @@ impl OffchainApi for () { key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.encode(); + let key = codec::Encode::encode(&key); let mut len = 0_u32; unsafe { let ptr = ext_encrypt.get()( @@ -992,7 +994,7 @@ impl OffchainApi for () { key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.encode(); + let key = codec::Encode::encode(&key); let mut len = 0_u32; unsafe { let ptr = ext_decrypt.get()( @@ -1011,7 +1013,7 @@ impl OffchainApi for () { key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.encode(); + let key = codec::Encode::encode(&key); let mut len = 0_u32; unsafe { let ptr = ext_sign.get()( @@ -1031,7 +1033,7 @@ impl OffchainApi for () { msg: &[u8], signature: &[u8], ) -> Result { - let key = key.encode(); + let key = codec::Encode::encode(&key); let val = unsafe { ext_verify.get()( key.as_ptr(), diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 5022d4b88859d..23c0dcaf20b8d 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -93,7 +93,7 @@ use substrate_primitives::offchain::CryptoKind; mod app { use substrate_primitives::{app_crypto, crypto::key_types::IM_ONLINE, sr25519}; - app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, IM_ONLINE); + app_crypto!(sr25519, IM_ONLINE); } /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in From c4d58bff83864c87684b0d2c0b7a0d1871aa1590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 16:14:32 +0200 Subject: [PATCH 17/80] Fix compilation of im-online. --- srml/im-online/src/lib.rs | 291 ++++++++++++++++++++------------------ 1 file changed, 152 insertions(+), 139 deletions(-) diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 23c0dcaf20b8d..0fda22c9f06d3 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -37,7 +37,6 @@ //! //! ### Public Functions //! -//! - `is_online_in_current_era` - True if the validator sent a heartbeat in the current era. //! - `is_online_in_current_session` - True if the validator sent a heartbeat in the current session. //! //! ## Usage @@ -51,9 +50,9 @@ //! //! decl_module! { //! pub struct Module for enum Call where origin: T::Origin { -//! pub fn is_online(origin, authority_id: T::AuthorityId) -> Result { +//! pub fn is_online(origin, authority_index: u32) -> Result { //! let _sender = ensure_signed(origin)?; -//! let _is_online = >::is_online_in_current_era(&authority_id); +//! let _is_online = >::is_online_in_current_session(&authority_index); //! Ok(()) //! } //! } @@ -69,30 +68,27 @@ #![cfg_attr(not(feature = "std"), no_std)] use primitives::{ - crypto::{AppKey, CryptoType}, - offchain::CryptoKey, - offchain::OpaqueNetworkState, - offchain::StorageKind, - sr25519, - ed25519, + crypto::{CryptoType, KeyTypeId}, + offchain::{OpaqueNetworkState, StorageKind}, }; use parity_codec::{Encode, Decode}; use sr_primitives::{ - ApplyError, traits::{Member, IsMember, Extrinsic as ExtrinsicT}, + ApplyError, traits::{Extrinsic as ExtrinsicT}, transaction_validity::{TransactionValidity, TransactionLongevity, ValidTransaction}, }; use rstd::prelude::*; use session::SessionIndex; use sr_io::Printable; use srml_support::{ - Parameter, StorageValue, decl_module, decl_event, decl_storage, - traits::Get, StorageDoubleMap, print, + StorageValue, decl_module, decl_event, decl_storage, + StorageDoubleMap, print, }; use system::ensure_none; -use substrate_primitives::offchain::CryptoKind; mod app { - use substrate_primitives::{app_crypto, crypto::key_types::IM_ONLINE, sr25519}; + pub use primitives::sr25519 as crypto; + use primitives::{app_crypto, crypto::key_types::IM_ONLINE, sr25519}; + app_crypto!(sr25519, IM_ONLINE); } @@ -128,6 +124,7 @@ struct WorkerStatus { enum OffchainErr { DecodeAuthorityId, DecodeWorkerStatus, + NoKeys, ExtrinsicCreation, FailedSigning, NetworkState, @@ -139,6 +136,7 @@ impl Printable for OffchainErr { match self { OffchainErr::DecodeAuthorityId => print("Offchain error: decoding AuthorityId failed!"), OffchainErr::DecodeWorkerStatus => print("Offchain error: decoding WorkerStatus failed!"), + OffchainErr::NoKeys => print("Offchain error: could not find local keys!"), OffchainErr::ExtrinsicCreation => print("Offchain error: extrinsic creation failed!"), OffchainErr::FailedSigning => print("Offchain error: signing failed!"), OffchainErr::NetworkState => print("Offchain error: fetching network state failed!"), @@ -157,13 +155,13 @@ pub struct Heartbeat { block_number: BlockNumber, network_state: OpaqueNetworkState, - session_index: session::SessionIndex, + session_index: SessionIndex, authority_index: AuthIndex, } pub trait Trait: system::Trait + session::Trait { /// The overarching event type. - type Event: From> + Into<::Event>; + type Event: From + Into<::Event>; /// The function call. type Call: From>; @@ -174,9 +172,7 @@ pub trait Trait: system::Trait + session::Trait { } decl_event!( - pub enum Event where - ::BlockNumber, - { + pub enum Event { /// A new heartbeat was received from `AuthorityId` HeartbeatReceived(AuthorityId), } @@ -190,37 +186,37 @@ decl_storage! { /// The current set of keys that may issue a heartbeat. Keys get(keys) config(): Vec; - /// For each session index we keep a mapping of `AuthorityId` to - /// `offchain::OpaqueNetworkState`. - ReceivedHeartbeats get(received_heartbeats): - double_map session::SessionIndex, AuthIndex => Vec; + /// For each session index we keep a mapping of `AuthorityId` + /// to `offchain::OpaqueNetworkState`. + ReceivedHeartbeats get(received_heartbeats): double_map SessionIndex, + blake2_256(AuthIndex) => Vec; } } + decl_module! { pub struct Module for enum Call where origin: T::Origin { - /// Number of sessions per era. - const SessionsPerEra: session::SessionIndex = T::SessionsPerEra::get(); - - fn deposit_event() = default; + fn deposit_event() = default; fn heartbeat( origin, heartbeat: Heartbeat, - _signature: AuthoritySignature, + _signature: AuthoritySignature ) { ensure_none(origin)?; let current_session = >::current_index(); - let exists = >::exists( + let exists = ::exists( ¤t_session, &heartbeat.authority_index ); - if !exists { - Self::deposit_event(RawEvent::HeartbeatReceived(heartbeat.authority_id.clone())); + let keys = Keys::get(); + let public = keys.get(heartbeat.authority_index as usize); + if let (true, Some(public)) = (!exists, public) { + Self::deposit_event(Event::HeartbeatReceived(public.clone())); let network_state = heartbeat.network_state.encode(); - >::insert( + ::insert( ¤t_session, &heartbeat.authority_index, &network_state @@ -240,103 +236,12 @@ impl Module { /// the authorities series, during the current session. Otherwise `false`. pub fn is_online_in_current_session(authority_index: AuthIndex) -> bool { let current_session = >::current_index(); - >::exists(¤t_session, authority_index) + ::exists(¤t_session, &authority_index) } - fn offchain(new: T::BlockNumber) { - fn gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { - // we run only when a local authority key is configured - let key_type: KeyTypeId = b"imon".into(); - let authorities = Keys::get(); - let maybe_key = authorities.into_iter() - .enumerate() - .filter_map(|(i, id)| sr_io::find_key(id, key_type).ok().map(|x| (i, x))); - if let Some((authority_index, key)) = maybe_key { - let network_state = - sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; - let heartbeat_data = Heartbeat { - block_number, - network_state, - session_index: >::current_index(), - authority_index, - }; - - let signature = sr_io::sign(CryptoKey { key_type, id }, &heartbeat_data.encode()) - .map_err(|_| OffchainErr::FailedSigning)?; - let call = Call::heartbeat(heartbeat_data, signature); - let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) - .ok_or(OffchainErr::ExtrinsicCreation)?; - sr_io::submit_transaction(&ex) - .map_err(|_| OffchainErr::SubmitTransaction)?; - - // once finished we set the worker status without comparing - // if the existing value changed in the meantime. this is - // because at this point the heartbeat was definitely submitted. - set_worker_status::(block_number, true); - } - Ok(()) - } - - fn compare_and_set_worker_status( - gossipping_at: T::BlockNumber, - done: bool, - curr_worker_status: Option>, - ) -> bool { - let enc = WorkerStatus { - done, - gossipping_at, - }; - sr_io::local_storage_compare_and_set( - StorageKind::PERSISTENT, - DB_KEY, - curr_worker_status.as_ref().map(Vec::as_slice), - &enc.encode() - ) - } - - fn set_worker_status( - gossipping_at: T::BlockNumber, - done: bool, - ) { - let enc = WorkerStatus { - done, - gossipping_at, - }; - sr_io::local_storage_set( - StorageKind::PERSISTENT, DB_KEY, &enc.encode()); - } - - // Checks if a heartbeat gossip already occurred at this block number. - // Returns a tuple of `(current worker status, bool)`, whereby the bool - // is true if not yet gossipped. - fn check_not_yet_gossipped( - now: T::BlockNumber, - next_gossip: T::BlockNumber, - ) -> Result<(Option>, bool), OffchainErr> { - let last_gossip = sr_io::local_storage_get(StorageKind::PERSISTENT, DB_KEY); - match last_gossip { - Some(last) => { - let worker_status: WorkerStatus = Decode::decode(&mut &last[..]) - .ok_or(OffchainErr::DecodeWorkerStatus)?; - - let was_aborted = !worker_status.done && worker_status.gossipping_at < now; - - // another off-chain worker is currently in the process of submitting - let already_submitting = - !worker_status.done && worker_status.gossipping_at == now; - - let not_yet_gossipped = - worker_status.done && worker_status.gossipping_at < next_gossip; - - let ret = (was_aborted && !already_submitting) || not_yet_gossipped; - Ok((Some(last), ret)) - }, - None => Ok((None, true)), - } - } - + fn offchain(now: T::BlockNumber) { let next_gossip = >::get(); - let check = check_not_yet_gossipped::(now, next_gossip); + let check = Self::check_not_yet_gossipped(now, next_gossip); let (curr_worker_status, not_yet_gossipped) = match check { Ok((s, v)) => (s, v), Err(err) => { @@ -345,7 +250,7 @@ impl Module { }, }; if next_gossip < now && not_yet_gossipped { - let value_set = compare_and_set_worker_status::(now, false, curr_worker_status); + let value_set = Self::compare_and_set_worker_status(now, false, curr_worker_status); if !value_set { // value could not be set in local storage, since the value was // different from `curr_worker_status`. this indicates that @@ -353,12 +258,117 @@ impl Module { return; } - match gossip_at::(now) { + match Self::do_gossip_at(now) { Ok(_) => {}, Err(err) => print(err), } } } + + fn do_gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { + // we run only when a local authority key is configured + let key_type = KeyTypeId(*b"imon"); + let authorities = Keys::get(); + let local_keys = sr_io::public_keys(AuthorityId::KIND, key_type) + .map_err(|_| OffchainErr::NoKeys)?; + let maybe_key = authorities.into_iter() + .enumerate() + .filter_map(|(index, id)| { + let id = app::crypto::Public::from(id); + let id_slice: &[u8] = id.as_ref(); + + local_keys + .iter() + .find(|k| &*k.public == id_slice) + .map(|key| (index as u32, key.clone())) + }) + .next(); + if let Some((authority_index, key)) = maybe_key { + let network_state = + sr_io::network_state().map_err(|_| OffchainErr::NetworkState)?; + let heartbeat_data = Heartbeat { + block_number, + network_state, + session_index: >::current_index(), + authority_index, + }; + + let signature = sr_io::sign(key, &heartbeat_data.encode()) + .map_err(|_| OffchainErr::FailedSigning)?; + let signature = AuthoritySignature::decode(&mut &*signature) + .ok_or(OffchainErr::ExtrinsicCreation)?; + let call = Call::heartbeat(heartbeat_data, signature); + let ex = T::UncheckedExtrinsic::new_unsigned(call.into()) + .ok_or(OffchainErr::ExtrinsicCreation)?; + sr_io::submit_transaction(&ex) + .map_err(|_| OffchainErr::SubmitTransaction)?; + + // once finished we set the worker status without comparing + // if the existing value changed in the meantime. this is + // because at this point the heartbeat was definitely submitted. + Self::set_worker_status(block_number, true); + } + Ok(()) + } + + fn compare_and_set_worker_status( + gossipping_at: T::BlockNumber, + done: bool, + curr_worker_status: Option>, + ) -> bool { + let enc = WorkerStatus { + done, + gossipping_at, + }; + sr_io::local_storage_compare_and_set( + StorageKind::PERSISTENT, + DB_KEY, + curr_worker_status.as_ref().map(Vec::as_slice), + &enc.encode() + ) + } + + fn set_worker_status( + gossipping_at: T::BlockNumber, + done: bool, + ) { + let enc = WorkerStatus { + done, + gossipping_at, + }; + sr_io::local_storage_set( + StorageKind::PERSISTENT, DB_KEY, &enc.encode()); + } + + // Checks if a heartbeat gossip already occurred at this block number. + // Returns a tuple of `(current worker status, bool)`, whereby the bool + // is true if not yet gossipped. + fn check_not_yet_gossipped( + now: T::BlockNumber, + next_gossip: T::BlockNumber, + ) -> Result<(Option>, bool), OffchainErr> { + let last_gossip = sr_io::local_storage_get(StorageKind::PERSISTENT, DB_KEY); + match last_gossip { + Some(last) => { + let worker_status: WorkerStatus = Decode::decode(&mut &last[..]) + .ok_or(OffchainErr::DecodeWorkerStatus)?; + + let was_aborted = !worker_status.done && worker_status.gossipping_at < now; + + // another off-chain worker is currently in the process of submitting + let already_submitting = + !worker_status.done && worker_status.gossipping_at == now; + + let not_yet_gossipped = + worker_status.done && worker_status.gossipping_at < next_gossip; + + let ret = (was_aborted && !already_submitting) || not_yet_gossipped; + Ok((Some(last), ret)) + }, + None => Ok((None, true)), + } + } + } impl session::OneSessionHandler for Module { @@ -367,14 +377,14 @@ impl session::OneSessionHandler for Module { fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, next_validators: I) where I: Iterator { - /// Reset heartbeats - >::remove_prefix(>::current_index()); + // Reset heartbeats + ::remove_prefix(&>::current_index()); - /// Tell the offchain worker to start making the next session's heartbeats. + // Tell the offchain worker to start making the next session's heartbeats. >::put(>::block_number()); - /// Remember who the authorities are for the new session. - Keys::put(next_validators.map(|x| x.1).collect()); + // Remember who the authorities are for the new session. + Keys::put(next_validators.map(|x| x.1).collect::>()); } fn on_disabled(_i: usize) { @@ -387,7 +397,7 @@ impl srml_support::unsigned::ValidateUnsigned for Module { fn validate_unsigned(call: &Self::Call) -> srml_support::unsigned::TransactionValidity { if let Call::heartbeat(heartbeat, signature) = call { - if >::is_online_in_current_session(&heartbeat.authority_index) { + if >::is_online_in_current_session(heartbeat.authority_index) { // we already received a heartbeat for this authority return TransactionValidity::Invalid(ApplyError::Stale as i8); } @@ -399,19 +409,21 @@ impl srml_support::unsigned::ValidateUnsigned for Module { } // verify that the incoming (unverified) pubkey is actually an authority id - let authority_id = match Keys::get().get(heartbeat.authority_index as usize) { + let keys = Keys::get(); + let authority_id = match keys.get(heartbeat.authority_index as usize) { Some(id) => id, None => return TransactionValidity::Invalid(ApplyError::BadSignature as i8), }; // check signature (this is expensive so we do it last). - let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| + let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| { + let sig: &app::crypto::Signature = signature.as_ref(); sr_io::sr25519_verify( - signature.as_ref(), + sig.as_ref(), encoded_heartbeat, &authority_id ) - ); + }); if !signature_valid { return TransactionValidity::Invalid(ApplyError::BadSignature as i8); } @@ -419,11 +431,12 @@ impl srml_support::unsigned::ValidateUnsigned for Module { return TransactionValidity::Valid(ValidTransaction { priority: 0, requires: vec![], - provides: vec![encoded_heartbeat], + provides: vec![(current_session, authority_id).encode()], longevity: TransactionLongevity::max_value(), propagate: true, }) } + TransactionValidity::Invalid(0) } } From 0d81c469ada6e84b6f05b053ba850e66347dfe1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 16:14:32 +0200 Subject: [PATCH 18/80] Fix compilation of im-online. --- srml/im-online/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 0fda22c9f06d3..46d374d2e9eca 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -52,7 +52,7 @@ //! pub struct Module for enum Call where origin: T::Origin { //! pub fn is_online(origin, authority_index: u32) -> Result { //! let _sender = ensure_signed(origin)?; -//! let _is_online = >::is_online_in_current_session(&authority_index); +//! let _is_online = >::is_online_in_current_session(authority_index); //! Ok(()) //! } //! } @@ -122,7 +122,6 @@ struct WorkerStatus { // Error which may occur while executing the off-chain code. enum OffchainErr { - DecodeAuthorityId, DecodeWorkerStatus, NoKeys, ExtrinsicCreation, @@ -134,7 +133,6 @@ enum OffchainErr { impl Printable for OffchainErr { fn print(self) { match self { - OffchainErr::DecodeAuthorityId => print("Offchain error: decoding AuthorityId failed!"), OffchainErr::DecodeWorkerStatus => print("Offchain error: decoding WorkerStatus failed!"), OffchainErr::NoKeys => print("Offchain error: could not find local keys!"), OffchainErr::ExtrinsicCreation => print("Offchain error: extrinsic creation failed!"), From e1d2fbcc7c64fad7c749010388b132edb1347188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 17:05:28 +0200 Subject: [PATCH 19/80] Fix more compilation errors. --- core/consensus/babe/src/lib.rs | 10 +-- core/offchain/src/api.rs | 81 ++++++++++++++++++++---- core/offchain/src/lib.rs | 6 +- core/service/src/components.rs | 8 +-- core/service/src/lib.rs | 110 +++------------------------------ node/runtime/src/lib.rs | 5 +- 6 files changed, 86 insertions(+), 134 deletions(-) diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 613d6afe5af80..65e53e7a24513 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -221,7 +221,7 @@ pub fn start_babe(BabeParams { struct BabeWorker { client: Arc, block_import: Arc>, - env: Arc, + env: E, local_key: Arc, sync_oracle: SO, force_authoring: bool, @@ -1225,10 +1225,10 @@ fn authority(client: &C, keystore: Arc) -> Option where { let owned = keystore.contents::().ok()?; let at = BlockId::Number(client.info().best_number); - /// The list of authority keys that is current. By default this will just use the state of - /// the best block, but you might want it to use some other block's state instead if it's - /// more sophisticated. Grandpa, for example, will probably want to use the state of the last - /// finalised block. + // The list of authority keys that is current. By default this will just use the state of + // the best block, but you might want it to use some other block's state instead if it's + // more sophisticated. Grandpa, for example, will probably want to use the state of the last + // finalised block. let authorities = authorities_at::(client, &at).ok()?; let maybe_pub = owned.into_iter() .find(|i| authorities.contains(i)); diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 96f12a58bbfeb..2dafed5e2bc2a 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -28,7 +28,7 @@ use keystore::Store as Keystore; use log::{info, debug, warn, error}; use network::{PeerId, Multiaddr, NetworkStateInfo}; use parity_codec::{Encode, Decode}; -use primitives::crypto::{Pair, Public}; +use primitives::crypto::{self, Pair, Public}; use primitives::offchain::{ CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, @@ -96,7 +96,7 @@ impl KnownCryptoKey { pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, - keystore: Arc, + keystore: Arc>, network_state: Arc, at: BlockId, } @@ -107,6 +107,10 @@ fn unavailable_yet(name: &str) -> R { Default::default() } +fn log_error(err: keystore::Error) -> () { + warn!("Keystore error when accessing keys from offchain worker: {}", err); +} + const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; const STORAGE_PREFIX: &[u8] = b"storage"; @@ -115,25 +119,50 @@ impl Api where Block: traits::Block, { fn check_allowed(&self, key_type: &KeyTypeId) -> Result<(), ()> { - // TODO [ToDr] whitelist or blacklist? - Ok(()) + let blacklist = vec![ + crypto::key_types::SR25519, + crypto::key_types::ED25519, + crypto::key_types::BABE, + crypto::key_types::GRANDPA, + crypto::key_types::ACCOUNT, + crypto::key_types::AURA, + ]; + + if blacklist.contains(key_type) { + Err(()) + } else { + Ok(()) + } } fn keys( &self, kind: CryptoKind, key_type: KeyTypeId, - ) -> Result { + ) -> Result, ()> { self.check_allowed(&key_type)?; + let keystore = (&*self.keystore).as_ref().ok_or(())?; match kind { CryptoKind::Sr25519 => { - //self.keystore.contents_by_type(key_type) - unimplemented!() + Ok(keystore.contents_by_type::(key_type) + .map_err(log_error)? + .into_iter() + .map(|key| CryptoKey { + public: key.to_raw_vec(), + key_type, + kind, + }).collect()) }, CryptoKind::Ed25519 => { - //self.keystore.contents_by_type(key_type) - unimplemented!() + Ok(keystore.contents_by_type::(key_type) + .map_err(log_error)? + .into_iter() + .map(|key| CryptoKey { + public: key.to_raw_vec(), + key_type, + kind, + }).collect()) }, CryptoKind::User => { unavailable_yet::<()>("custom crypto"); @@ -150,7 +179,34 @@ impl Api where &self, key: CryptoKey, ) -> Result { - unimplemented!() + self.check_allowed(&key.key_type)?; + + // TODO [ToDr] Remove + let keystore = (&*self.keystore).as_ref().ok_or(())?; + let pass = "".into(); + + match key.kind { + CryptoKind::Sr25519 => { + let public = sr25519::Public::from_slice(&key.public); + keystore.load_by_type(&public, pass, key.key_type) + .map_err(log_error) + .map(KnownCryptoKey::Sr25519) + }, + CryptoKind::Ed25519 => { + let public = ed25519::Public::from_slice(&key.public); + keystore.load_by_type(&public, pass, key.key_type) + .map_err(log_error) + .map(KnownCryptoKey::Ed25519) + }, + CryptoKind::User => { + unavailable_yet::<()>("custom crypto"); + Err(()) + }, + CryptoKind::Dummy => { + unavailable_yet::<()>("dummy crypto"); + Err(()) + }, + } } } @@ -182,8 +238,7 @@ where } fn public_keys(&self, crypto: CryptoKind, key_type: KeyTypeId) -> Result, ()> { - // TODO - unimplemented!() + self.keys(crypto, key_type) } fn encrypt(&self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { @@ -400,7 +455,7 @@ impl AsyncApi { pub fn new( transaction_pool: Arc>, db: S, - keystore: Arc, + keystore: Arc>, at: BlockId, network_state: Arc, ) -> (Api, AsyncApi) { diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index a70c06f6de392..6f95906b65b12 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -44,7 +44,7 @@ use futures::future::Future; use keystore::Store as Keystore; use log::{debug, warn}; use network::NetworkStateInfo; -use primitives::{ExecutionContext, crypto,}; +use primitives::ExecutionContext; use sr_primitives::{ generic::BlockId, traits::{self, ProvideRuntimeApi}, @@ -65,7 +65,7 @@ pub struct OffchainWorkers< > { client: Arc, db: Storage, - keystore: Arc, + keystore: Arc>, _block: PhantomData, } @@ -78,7 +78,7 @@ impl OffchainWorkers< pub fn new( client: Arc, db: Storage, - keystore: Arc, + keystore: Arc>, ) -> Self { Self { client, diff --git a/core/service/src/components.rs b/core/service/src/components.rs index b03fe95e39ae0..13d48949aa08b 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -21,7 +21,7 @@ use serde::{Serialize, de::DeserializeOwned}; use crate::chain_spec::ChainSpec; use client_db; use client::{self, Client, runtime_api}; -use crate::{error, Service, AuthorityKeyProvider}; +use crate::{error, Service}; use consensus_common::{import_queue::ImportQueue, SelectChain}; use network::{self, OnDemand, FinalityProofProvider, NetworkStateInfo, config::BoxFinalityProofRequestBuilder}; use substrate_executor::{NativeExecutor, NativeExecutionDispatch}; @@ -134,10 +134,6 @@ pub type ComponentConsensusPair = <::Factory as ServiceFacto /// FinalityPair type for `Components` pub type ComponentFinalityPair = <::Factory as ServiceFactory>::FinalityPair; -/// AuthorityKeyProvider type for `Components` -pub type ComponentAuthorityKeyProvider = - AuthorityKeyProvider, ComponentConsensusPair, ComponentFinalityPair>; - /// Extrinsic hash type for `Components` pub type ComponentExHash = <::TransactionPoolApi as txpool::ChainApi>::Hash; @@ -241,7 +237,6 @@ pub trait OffchainWorker { offchain: &offchain::OffchainWorkers< ComponentClient, ComponentOffchainStorage, - ComponentAuthorityKeyProvider, ComponentBlock >, pool: &Arc>, @@ -258,7 +253,6 @@ impl OffchainWorker for C where offchain: &offchain::OffchainWorkers< ComponentClient, ComponentOffchainStorage, - ComponentAuthorityKeyProvider, ComponentBlock >, pool: &Arc>, diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 12671f50cd5ed..cbbb8f6def59b 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -26,7 +26,6 @@ pub mod chain_ops; pub mod error; use std::io; -use std::marker::PhantomData; use std::net::SocketAddr; use std::collections::HashMap; use std::time::{Duration, Instant}; @@ -41,9 +40,8 @@ use keystore::Store as Keystore; use network::{NetworkState, NetworkStateInfo}; use log::{log, info, warn, debug, error, Level}; use parity_codec::{Encode, Decode}; -use primitives::{crypto::{self, AppKey, AppPair}}; -use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero}; +use sr_primitives::generic::BlockId; +use sr_primitives::traits::{Header, NumberFor, SaturatedConversion}; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -57,7 +55,7 @@ pub use transaction_pool::txpool::{ pub use client::FinalityNotifications; pub use components::{ - ServiceFactory, FullBackend, FullExecutor, LightBackend, ComponentAuthorityKeyProvider, + ServiceFactory, FullBackend, FullExecutor, LightBackend, LightExecutor, Components, PoolApi, ComponentClient, ComponentOffchainStorage, ComponentBlock, FullClient, LightClient, FullComponents, LightComponents, CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock, @@ -85,7 +83,7 @@ pub struct Service { NetworkStatus>, NetworkState )>>>>, transaction_pool: Arc>, - keystore: ComponentAuthorityKeyProvider, + keystore: Arc>, exit: ::exit_future::Exit, signal: Option, /// Sender for futures that must be spawned as background tasks. @@ -105,7 +103,6 @@ pub struct Service { _offchain_workers: Option, ComponentOffchainStorage, - ComponentAuthorityKeyProvider, ComponentBlock> >>, } @@ -212,6 +209,7 @@ impl Service { } */ public_key = format!(""); + let keystore = Arc::new(keystore); let (client, on_demand) = Components::build_client(&config, executor)?; let select_chain = Components::build_select_chain(&mut config, client.clone())?; @@ -272,13 +270,6 @@ impl Service { let network = network_mut.service().clone(); let network_status_sinks = Arc::new(Mutex::new(Vec::new())); - let keystore_authority_key = AuthorityKeyProvider { - _marker: PhantomData, - roles: config.roles, - password: config.password.clone(), - keystore: keystore.map(Arc::new), - }; - #[allow(deprecated)] let offchain_storage = client.backend().offchain_storage(); let offchain_workers = match (config.offchain_worker, offchain_storage) { @@ -286,8 +277,7 @@ impl Service { Some(Arc::new(offchain::OffchainWorkers::new( client.clone(), db, - keystore_authority_key.clone(), - config.password.clone(), + keystore.clone(), ))) }, (true, None) => { @@ -496,7 +486,7 @@ impl Service { to_spawn_tx, to_spawn_rx, to_poll: Vec::new(), - keystore: keystore_authority_key, + keystore, config, exit, rpc_handlers, @@ -507,20 +497,6 @@ impl Service { }) } - /// give the authority key, if we are an authority and have a key - pub fn authority_key(&self) -> Option> { - use offchain::AuthorityKeyProvider; - - self.keystore.authority_key(&BlockId::Number(Zero::zero())) - } - - /// give the authority key, if we are an authority and have a key - pub fn fg_authority_key(&self) -> Option> { - use offchain::AuthorityKeyProvider; - - self.keystore.fg_authority_key(&BlockId::Number(Zero::zero())) - } - /// return a shared instance of Telemetry (if enabled) pub fn telemetry(&self) -> Option { self._telemetry.as_ref().map(|t| t.clone()) @@ -908,78 +884,6 @@ impl network::TransactionPool, ComponentBlock< } } -#[derive(Clone)] -/// A provider of current authority key. -pub struct AuthorityKeyProvider { - _marker: PhantomData<(Block, ConsensusPair, FinalityPair)>, - roles: Roles, - keystore: Option>, - password: crypto::Protected, -} - -impl - offchain::AuthorityKeyProvider -for - AuthorityKeyProvider -where - Block: sr_primitives::traits::Block, - ConsensusPair: AppPair, - FinalityPair: AppPair, -{ - type ConsensusPair = ConsensusPair; - type FinalityPair = FinalityPair; - - fn authority_key(&self, _at: &BlockId) -> Option { - if self.roles != Roles::AUTHORITY { - return None - } - - let keystore = match self.keystore { - Some(ref keystore) => keystore, - None => return None - }; - - let loaded_key = keystore - .contents::<::Public>() - .map(|keys| keys.get(0) - .map(|k| - keystore.load::(k, self.password.as_ref()) - ) - ); - - if let Ok(Some(Ok(key))) = loaded_key { - Some(key) - } else { - None - } - } - - fn fg_authority_key(&self, _at: &BlockId) -> Option { - if self.roles != Roles::AUTHORITY { - return None - } - - let keystore = match self.keystore { - Some(ref keystore) => keystore, - None => return None - }; - - let loaded_key = keystore - .contents::<::Public>() - .map(|keys| keys.get(0) - .map(|k| - keystore.load::(k, self.password.as_ref()) - ) - ); - - if let Ok(Some(Ok(key))) = loaded_key { - Some(key) - } else { - None - } - } -} - /// Constructs a service factory with the given name that implements the `ServiceFactory` trait. /// The required parameters are required to be given in the exact order. Some parameters are followed /// by `{}` blocks. These blocks are required and used to initialize the given parameter. diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 8bdeec40235c4..914814dcb9e81 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -199,7 +199,7 @@ impl_opaque_keys! { #[id(key_types::BABE)] pub babe: BabeId, #[id(key_types::IM_ONLINE)] - pub babe: ImOnlineId, + pub im_online: ImOnlineId, } } @@ -376,7 +376,6 @@ impl sudo::Trait for Runtime { impl im_online::Trait for Runtime { type Call = Call; type Event = Event; - type SessionsPerEra = SessionsPerEra; type UncheckedExtrinsic = UncheckedExtrinsic; } @@ -418,7 +417,7 @@ construct_runtime!( Treasury: treasury::{Module, Call, Storage, Event}, Contracts: contracts, Sudo: sudo, - ImOnline: im_online::{default, ValidateUnsigned}, + ImOnline: im_online::{Module, Call, Storage, Event, OfflineWorker, ValidateUnsigned}, } ); From 182c753211e1f2110fa4e51be5574cd6b17f0ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 17:23:26 +0200 Subject: [PATCH 20/80] Make it compile. --- Cargo.lock | 1 + .../finality-grandpa/src/communication/mod.rs | 14 +-- core/finality-grandpa/src/environment.rs | 2 +- core/finality-grandpa/src/lib.rs | 4 +- node/cli/Cargo.toml | 1 + node/cli/src/chain_spec.rs | 91 +++++++++---------- node/runtime/src/lib.rs | 2 +- 7 files changed, 57 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 872dbc25e1e19..2a2fd79d7877c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2251,6 +2251,7 @@ dependencies = [ "srml-balances 2.0.0", "srml-contracts 2.0.0", "srml-finality-tracker 2.0.0", + "srml-im-online 0.1.0", "srml-indices 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index d1943923da725..c54be8fcee39e 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -29,18 +29,18 @@ use std::sync::Arc; -use grandpa::{voter, voter_set::VoterSet}; -use grandpa::Message::{Prevote, Precommit, PrimaryPropose}; use futures::prelude::*; use futures::sync::{oneshot, mpsc}; +use grandpa::Message::{Prevote, Precommit, PrimaryPropose}; +use grandpa::{voter, voter_set::VoterSet}; use log::{debug, trace}; -use tokio_executor::Executor; -use parity_codec::{Encode, Decode}; -use substrate_primitivesa::{ed25519, Pair}; -use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO}; -use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; use network::{consensus_gossip as network_gossip, NetworkService}; use network_gossip::ConsensusMessage; +use parity_codec::{Encode, Decode}; +use primitives::Pair; +use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; +use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO}; +use tokio_executor::Executor; use crate::{ CatchUp, Commit, CommunicationIn, CommunicationOut, CompactCommit, Error, diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index 47c88aed809bb..f73bd3e5aa7f4 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -33,11 +33,11 @@ use grandpa::{ BlockNumberOps, Equivocation, Error as GrandpaError, round::State as RoundState, voter, voter_set::VoterSet, }; +use primitives::{Blake2Hasher, H256, Pair}; use sr_primitives::generic::BlockId; use sr_primitives::traits::{ Block as BlockT, Header as HeaderT, NumberFor, One, Zero, BlockNumberToHash, }; -use substrate_primitives::{Blake2Hasher, ed25519, H256, Pair}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use crate::{ diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index b35d43bb1b338..64ee4d23beb55 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -58,14 +58,14 @@ use futures::sync::mpsc; use client::{BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError}; use client::blockchain::HeaderBackend; use parity_codec::Encode; +use sr_primitives::generic::BlockId; use sr_primitives::traits::{ NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi, }; use fg_primitives::{GrandpaApi, AuthorityPair}; use inherents::InherentDataProviders; -use sr_primitives::generic::BlockId; use consensus_common::SelectChain; -use substrate_primitives::{ed25519, H256, Pair, Blake2Hasher}; +use primitives::{H256, Pair, Blake2Hasher}; use substrate_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG, CONSENSUS_WARN}; use serde_json; diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index f40ef95ada8f9..5ca4109990506 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -43,6 +43,7 @@ contracts = { package = "srml-contracts", path = "../../srml/contracts" } system = { package = "srml-system", path = "../../srml/system" } balances = { package = "srml-balances", path = "../../srml/balances" } support = { package = "srml-support", path = "../../srml/support", default-features = false } +im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } [dev-dependencies] babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe", features = ["test-helpers"] } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index c9ad36fc96812..11efb49d6ae05 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -16,7 +16,7 @@ //! Substrate chain configurations. -use primitives::{sr25519, Pair, crypto::UncheckedInto}; +use primitives::{Pair, Public, crypto::UncheckedInto}; use node_primitives::{AccountId, Balance}; use node_runtime::{ BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, @@ -29,8 +29,9 @@ pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::hex; use substrate_telemetry::TelemetryEndpoints; -use grandpa_primitives::{AuthorityId as GrandpaId, AuthorityPair as GrandpaPair}; -use babe_primitives::{AuthorityId as BabeId, AuthorityPair as BabePair}; +use grandpa_primitives::{AuthorityId as GrandpaId}; +use babe_primitives::{AuthorityId as BabeId}; +use im_online::AuthorityId as ImOnlineId; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -42,8 +43,8 @@ pub fn flaming_fir_config() -> Result { ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..]) } -fn session_keys(grandpa: GrandpaId, babe: BabeId) -> SessionKeys { - SessionKeys { grandpa, babe } +fn session_keys(grandpa: GrandpaId, babe: BabeId, im_online: ImOnlineId) -> SessionKeys { + SessionKeys { grandpa, babe, im_online, } } fn staging_testnet_config_genesis() -> GenesisConfig { @@ -55,7 +56,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // TODO: actually use sr25519 for babe keys (right now they seems to just be copies of the // ed25519 grandpa key). - let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)> = vec![( + let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId)> = vec![( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq @@ -64,6 +65,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), + // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC + hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), ),( // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].unchecked_into(), @@ -73,6 +76,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), + // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE + hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), ),( // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].unchecked_into(), @@ -82,6 +87,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), + // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d + hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), ),( // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].unchecked_into(), @@ -91,6 +98,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), + // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 + hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), )]; // generated with secret: subkey inspect "$secret"/fir @@ -121,7 +130,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -162,7 +171,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), im_online: Some(ImOnlineConfig { gossip_at: 0, - last_new_era_start: 0, + keys: initial_authorities.iter().map(|x| x.4.clone()).collect(), }), grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), @@ -185,58 +194,46 @@ pub fn staging_testnet_config() -> ChainSpec { ) } -/// Helper function to generate AccountId from seed -pub fn get_account_id_from_seed(seed: &str) -> AccountId { - sr25519::Pair::from_string(&format!("//{}", seed), None) +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } -/// Helper function to generate BabeId from seed -pub fn get_babe_id_from_seed(seed: &str) -> BabeId { - BabePair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate GrandpaId from seed -pub fn get_grandpa_id_from_seed(seed: &str) -> GrandpaId { - GrandpaPair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} /// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId) { +pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId) { ( - get_account_id_from_seed(&format!("{}//stash", seed)), - get_account_id_from_seed(seed), - get_grandpa_id_from_seed(seed), - get_babe_id_from_seed(seed), + get_from_seed::(&format!("{}//stash", seed)), + get_from_seed::(seed), + get_from_seed::(seed), + get_from_seed::(seed), + get_from_seed::(seed), ) } /// Helper function to create GenesisConfig for testing pub fn testnet_genesis( - initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>, + initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId)>, root_key: AccountId, endowed_accounts: Option>, enable_println: bool, ) -> GenesisConfig { let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { vec![ - get_account_id_from_seed("Alice"), - get_account_id_from_seed("Bob"), - get_account_id_from_seed("Charlie"), - get_account_id_from_seed("Dave"), - get_account_id_from_seed("Eve"), - get_account_id_from_seed("Ferdie"), - get_account_id_from_seed("Alice//stash"), - get_account_id_from_seed("Bob//stash"), - get_account_id_from_seed("Charlie//stash"), - get_account_id_from_seed("Dave//stash"), - get_account_id_from_seed("Eve//stash"), - get_account_id_from_seed("Ferdie//stash"), + get_from_seed::("Alice"), + get_from_seed::("Bob"), + get_from_seed::("Charlie"), + get_from_seed::("Dave"), + get_from_seed::("Eve"), + get_from_seed::("Ferdie"), + get_from_seed::("Alice//stash"), + get_from_seed::("Bob//stash"), + get_from_seed::("Charlie//stash"), + get_from_seed::("Dave//stash"), + get_from_seed::("Eve//stash"), + get_from_seed::("Ferdie//stash"), ] }); @@ -259,7 +256,7 @@ pub fn testnet_genesis( }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -305,7 +302,7 @@ pub fn testnet_genesis( }), im_online: Some(ImOnlineConfig{ gossip_at: 0, - last_new_era_start: 0, + keys: initial_authorities.iter().map(|x| x.4.clone()).collect(), }), grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), @@ -318,7 +315,7 @@ fn development_config_genesis() -> GenesisConfig { vec![ get_authority_keys_from_seed("Alice"), ], - get_account_id_from_seed("Alice"), + get_from_seed::("Alice"), None, true, ) @@ -335,7 +332,7 @@ fn local_testnet_genesis() -> GenesisConfig { get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), ], - get_account_id_from_seed("Alice"), + get_from_seed::("Alice"), None, false, ) @@ -357,7 +354,7 @@ pub(crate) mod tests { vec![ get_authority_keys_from_seed("Alice"), ], - get_account_id_from_seed("Alice"), + get_from_seed("Alice"), None, false, ) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 914814dcb9e81..44e78dc337aff 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -417,7 +417,7 @@ construct_runtime!( Treasury: treasury::{Module, Call, Storage, Event}, Contracts: contracts, Sudo: sudo, - ImOnline: im_online::{Module, Call, Storage, Event, OfflineWorker, ValidateUnsigned}, + ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, } ); From f1ecdee76d0d23df1fc2445a200911e469087b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 30 Jul 2019 17:35:21 +0200 Subject: [PATCH 21/80] Fixing tests. --- core/consensus/aura/primitives/src/lib.rs | 2 +- core/primitives/src/crypto.rs | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 1bc6a1e4f6a3b..bc1bf3939a1af 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -41,7 +41,7 @@ pub mod sr25519 { } mod app_ed25519 { - use substrate_primitives::{app_crypto, crypto::key_types::AURA, ed25519}; + use primitives::{app_crypto, crypto::key_types::AURA, ed25519}; app_crypto!(ed25519, AURA); } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 029c7aa2fd4da..0168d57fd34af 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -1166,14 +1166,33 @@ mod tests { Standard{phrase: String, password: Option, path: Vec}, Seed(Vec), } + impl Default for TestPair { + fn default() -> Self { + TestPair::Generated + } + } + impl CryptoType for TestPair { + const KIND: Kind = Kind::Dummy; + type Pair = Self; + } - #[derive(Clone, PartialEq, Eq, Hash)] + #[derive(Clone, PartialEq, Eq, Hash, Default)] struct TestPublic; impl AsRef<[u8]> for TestPublic { fn as_ref(&self) -> &[u8] { &[] } } + impl AsMut<[u8]> for TestPublic { + fn as_mut(&mut self) -> &mut [u8] { + &mut [] + } + } + impl CryptoType for TestPublic { + const KIND: Kind = Kind::Dummy; + type Pair = TestPair; + } + impl Derive for TestPublic {} impl Public for TestPublic { fn from_slice(_bytes: &[u8]) -> Self { Self From 82cbe9e3aca7f1af2923bf04acb0e12d529eb31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 30 Jul 2019 21:40:25 +0200 Subject: [PATCH 22/80] Rewrite `keystore` --- core/cli/src/lib.rs | 20 ++- core/cli/src/params.rs | 37 ++++-- core/keystore/src/lib.rs | 226 +++++++++++++++++++++----------- core/offchain/src/api.rs | 9 +- core/primitives/src/crypto.rs | 12 +- core/primitives/src/offchain.rs | 23 ---- core/service/src/config.rs | 11 +- core/service/src/lib.rs | 35 +---- 8 files changed, 214 insertions(+), 159 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 7cd7db88979cf..4ab079f7c875f 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -366,6 +366,22 @@ fn input_keystore_password() -> Result { .map_err(|e| format!("{:?}", e)) } +/// Fill the password field of the given config instance. +fn fill_config_keystore_password( + config: &mut service::Configuration, + cli: &RunCmd, +) -> Result<(), String> { + config.keystore_password = if cli.password_interactive { + Some(input_keystore_password()?.into()); + } else if let Some(file) = cli.password_filename { + Some(fs::read_to_string(file)?.into()); + } else if let Some(password) = cli.password { + Some(password.into()); + }; + + Ok(()) +} + fn create_run_node_config( cli: RunCmd, spec_factory: S, impl_name: &'static str, version: &VersionInfo ) -> error::Result> @@ -375,9 +391,6 @@ where { let spec = load_spec(&cli.shared_params, spec_factory)?; let mut config = service::Configuration::default_with_spec(spec.clone()); - if cli.interactive_password { - config.password = input_keystore_password()?.into() - } config.impl_name = impl_name; config.impl_commit = version.commit; @@ -402,6 +415,7 @@ where let base_path = base_path(&cli.shared_params, version); config.keystore_path = cli.keystore_path.or_else(|| Some(keystore_path(&base_path, config.chain_spec.id()))); + fill_config_keystore_password(&mut config, &cli)?; config.database_path = db_path(&base_path, config.chain_spec.id()); config.database_cache_size = cli.database_cache_size; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index e1018eb93a4e8..c94d71fe51900 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -306,14 +306,6 @@ pub struct ExecutionStrategies { /// The `run` command used to run a node. #[derive(Debug, StructOpt, Clone)] pub struct RunCmd { - /// Specify custom keystore path - #[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))] - pub keystore_path: Option, - - /// Specify additional key seed - #[structopt(long = "key", value_name = "STRING")] - pub key: Option, - /// Enable validator mode #[structopt(long = "validator")] pub validator: bool, @@ -422,9 +414,32 @@ pub struct RunCmd { #[structopt(long = "force-authoring")] pub force_authoring: bool, - /// Interactive password for validator key. - #[structopt(short = "i")] - pub interactive_password: bool, + /// Specify custom keystore path. + #[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))] + pub keystore_path: Option, + + /// Use interactive shell for entering the password used by the keystore. + #[structopt( + long = "password-interactive", + raw(conflicts_with_all = r#"&[ "password", "password-filename" ]"#) + )] + pub password_interactive: bool, + + /// Password used by the keystore. + #[structopt( + long = "password" + raw(conflicts_with_all = r#"&[ "password-interactive", "password-filename" ]"#) + )] + pub password: Option, + + /// File that contains the password used by the keystore. + #[structopt( + long = "password-filename", + value_name = "PATH", + parse(from_os_str), + raw(conflicts_with_all = r#"&[ "password-interactive", "password" ]"#) + )] + pub password_filename: Option } /// Stores all required Cli values for a keyring test account. diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index b7ef99a65ea4d..127de654e7904 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -18,13 +18,10 @@ #![warn(missing_docs)] -use std::collections::HashMap; -use std::path::PathBuf; -use std::fs::{self, File}; -use std::io::{self, Write}; +use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}}; use primitives::crypto::{ - KeyTypeId, AppPublic, AppKey, AppPair, Pair, Public, IsWrappedBy + KeyTypeId, AppPublic, AppKey, AppPair, Pair as PairT, Public, IsWrappedBy, Protected, }; /// Keystore error. @@ -59,104 +56,122 @@ impl std::error::Error for Error { } /// Key store. +/// +/// Stores key pairs in a file system store + short lived key pairs in memory. +/// +/// Every pair that is being generated by a `seed`, will be placed in memory. pub struct Store { path: PathBuf, additional: HashMap<(KeyTypeId, Vec), Vec>, + password: Option>, } impl Store { - /// Create a new store at the given path. - pub fn open(path: PathBuf) -> Result { + /// Open the store at the given path. + /// + /// Optionally takes a password that will be used to encrypt/decrypt the keys. + pub fn open>(path: T, password: Option>) -> Result { + let path = path.into(); fs::create_dir_all(&path)?; - Ok(Store { path, additional: HashMap::new() }) + Ok(Self { path, additional: HashMap::new(), password }) } - fn get_pair(&self, public: &TPair::Public, key_type: KeyTypeId) -> Result> { + /// Get the public/private key pair for the given public key and key type. + fn get_pair( + &self, + public: &Pair::Public, + key_type: KeyTypeId, + ) -> Result> { let key = (key_type, public.to_raw_vec()); - if let Some(bytes) = self.additional.get(&key) { - let pair = TPair::from_seed_slice(bytes) - .map_err(|_| Error::InvalidSeed)?; - return Ok(Some(pair)); - } - Ok(None) + self.additional + .get(&key) + .map(|bytes| Pair::from_seed_slice(bytes).map_err(|_| Error::InvalidSeed)) + .transpose() } - fn insert_pair(&mut self, pair: &TPair, key_type: KeyTypeId) { + /// Insert the given public/private key pair with the given key type. + fn insert_pair(&mut self, pair: &Pair, key_type: KeyTypeId) { let key = (key_type, pair.public().to_raw_vec()); self.additional.insert(key, pair.to_raw_vec()); } - /// Generate a new key, placing it into the store. - pub fn generate_by_type(&self, password: &str, key_type: KeyTypeId) -> Result { - let (pair, phrase, _) = TPair::generate_with_phrase(Some(password)); - let mut file = File::create(self.key_file_path::(&pair.public(), key_type))?; - ::serde_json::to_writer(&file, &phrase)?; + /// Generate a new key. + /// + /// Places it into the file system store. + pub fn generate_by_type(&self, key_type: KeyTypeId) -> Result { + let (pair, phrase, _) = Pair::generate_with_phrase(self.password.as_ref().map(|p| &***p)); + let mut file = File::create(self.key_file_path::(&pair.public(), key_type))?; + serde_json::to_writer(&file, &phrase)?; file.flush()?; Ok(pair) } - /// Create a new key from seed. Do not place it into the store. - pub fn generate_from_seed_by_type(&mut self, seed: &str, key_type: KeyTypeId) -> Result { - let pair = TPair::from_string(seed, None) - .ok().ok_or(Error::InvalidSeed)?; - self.insert_pair(&pair, key_type); - Ok(pair) + /// Generate a new key. + /// + /// Places it into the file system store. + pub fn generate(&self) -> Result { + self.generate_by_type::(Pair::ID).map(Into::into) } - /// Generate a new key, placing it into the store. - pub fn generate< - Pair: AppPair - >(&self, password: &str) -> Result { - self.generate_by_type::(password, Pair::ID) - .map(Into::into) + /// Create a new key from seed. + /// + /// Does not place it into the file system store. + pub fn generate_from_seed_by_type( + &mut self, + seed: &str, + key_type: KeyTypeId, + ) -> Result { + let pair = Pair::from_string(seed, None).map_err(|_| Error::InvalidSeed)?; + self.insert_pair(&pair, key_type); + Ok(pair) } - /// Create a new key from seed. Do not place it into the store. - pub fn generate_from_seed< - Pair: AppPair, - >(&mut self, seed: &str) -> Result { - self.generate_from_seed_by_type::(seed, Pair::ID) - .map(Into::into) + /// Create a new key from seed. + /// + /// Does not place it into the file system store. + pub fn generate_from_seed(&mut self, seed: &str) -> Result { + self.generate_from_seed_by_type::(seed, Pair::ID).map(Into::into) } - /// Load a key file with given public key. - pub fn load_by_type(&self, - public: &TPair::Public, - password: &str, - key_type: KeyTypeId - ) -> Result { + /// Get a key pair for the given public key and key type. + pub fn key_pair_by_type(&self, + public: &Pair::Public, + key_type: KeyTypeId, + ) -> Result { if let Some(pair) = self.get_pair(public, key_type)? { return Ok(pair) } - let path = self.key_file_path::(public, key_type); + let path = self.key_file_path::(public, key_type); let file = File::open(path)?; - let phrase: String = ::serde_json::from_reader(&file)?; - let (pair, _) = TPair::from_phrase(&phrase, Some(password)) - .ok().ok_or(Error::InvalidPhrase)?; - if &pair.public() != public { - return Err(Error::InvalidPassword); + let phrase: String = serde_json::from_reader(&file)?; + let pair = Pair::from_phrase( + &phrase, + self.password.as_ref().map(|p| &***p), + ).map_err(|_| Error::InvalidPhrase)?.0; + + if &pair.public() == public { + Ok(pair) + } else { + Err(Error::InvalidPassword) } - Ok(pair) } - /// Load a key file with given public key. - pub fn load< - Pair_: AppPair - >(&self, public: &::Public, password: &str) -> Result { - self.load_by_type::(IsWrappedBy::from_ref(public), password, Pair_::ID) - .map(Into::into) + /// Get a key pair for the given public key. + pub fn key_pair(&self, public: &::Public) -> Result { + self.key_pair_by_type::(IsWrappedBy::from_ref(public), Pair::ID).map(Into::into) } - /// Get public keys of all stored keys. - pub fn contents_by_type(&self, key_type: KeyTypeId) -> Result> { + /// Get public keys of all stored keys that match the given key type. + pub fn public_keys_by_type(&self, key_type: KeyTypeId) -> Result> { let mut public_keys: Vec = self.additional.keys() .filter_map(|(ty, public)| { - if *ty != key_type { - return None + if *ty == key_type { + Some(TPublic::from_slice(public)) + } else { + None } - Some(TPublic::from_slice(public)) }) .collect(); @@ -180,20 +195,19 @@ impl Store { Ok(public_keys) } - /// Get public keys of all stored keys. + /// Get public keys of all stored keys that match the key type. /// /// This will just use the type of the public key (a list of which to be returned) in order /// to determine the key type. Unless you use a specialised application-type public key, then /// this only give you keys registered under generic cryptography, and will not return keys /// registered under the application type. - pub fn contents< - Public: AppPublic - >(&self) -> Result> { - self.contents_by_type::(Public::ID) + pub fn public_keys(&self) -> Result> { + self.public_keys_by_type::(Public::ID) .map(|v| v.into_iter().map(Into::into).collect()) } - fn key_file_path(&self, public: &TPair::Public, key_type: KeyTypeId) -> PathBuf { + /// Returns the file path for the given public key and key type. + fn key_file_path(&self, public: &Pair::Public, key_type: KeyTypeId) -> PathBuf { let mut buf = self.path.clone(); let key_type = hex::encode(key_type.0); let key = hex::encode(public.as_slice()); @@ -206,34 +220,86 @@ impl Store { mod tests { use super::*; use tempdir::TempDir; - use primitives::ed25519; + use primitives::{ed25519, sr25519}; use primitives::crypto::Ss58Codec; #[test] fn basic_store() { let temp_dir = TempDir::new("keystore").unwrap(); - let store = Store::open(temp_dir.path().to_owned()).unwrap(); - - assert!(store.contents::().unwrap().is_empty()); + let store = Store::open(temp_dir.path(), None).unwrap(); - let key: ed25519::Pair = store.generate("thepassword").unwrap(); - let key2: ed25519::Pair = store.load(&key.public(), "thepassword").unwrap(); + assert!(store.public_keys::().unwrap().is_empty()); - assert!(store.load::(&key.public(), "notthepassword").is_err()); + let key: ed25519::AppPair = store.generate().unwrap(); + let key2: ed25519::AppPair = store.key_pair(&key.public()).unwrap(); assert_eq!(key.public(), key2.public()); - assert_eq!(store.contents::().unwrap()[0], key.public()); + assert_eq!(store.public_keys::().unwrap()[0], key.public()); } #[test] fn test_generate_from_seed() { let temp_dir = TempDir::new("keystore").unwrap(); - let mut store = Store::open(temp_dir.path().to_owned()).unwrap(); + let mut store = Store::open(temp_dir.path(), None).unwrap(); - let pair: ed25519::Pair = store + let pair: ed25519::AppPair = store .generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc") .unwrap(); - assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", pair.public().to_ss58check()); + assert_eq!( + "5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", + pair.public().to_ss58check() + ); + + drop(store); + let store = Store::open(temp_dir.path(), None).unwrap(); + // Keys generated from seed should not be persisted! + assert!(store.key_pair::(&pair.public()).is_err()); + } + + #[test] + fn password_being_used() { + let password = String::from("password"); + let temp_dir = TempDir::new("keystore").unwrap(); + let store = Store::open(temp_dir.path(), Some(password.clone().into())).unwrap(); + + let pair: ed25519::AppPair = store.generate().unwrap(); + assert_eq!( + pair.public(), + store.key_pair::(&pair.public()).unwrap().public(), + ); + + // Without the password the key should not be retrievable + let store = Store::open(temp_dir.path(), None).unwrap(); + assert!(store.key_pair::(&pair.public()).is_err()); + + let store = Store::open(temp_dir.path(), Some(password.into())).unwrap(); + assert_eq!( + pair.public(), + store.key_pair::(&pair.public()).unwrap().public(), + ); + } + + #[test] + fn public_keys_are_returned() { + let temp_dir = TempDir::new("keystore").unwrap(); + let mut store = Store::open(temp_dir.path(), None).unwrap(); + + let mut public_keys = Vec::new(); + for i in 0..10 { + public_keys.push(store.generate::().unwrap().public()); + public_keys.push(store.generate_from_seed::( + &format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i), + ).unwrap().public()); + } + + // Generate a key of a different type + store.generate::().unwrap(); + + public_keys.sort(); + let mut store_pubs = store.public_keys::().unwrap(); + store_pubs.sort(); + + assert_eq!(public_keys, store_pubs); } } diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 2dafed5e2bc2a..7121cec3bea9f 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -145,7 +145,7 @@ impl Api where let keystore = (&*self.keystore).as_ref().ok_or(())?; match kind { CryptoKind::Sr25519 => { - Ok(keystore.contents_by_type::(key_type) + Ok(keystore.public_keys_by_type::(key_type) .map_err(log_error)? .into_iter() .map(|key| CryptoKey { @@ -155,7 +155,7 @@ impl Api where }).collect()) }, CryptoKind::Ed25519 => { - Ok(keystore.contents_by_type::(key_type) + Ok(keystore.public_keys_by_type::(key_type) .map_err(log_error)? .into_iter() .map(|key| CryptoKey { @@ -183,18 +183,17 @@ impl Api where // TODO [ToDr] Remove let keystore = (&*self.keystore).as_ref().ok_or(())?; - let pass = "".into(); match key.kind { CryptoKind::Sr25519 => { let public = sr25519::Public::from_slice(&key.public); - keystore.load_by_type(&public, pass, key.key_type) + keystore.key_pair_by_type(&public, key.key_type) .map_err(log_error) .map(KnownCryptoKey::Sr25519) }, CryptoKind::Ed25519 => { let public = ed25519::Public::from_slice(&key.public); - keystore.load_by_type(&public, pass, key.key_type) + keystore.key_pair_by_type(&public, key.key_type) .map_err(log_error) .map(KnownCryptoKey::Ed25519) }, diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 0168d57fd34af..2c022ebfa92fc 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -82,6 +82,14 @@ impl AsRef for Protected { } } +impl rstd::ops::Deref for Protected { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + #[cfg(feature = "std")] impl std::fmt::Debug for Protected { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -706,7 +714,7 @@ impl TryFrom for Kind { e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, e if e == Kind::Dummy as usize as u32 => Kind::Dummy, - _ => Err(())?, + _ => return Err(()), }) } } @@ -980,7 +988,7 @@ macro_rules! app_crypto { } } #[cfg(feature = "std")] - impl ::std::fmt::Display for Public { + impl std::fmt::Display for Public { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { use $crate::crypto::Ss58Codec; write!(f, "{}", self.0.to_ss58check()) diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index a3aa06b7ded78..b4a8463003536 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -502,27 +502,4 @@ mod tests { assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0)); assert_eq!(t.diff(&Timestamp(3)), Duration(2)); } - - #[test] - fn crypto_key_to_from_u64() { - let key = CryptoKey::AuthorityKey; - let uint: u64 = key.clone().into(); - let key2 = CryptoKey::try_from(uint).unwrap(); - assert_eq!(key, key2); - - let key = CryptoKey::FgAuthorityKey; - let uint: u64 = key.clone().into(); - let key2 = CryptoKey::try_from(uint).unwrap(); - assert_eq!(key, key2); - - let key = CryptoKey::LocalKey { id: 0, kind: CryptoKind::Ed25519 }; - let uint: u64 = key.clone().into(); - let key2 = CryptoKey::try_from(uint).unwrap(); - assert_eq!(key, key2); - - let key = CryptoKey::LocalKey { id: 10, kind: CryptoKind::Sr25519 }; - let uint: u64 = key.clone().into(); - let key2 = CryptoKey::try_from(uint).unwrap(); - assert_eq!(key, key2); - } } diff --git a/core/service/src/config.rs b/core/service/src/config.rs index cd2364b37d17e..5e45d86fb2a22 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -91,7 +91,13 @@ pub struct Configuration { /// running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages. pub grandpa_voter: bool, /// Node keystore's password - pub password: Protected, + pub keystore_password: Option>, + /// Development key seed. + /// + /// When running in development mode, the seed will be used to generate authority keys by the keystore. + /// + /// Should only be set when `node` is running development mode. + pub dev_key_seed: Option, } impl Configuration { @@ -126,7 +132,8 @@ impl Configuration { NetworkStatus>, NetworkState )>>>>, transaction_pool: Arc>, - keystore: Arc>, - exit: ::exit_future::Exit, + exit: exit_future::Exit, signal: Option, /// Sender for futures that must be spawned as background tasks. to_spawn_tx: mpsc::UnboundedSender + Send>>, @@ -170,7 +169,7 @@ impl Service { let executor = NativeExecutor::new(config.default_heap_pages); let keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { - match Keystore::open(keystore_path.clone()) { + match Keystore::open(keystore_path.clone(), config.keystore_password.clone()) { Ok(ks) => Some(ks), Err(err) => { error!("Failed to initialize keystore: {}", err); @@ -181,34 +180,6 @@ impl Service { None }; - // Keep the public key for telemetry - let public_key: String; - - /* - // This is meant to be for testing only - // FIXME #1063 remove this - if let Some(keystore) = keystore.as_mut() { - for seed in &config.keys { - // this won't work as desired since it's only generating "plain" - // keys here, not app-specific keys as the engines will need. - keystore.generate_from_seed::(seed)?; - keystore.generate_from_seed::(seed)?; - } - - public_key = match keystore.contents::()?.get(0) { - Some(public_key) => public_key.to_string(), - None => { - let key: ed25519::Pair = keystore.generate(&config.password.as_ref())?; - let public_key = key.public(); - info!("Generated a new keypair: {:?}", public_key); - public_key.to_string() - } - } - } else { - public_key = format!(""); - } - */ - public_key = format!(""); let keystore = Arc::new(keystore); let (client, on_demand) = Components::build_client(&config, executor)?; @@ -460,7 +431,6 @@ impl Service { "version" => version.clone(), "config" => "", "chain" => chain_name.clone(), - "pubkey" => &public_key, "authority" => is_authority, "network_id" => network_id.clone() ); @@ -486,7 +456,6 @@ impl Service { to_spawn_tx, to_spawn_rx, to_poll: Vec::new(), - keystore, config, exit, rpc_handlers, From b270f2475e1ebcc31e670d902d92b7240b90d94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 30 Jul 2019 22:50:58 +0200 Subject: [PATCH 23/80] Fix session tests --- core/sr-primitives/src/testing.rs | 3 +-- srml/session/src/historical.rs | 23 +++++------------------ srml/session/src/lib.rs | 8 ++++---- srml/session/src/mock.rs | 7 ++++--- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index e9119d2b90fae..8193808ffe0c9 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -141,8 +141,7 @@ impl traits::Extrinsic for ExtrinsicWrapper { } } -impl serde::Serialize for ExtrinsicWrapper -{ +impl serde::Serialize for ExtrinsicWrapper { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { self.using_encoded(|bytes| seq.serialize_bytes(bytes)) } diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index 0b838a857fa79..fef9ad2b1d531 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -312,11 +312,8 @@ impl> srml_support::traits::KeyOwnerProofSystem<(KeyTyp mod tests { use super::*; use runtime_io::with_externalities; - use primitives::Blake2Hasher; - use sr_primitives::{ - traits::OnInitialize, - testing::{UintAuthorityId, UINT_DUMMY_KEY}, - }; + use primitives::{Blake2Hasher, crypto::key_types::DUMMY}; + use sr_primitives::{traits::OnInitialize, testing::UintAuthorityId}; use crate::mock::{ NEXT_VALIDATORS, force_new_session, set_next_validators, Test, System, Session, @@ -346,15 +343,10 @@ mod tests { Session::on_initialize(1); let encoded_key_1 = UintAuthorityId(1).encode(); - let proof = Historical::prove((UINT_DUMMY_KEY, &encoded_key_1[..])).unwrap(); + let proof = Historical::prove((DUMMY, &encoded_key_1[..])).unwrap(); // proof-checking in the same session is OK. - assert!( - Historical::check_proof( - (UINT_DUMMY_KEY, &encoded_key_1[..]), - proof.clone(), - ).is_some() - ); + assert!(Historical::check_proof((DUMMY, &encoded_key_1[..]), proof.clone()).is_some()); set_next_validators(vec![1, 2, 4]); force_new_session(); @@ -370,12 +362,7 @@ mod tests { assert!(Session::current_index() > proof.session); // proof-checking in the next session is also OK. - assert!( - Historical::check_proof( - (UINT_DUMMY_KEY, &encoded_key_1[..]), - proof.clone(), - ).is_some() - ); + assert!(Historical::check_proof((DUMMY, &encoded_key_1[..]), proof.clone()).is_some()); set_next_validators(vec![1, 2, 5]); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index f33e082d03bf5..63cd2617f14f5 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -565,7 +565,7 @@ mod tests { use super::*; use srml_support::assert_ok; use runtime_io::with_externalities; - use primitives::Blake2Hasher; + use primitives::{Blake2Hasher, crypto::key_types::DUMMY}; use sr_primitives::{ traits::OnInitialize, testing::UintAuthorityId, @@ -614,12 +614,12 @@ mod tests { assert_eq!(Session::validators(), vec![1, 2, 3]); assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1))); - let id = ::ID; - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(&id.0)), Some(1)); + let id = DUMMY; + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); Session::on_free_balance_zero(&1); assert_eq!(Session::load_keys(&1), None); - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(&id.0)), None); + assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None); assert!(Changed::get()); }) diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 0194ee131e3be..5e284902196be 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -19,14 +19,13 @@ use super::*; use std::cell::RefCell; use srml_support::{impl_outer_origin, parameter_types}; -use primitives::H256; +use primitives::{crypto::key_types::DUMMY, H256}; use sr_primitives::{ Perbill, traits::{BlakeTwo256, IdentityLookup, ConvertInto}, testing::{Header, UintAuthorityId} }; - impl_outer_origin! { pub enum Origin for Test {} } @@ -58,7 +57,9 @@ impl SessionHandler for TestSessionHandler { ) { SESSION_CHANGED.with(|l| *l.borrow_mut() = changed); AUTHORITIES.with(|l| - *l.borrow_mut() = validators.iter().map(|(_, id)| id.get::(0).unwrap_or_default()).collect() + *l.borrow_mut() = validators.iter() + .map(|(_, id)| id.get::(DUMMY).unwrap_or_default()) + .collect() ); } fn on_disabled(_validator_index: usize) {} From 1bd145a3e7a8b692be4679011bdf8d6ca0625fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 30 Jul 2019 22:55:55 +0200 Subject: [PATCH 24/80] Bring back `TryFrom`'s' --- core/primitives/src/crypto.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 2c022ebfa92fc..6a95e91fe2c28 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -1130,7 +1130,7 @@ pub mod key_types { pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } -/*impl TryFrom for Kind { +impl TryFrom for Kind { type Error = (); fn try_from(kind: KeyTypeId) -> Result { @@ -1156,9 +1156,10 @@ impl TryFrom for KeyTypeId { Kind::Ed25519 => key_types::ED25519, #[cfg(feature = "std")] Kind::Dummy => key_types::DUMMY, + Kind::User => return Err(()), }) } -}*/ +} #[cfg(test)] mod tests { From 0a93060eb3a49344633f51c6747f62edfad404d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 10:00:45 +0200 Subject: [PATCH 25/80] Fix `srml-grandpa` --- Cargo.lock | 1 + core/primitives/src/crypto.rs | 6 +++--- core/sr-primitives/src/testing.rs | 11 ++++++----- srml/aura/src/lib.rs | 5 ++--- srml/grandpa/src/mock.rs | 4 +++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7a8149b2d035..2a2fd79d7877c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2253,6 +2253,7 @@ dependencies = [ "srml-finality-tracker 2.0.0", "srml-im-online 0.1.0", "srml-indices 2.0.0", + "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 6a95e91fe2c28..22c1c2f360b9d 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -1130,7 +1130,7 @@ pub mod key_types { pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } -impl TryFrom for Kind { +impl rstd::convert::TryFrom for Kind { type Error = (); fn try_from(kind: KeyTypeId) -> Result { @@ -1141,13 +1141,13 @@ impl TryFrom for Kind { e if e == key_types::GRANDPA => Kind::Ed25519, #[cfg(feature = "std")] e if e == key_types::DUMMY => Kind::Dummy, - _ => Err(())?, + _ => return Err(()), }) } } // This doesn't make much sense and should be reconsidered. -impl TryFrom for KeyTypeId { +impl rstd::convert::TryFrom for KeyTypeId { type Error = (); fn try_from(kind: Kind) -> Result { diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 8193808ffe0c9..c529ce35d17fe 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -26,17 +26,18 @@ use crate::traits::{ use crate::{generic, KeyTypeId}; use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use primitives::H256; -use primitives::{crypto::{Kind, CryptoType, Dummy, key_types}, U256}; -use primitives::ed25519::{Public as AuthorityId}; +use primitives::{crypto::{Kind, CryptoType, Dummy, key_types, Public}, U256}; use crate::transaction_validity::TransactionValidity; /// Authority Id #[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize)] pub struct UintAuthorityId(pub u64); -impl Into for UintAuthorityId { - fn into(self) -> AuthorityId { + +impl UintAuthorityId { + /// Convert this authority id into a public key. + pub fn to_public_key(&self) -> T { let bytes: [u8; 32] = U256::from(self.0).into(); - AuthorityId(bytes) + T::from_slice(&bytes) } } diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index ed10f69f20ec4..f2f5586cae29a 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -53,10 +53,9 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; -use substrate_primitives::crypto::AppPublic; +use primitives::crypto::AppPublic; use sr_primitives::{ - traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember}, - generic::DigestItem, + traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember}, generic::DigestItem, }; use timestamp::OnTimestampSet; #[cfg(feature = "std")] diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index e6df8697bf79a..3c7915f0822a4 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -76,7 +76,9 @@ impl_outer_event!{ } pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { - vec.into_iter().map(|(id, weight)| (UintAuthorityId(id).into(), weight)).collect() + vec.into_iter() + .map(|(id, weight)| (UintAuthorityId(id).to_public_key::(), weight)) + .collect() } pub fn new_test_ext(authorities: Vec<(u64, u64)>) -> runtime_io::TestExternalities { From c5439890287d105b138bd9f9cfa587fcebd3e2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 10:21:34 +0200 Subject: [PATCH 26/80] Fix `srml-aura` --- srml/aura/src/mock.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 2002366cbbedd..7c5d862a50c8a 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -18,6 +18,8 @@ #![cfg(test)] +use crate::{Trait, Module, GenesisConfig}; +use substrate_consensus_aura_primitives::ed25519::AuthorityId; use sr_primitives::{ traits::IdentityLookup, Perbill, testing::{Header, UintAuthorityId}, @@ -25,7 +27,6 @@ use sr_primitives::{ use srml_support::{impl_outer_origin, parameter_types}; use runtime_io; use primitives::{H256, Blake2Hasher}; -use crate::{Trait, Module, GenesisConfig}; impl_outer_origin!{ pub enum Origin for Test {} @@ -69,13 +70,13 @@ impl timestamp::Trait for Test { impl Trait for Test { type HandleReport = (); - type AuthorityId = UintAuthorityId; + type AuthorityId = AuthorityId; } pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; t.extend(GenesisConfig::{ - authorities: authorities.into_iter().map(|a| UintAuthorityId(a)).collect(), + authorities: authorities.into_iter().map(|a| UintAuthorityId(a).to_public_key()).collect(), }.build_storage().unwrap().0); t.into() } From f7a2de3a686c75ef46634ee37be0798cd734b85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 11:38:31 +0200 Subject: [PATCH 27/80] Fix consensus babe --- core/consensus/babe/src/lib.rs | 4 ++-- core/consensus/babe/src/tests.rs | 23 ++++++++++++----------- core/keyring/src/sr25519.rs | 28 ++++++---------------------- core/primitives/src/crypto.rs | 17 +++++++++++++++++ core/primitives/src/sr25519.rs | 8 ++++---- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 65e53e7a24513..fd202ac6a454f 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -1223,7 +1223,7 @@ fn authority(client: &C, keystore: Arc) -> Option where + HeaderBackend<::Type>, C::Api: BabeApi<::Type> { - let owned = keystore.contents::().ok()?; + let owned = keystore.public_keys::().ok()?; let at = BlockId::Number(client.info().best_number); // The list of authority keys that is current. By default this will just use the state of // the best block, but you might want it to use some other block's state instead if it's @@ -1232,7 +1232,7 @@ fn authority(client: &C, keystore: Arc) -> Option where let authorities = authorities_at::(client, &at).ok()?; let maybe_pub = owned.into_iter() .find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.load(&public, "").ok()) + maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) } /// Type of source for block sealing. Different consensus algorithms have different sealing diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index f9a2360210acb..445bf77bcfb61 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -20,7 +20,9 @@ // https://github.com/paritytech/substrate/issues/2532 #![allow(deprecated)] use super::*; +use super::generic::DigestItem; +use babe_primitives::AuthorityPair; use client::{LongestChain, block_builder::BlockBuilder}; use consensus_common::NoNetwork as DummyOracle; use network::test::*; @@ -29,7 +31,6 @@ use sr_primitives::traits::{Block as BlockT, DigestFor}; use network::config::ProtocolConfig; use tokio::runtime::current_thread; use keyring::sr25519::Keyring; -use super::generic::DigestItem; use client::BlockchainEvents; use test_client; use log::debug; @@ -220,7 +221,7 @@ fn run_one_test() { runtime.spawn(start_babe(BabeParams { config, - local_key: Arc::new(key.clone().into()), + local_key: Arc::new(key.clone().pair().into()), block_import: client.clone(), select_chain, client, @@ -236,7 +237,7 @@ fn run_one_test() { net.lock().poll(); Ok::<_, ()>(futures01::Async::NotReady::<()>) })); - + runtime.block_on(future::join_all(import_notifications) .map(|_| Ok::<(), ()>(())).compat()).unwrap(); } @@ -286,8 +287,8 @@ fn rejects_missing_consensus_digests() { #[test] fn wrong_consensus_engine_id_rejected() { let _ = env_logger::try_init(); - let sig = sr25519::Pair::generate().0.sign(b""); - let bad_seal: Item = DigestItem::Seal([0; 4], sig.0.to_vec()); + let sig = AuthorityPair::generate().0.sign(b""); + let bad_seal: Item = DigestItem::Seal([0; 4], sig.to_vec()); assert!(bad_seal.as_babe_pre_digest().is_none()); assert!(bad_seal.as_babe_seal().is_none()) } @@ -302,8 +303,8 @@ fn malformed_pre_digest_rejected() { #[test] fn sig_is_not_pre_digest() { let _ = env_logger::try_init(); - let sig = sr25519::Pair::generate().0.sign(b""); - let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig.0.to_vec()); + let sig = AuthorityPair::generate().0.sign(b""); + let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig.to_vec()); assert!(bad_seal.as_babe_pre_digest().is_none()); assert!(bad_seal.as_babe_seal().is_some()) } @@ -311,7 +312,7 @@ fn sig_is_not_pre_digest() { #[test] fn can_author_block() { let _ = env_logger::try_init(); - let (pair, _) = sr25519::Pair::generate(); + let (pair, _) = AuthorityPair::generate(); let mut i = 0; let epoch = Epoch { start_slot: 0, @@ -338,8 +339,8 @@ fn authorities_call_works() { assert_eq!(client.info().chain.best_number, 0); assert_eq!(epoch(&client, &BlockId::Number(0)).unwrap().authorities, vec![ - (Keyring::Alice.into(), 1), - (Keyring::Bob.into(), 1), - (Keyring::Charlie.into(), 1), + (Keyring::Alice.public().into(), 1), + (Keyring::Bob.public().into(), 1), + (Keyring::Charlie.public().into(), 1), ]); } diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index aefdc05fa7119..3e201ab8ae96e 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -37,18 +37,7 @@ pub enum Keyring { impl Keyring { pub fn from_public(who: &Public) -> Option { - [ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, - Keyring::One, - Keyring::Two, - ].iter() - .map(|i| *i) - .find(|&k| &Public::from(k) == who) + Self::iter().find(|&k| &Public::from(k) == who) } pub fn from_raw_public(who: [u8; 32]) -> Option { @@ -84,6 +73,10 @@ impl Keyring { pub fn iter() -> impl Iterator { ::iter() } + + pub fn public(self) -> Public { + self.pair().public() + } } impl From for &'static str { @@ -109,16 +102,7 @@ impl From for sr_primitives::MultiSigner { lazy_static! { static ref PRIVATE_KEYS: HashMap = { - [ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, - Keyring::One, - Keyring::Two, - ].iter().map(|&i| (i, i.pair())).collect() + Keyring::iter().map(|i| (i, i.pair())).collect() }; static ref PUBLIC_KEYS: HashMap = { diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 22c1c2f360b9d..d9f038ec4a6cf 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -32,6 +32,8 @@ use base58::{FromBase58, ToBase58}; #[cfg(feature = "std")] use std::hash::Hash; use zeroize::Zeroize; +#[doc(hidden)] +pub use rstd::ops::Deref; /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk"; @@ -987,6 +989,7 @@ macro_rules! app_crypto { self.0.derive(path).map(Self) } } + #[cfg(feature = "std")] impl std::fmt::Display for Public { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { @@ -1013,12 +1016,15 @@ macro_rules! app_crypto { .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) } } + impl AsRef<[u8]> for Public { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } + impl AsMut<[u8]> for Public { fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } } + impl $crate::crypto::CryptoType for Public { const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; #[cfg(feature="std")] @@ -1027,6 +1033,7 @@ macro_rules! app_crypto { impl $crate::crypto::Public for Public { fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } } + impl $crate::crypto::AppKey for Public { type UntypedGeneric = $public; type Public = Public; @@ -1035,6 +1042,7 @@ macro_rules! app_crypto { type Signature = Signature; const ID: $crate::crypto::KeyTypeId = $key_type; } + impl $crate::crypto::AppPublic for Public { type Generic = $public; } @@ -1046,14 +1054,22 @@ macro_rules! app_crypto { pub struct Signature($sig); } + impl $crate::crypto::Deref for Signature { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { self.0.as_ref() } + } + impl AsRef<[u8]> for Signature { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } + impl $crate::crypto::CryptoType for Signature { const KIND: $crate::crypto::Kind = <$public as $crate::crypto::CryptoType>::KIND; #[cfg(feature="std")] type Pair = Pair; } + impl $crate::crypto::AppKey for Signature { type UntypedGeneric = $sig; type Public = Public; @@ -1062,6 +1078,7 @@ macro_rules! app_crypto { type Signature = Signature; const ID: $crate::crypto::KeyTypeId = $key_type; } + impl $crate::crypto::AppSignature for Signature { type Generic = $sig; } diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 7265e59c9db7b..a37e239159a06 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -58,7 +58,7 @@ pub struct Pair(Keypair); impl Clone for Pair { fn clone(&self) -> Self { Pair(schnorrkel::Keypair { - public: self.0.public.clone(), + public: self.0.public, secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..]) .expect("key is always the correct size; qed") }) @@ -140,8 +140,8 @@ impl<'de> Deserialize<'de> for Public { } #[cfg(feature = "std")] -impl ::std::hash::Hash for Public { - fn hash(&self, state: &mut H) { +impl std::hash::Hash for Public { + fn hash(&self, state: &mut H) { self.0.hash(state); } } @@ -168,7 +168,7 @@ impl Default for Signature { impl PartialEq for Signature { fn eq(&self, b: &Self) -> bool { - &self.0[..] == &b.0[..] + self.0[..] == b.0[..] } } From 5213c7f7ef696efa711efbffd9f5aa044f15ca76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 12:38:08 +0200 Subject: [PATCH 28/80] More fixes --- core/client/src/genesis.rs | 6 +++--- core/consensus/aura/src/lib.rs | 7 +++---- core/keyring/src/ed25519.rs | 17 +++++------------ node/executor/src/lib.rs | 5 +++-- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index 719661e344fe4..4131fa6177145 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -147,7 +147,7 @@ mod tests { #[test] fn construct_genesis_should_work_with_native() { let mut storage = GenesisConfig::new(false, - vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], + vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], 1000, None, @@ -177,7 +177,7 @@ mod tests { #[test] fn construct_genesis_should_work_with_wasm() { let mut storage = GenesisConfig::new(false, - vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], + vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], 1000, None, @@ -207,7 +207,7 @@ mod tests { #[test] fn construct_genesis_with_bad_transaction_should_panic() { let mut storage = GenesisConfig::new(false, - vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], + vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], 68, None, diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index 2de35a899794f..28e8d635ddcc9 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -690,11 +690,10 @@ pub trait AuthorityProvider: AppPair { + HeaderBackend<::Type>, C::Api: AuraApi<::Type, ::Public> { - let owned = keystore.contents::<::Public>().ok()?; + let owned = keystore.public_keys::<::Public>().ok()?; let authorities = Self::authorities(client).ok()?; - let maybe_pub = owned.into_iter() - .find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.load(&public, "").ok()) + let maybe_pub = owned.into_iter().find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) } } diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index a66cc73b56466..48917eef64c34 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -36,18 +36,7 @@ pub enum Keyring { impl Keyring { pub fn from_public(who: &Public) -> Option { - [ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, - Keyring::One, - Keyring::Two, - ].iter() - .map(|i| *i) - .find(|&k| &Public::from(k) == who) + Self::iter().find(|&k| &Public::from(k) == who) } pub fn from_raw_public(who: [u8; 32]) -> Option { @@ -83,6 +72,10 @@ impl Keyring { pub fn iter() -> impl Iterator { ::iter() } + + pub fn public(self) -> Public { + self.pair().public() + } } impl From for &'static str { diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index fa3a5b08bda86..aa6f64182ec5b 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -320,8 +320,9 @@ mod tests { sr25519_keyring: &Sr25519Keyring, ) -> SessionKeys { SessionKeys { - ed25519: ed25519_keyring.to_owned().into(), - sr25519: sr25519_keyring.to_owned().into(), + grandpa: ed25519_keyring.to_owned().public().into(), + babe: sr25519_keyring.to_owned().public().into(), + im_online: sr25519_keyring.to_owned().public().into(), } } From 9ce110a471cc7600d229381cfa0bd4d716633063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 13:30:57 +0200 Subject: [PATCH 29/80] Make service generate keys from dev_seed --- core/service/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 0b41bbb84b797..81545e47972b8 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -168,7 +168,7 @@ impl Service { // Create client let executor = NativeExecutor::new(config.default_heap_pages); - let keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { + let mut keystore = if let Some(keystore_path) = config.keystore_path.as_ref() { match Keystore::open(keystore_path.clone(), config.keystore_password.clone()) { Ok(ks) => Some(ks), Err(err) => { @@ -180,6 +180,12 @@ impl Service { None }; + //TODO: Make sure we generate for all types and apps + if let Some((keystore, seed)) = keystore.and_then(|k| config.dev_key_seed.map(|s| (k, s))) { + keystore.generate_from_seed_by_type(&seed, primitives::crypto::key_types::ED25519); + keystore.generate_from_seed_by_type(&seed, primitives::crypto::key_types::SR25519); + } + let keystore = Arc::new(keystore); let (client, on_demand) = Components::build_client(&config, executor)?; From 0610ef0dba6c3ff93e205fa90d17a0ac3f8a6bc2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 31 Jul 2019 14:35:52 +0200 Subject: [PATCH 30/80] Build fixes --- Cargo.lock | 2 ++ core/cli/Cargo.toml | 1 + core/cli/src/lib.rs | 26 ++++++++++++++------------ core/cli/src/params.rs | 13 +++++++++---- core/consensus/babe/src/lib.rs | 4 ++-- core/keystore/src/lib.rs | 4 ++-- core/primitives/src/crypto.rs | 3 +-- srml/aura/src/lib.rs | 2 +- 8 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7a8149b2d035..6ee15870dac2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2253,6 +2253,7 @@ dependencies = [ "srml-finality-tracker 2.0.0", "srml-im-online 0.1.0", "srml-indices 2.0.0", + "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4207,6 +4208,7 @@ dependencies = [ "names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index 53c320035f511..15475963cc1c5 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -20,6 +20,7 @@ tokio = "0.1.7" futures = "0.1.17" futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } fdlimit = "0.1" +serde = { version = "1.0", features = ["derive"] } exit-future = "0.1" serde_json = "1.0" panic-handler = { package = "substrate-panic-handler", path = "../../core/panic-handler" } diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 4ab079f7c875f..b9d6930cd272f 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -25,6 +25,9 @@ mod params; pub mod error; pub mod informant; +use sr_primitives::BuildStorage; +use serde::{Serialize, de::DeserializeOwned}; + use client::ExecutionStrategies; use service::{ ServiceFactory, FactoryFullConfiguration, RuntimeGenesis, @@ -367,16 +370,18 @@ fn input_keystore_password() -> Result { } /// Fill the password field of the given config instance. -fn fill_config_keystore_password( - config: &mut service::Configuration, +fn fill_config_keystore_password( + config: &mut service::Configuration, cli: &RunCmd, ) -> Result<(), String> { config.keystore_password = if cli.password_interactive { - Some(input_keystore_password()?.into()); - } else if let Some(file) = cli.password_filename { - Some(fs::read_to_string(file)?.into()); - } else if let Some(password) = cli.password { - Some(password.into()); + Some(input_keystore_password()?.into()) + } else if let Some(ref file) = cli.password_filename { + Some(fs::read_to_string(file).map_err(|e| format!("{}", e))?.into()) + } else if let Some(ref password) = cli.password { + Some(password.clone().into()) + } else { + None }; Ok(()) @@ -392,6 +397,8 @@ where let spec = load_spec(&cli.shared_params, spec_factory)?; let mut config = service::Configuration::default_with_spec(spec.clone()); + fill_config_keystore_password(&mut config, &cli)?; + config.impl_name = impl_name; config.impl_commit = version.commit; config.impl_version = version.version; @@ -415,7 +422,6 @@ where let base_path = base_path(&cli.shared_params, version); config.keystore_path = cli.keystore_path.or_else(|| Some(keystore_path(&base_path, config.chain_spec.id()))); - fill_config_keystore_password(&mut config, &cli)?; config.database_path = db_path(&base_path, config.chain_spec.id()); config.database_cache_size = cli.database_cache_size; @@ -476,10 +482,6 @@ where cli.pool_config, )?; - if let Some(key) = cli.key { - config.keys.push(key); - } - if cli.shared_params.dev && cli.keyring.account.is_none() { config.keys.push("//Alice".into()); } diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index c94d71fe51900..04380dfa33d98 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -36,9 +36,13 @@ arg_enum! { #[allow(missing_docs)] #[derive(Debug, Clone, Copy)] pub enum ExecutionStrategy { + // Execute with native build (if available, WebAssembly otherwise). Native, + // Only execute with the WebAssembly build. Wasm, + // Execute with both native (where available) and WebAssembly builds. Both, + // Execute with the native build if possible; if it fails, then execute with WebAssembly. NativeElseWasm, } } @@ -55,7 +59,8 @@ impl Into for ExecutionStrategy { } arg_enum! { - /// How to execute blocks + /// Whether off-chain workers are enabled. + #[allow(missing_docs)] #[derive(Debug, Clone)] pub enum OffchainWorkerEnabled { Always, @@ -421,14 +426,14 @@ pub struct RunCmd { /// Use interactive shell for entering the password used by the keystore. #[structopt( long = "password-interactive", - raw(conflicts_with_all = r#"&[ "password", "password-filename" ]"#) + raw(conflicts_with_all = "&[ \"password\", \"password-filename\" ]") )] pub password_interactive: bool, /// Password used by the keystore. #[structopt( - long = "password" - raw(conflicts_with_all = r#"&[ "password-interactive", "password-filename" ]"#) + long = "password", + raw(conflicts_with_all = "&[ \"password-interactive\", \"password-filename\" ]") )] pub password: Option, diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 65e53e7a24513..fd202ac6a454f 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -1223,7 +1223,7 @@ fn authority(client: &C, keystore: Arc) -> Option where + HeaderBackend<::Type>, C::Api: BabeApi<::Type> { - let owned = keystore.contents::().ok()?; + let owned = keystore.public_keys::().ok()?; let at = BlockId::Number(client.info().best_number); // The list of authority keys that is current. By default this will just use the state of // the best block, but you might want it to use some other block's state instead if it's @@ -1232,7 +1232,7 @@ fn authority(client: &C, keystore: Arc) -> Option where let authorities = authorities_at::(client, &at).ok()?; let maybe_pub = owned.into_iter() .find(|i| authorities.contains(i)); - maybe_pub.and_then(|public| keystore.load(&public, "").ok()) + maybe_pub.and_then(|public| keystore.key_pair(&public).ok()) } /// Type of source for block sealing. Different consensus algorithms have different sealing diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 127de654e7904..7aaafaf5771fd 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -77,7 +77,7 @@ impl Store { } /// Get the public/private key pair for the given public key and key type. - fn get_pair( + fn get_additional_pair( &self, public: &Pair::Public, key_type: KeyTypeId, @@ -138,7 +138,7 @@ impl Store { public: &Pair::Public, key_type: KeyTypeId, ) -> Result { - if let Some(pair) = self.get_pair(public, key_type)? { + if let Some(pair) = self.get_additional_pair(public, key_type)? { return Ok(pair) } diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 6a95e91fe2c28..63d08bd69cbb6 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -18,8 +18,7 @@ //! Cryptographic utilities. // end::description[] -#[cfg(feature = "std")] -use std::convert::{TryFrom, TryInto}; +use rstd::convert::{TryFrom, TryInto}; #[cfg(feature = "std")] use parking_lot::Mutex; #[cfg(feature = "std")] diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index ed10f69f20ec4..0d6e6785218d6 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -53,7 +53,7 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; -use substrate_primitives::crypto::AppPublic; +use primitives::crypto::AppPublic; use sr_primitives::{ traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember}, generic::DigestItem, From 5d696be9360b48d9b4df88bee5082694977d6934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 15:16:21 +0200 Subject: [PATCH 31/80] Remove offchain tests --- core/offchain/src/api.rs | 68 +++++++--------------------------------- core/offchain/src/lib.rs | 5 ++- 2 files changed, 13 insertions(+), 60 deletions(-) diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 7121cec3bea9f..be1b4e0ea80b7 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -30,18 +30,11 @@ use network::{PeerId, Multiaddr, NetworkStateInfo}; use parity_codec::{Encode, Decode}; use primitives::crypto::{self, Pair, Public}; use primitives::offchain::{ - CryptoKind, CryptoKey, KeyTypeId, - Externalities as OffchainExt, - HttpRequestId, HttpRequestStatus, HttpError, - OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, - StorageKind, - Timestamp, + CryptoKind, CryptoKey, KeyTypeId, Externalities as OffchainExt, HttpRequestId, Timestamp, + HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; use primitives::{ed25519, sr25519}; -use sr_primitives::{ - generic::BlockId, - traits::{self, Extrinsic}, -}; +use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; /// A message between the offchain extension and the processing thread. @@ -514,7 +507,6 @@ mod tests { use std::convert::TryFrom; use sr_primitives::traits::Zero; use client_db::offchain::LocalStorage; - use crate::tests::TestProvider; use network::PeerId; use test_client::runtime::Block; @@ -530,7 +522,7 @@ mod tests { } } - fn offchain_api() -> (Api, Block>, AsyncApi) { + fn offchain_api() -> (Api, AsyncApi) { let _ = env_logger::try_init(); let db = LocalStorage::new_test(); let client = Arc::new(test_client::new()); @@ -539,7 +531,13 @@ mod tests { ); let mock = Arc::new(MockNetworkStateInfo()); - AsyncApi::new(pool, db, "pass".to_owned().into(), TestProvider::default(), BlockId::Number(Zero::zero()), mock) + AsyncApi::new( + pool, + db, + Arc::new(None), + BlockId::Number(Zero::zero()), + mock, + ) } #[test] @@ -623,50 +621,6 @@ mod tests { assert_eq!(api.local_storage_get(kind, key), Some(b"value".to_vec())); } - #[test] - fn should_create_a_new_key_and_sign_and_verify_stuff() { - let test = |kind: CryptoKind| { - // given - let mut api = offchain_api().0; - let msg = b"Hello world!"; - - // when - let key_type = primitives::crypto::key_types::DUMMY; - let key = api.new_crypto_key(kind, key_type).unwrap(); - let signature = api.sign(key, msg).unwrap(); - - // then - let res = api.verify(key, msg, &signature).unwrap(); - assert_eq!(res, true); - let res = api.verify(key, msg, &[]).unwrap(); - assert_eq!(res, false); - let res = api.verify(key, b"Different msg", &signature).unwrap(); - assert_eq!(res, false); - }; - - test(CryptoKind::Ed25519); - test(CryptoKind::Sr25519); - } - - #[test] - fn should_sign_and_verify_with_authority_key() { - // given - let mut api = offchain_api().0; - api.key_provider.ed_key = Some(ed25519::Pair::generate().0); - let msg = b"Hello world!"; - - // when - let signature = api.sign(CryptoKey::AuthorityKey, msg).unwrap(); - - // then - let res = api.verify(CryptoKey::AuthorityKey, msg, &signature).unwrap(); - assert_eq!(res, true); - let res = api.verify(CryptoKey::AuthorityKey, msg, &[]).unwrap(); - assert_eq!(res, false); - let res = api.verify(CryptoKey::AuthorityKey, b"Different msg", &signature).unwrap(); - assert_eq!(res, false); - } - #[test] fn should_convert_network_states() { // given diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index 6f95906b65b12..d9818dc767e42 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -172,7 +172,6 @@ fn spawn_worker(f: impl FnOnce() -> () + Send + 'static) { mod tests { use super::*; use futures::Future; - use primitives::{ed25519, sr25519}; use network::{Multiaddr, PeerId}; struct MockNetworkStateInfo(); @@ -197,10 +196,10 @@ mod tests { let db = client_db::offchain::LocalStorage::new_test(); let network_state = Arc::new(MockNetworkStateInfo()); // TODO Test keystore - let keystore = unimplemented!(); + let keystore = Arc::new(None); // when - let offchain = OffchainWorkers::new(client, db, keystore, "".to_owned().into()); + let offchain = OffchainWorkers::new(client, db, keystore); runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone())); // then From dfcd08a752a9da924489fd44530c309c56309b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 16:04:36 +0200 Subject: [PATCH 32/80] More fixes and cleanups --- Cargo.lock | 1 - core/cli/Cargo.toml | 1 - core/cli/src/lib.rs | 15 ++++++--------- core/cli/src/params.rs | 2 +- core/service/src/chain_spec.rs | 6 +++--- core/service/src/config.rs | 5 +---- core/service/src/lib.rs | 10 ++++++---- core/service/test/src/lib.rs | 4 ++-- 8 files changed, 19 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ee15870dac2f..2a2fd79d7877c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4208,7 +4208,6 @@ dependencies = [ "names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index 15475963cc1c5..53c320035f511 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -20,7 +20,6 @@ tokio = "0.1.7" futures = "0.1.17" futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] } fdlimit = "0.1" -serde = { version = "1.0", features = ["derive"] } exit-future = "0.1" serde_json = "1.0" panic-handler = { package = "substrate-panic-handler", path = "../../core/panic-handler" } diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index b9d6930cd272f..f017726f93ff2 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -25,9 +25,6 @@ mod params; pub mod error; pub mod informant; -use sr_primitives::BuildStorage; -use serde::{Serialize, de::DeserializeOwned}; - use client::ExecutionStrategies; use service::{ ServiceFactory, FactoryFullConfiguration, RuntimeGenesis, @@ -370,7 +367,7 @@ fn input_keystore_password() -> Result { } /// Fill the password field of the given config instance. -fn fill_config_keystore_password( +fn fill_config_keystore_password( config: &mut service::Configuration, cli: &RunCmd, ) -> Result<(), String> { @@ -482,14 +479,14 @@ where cli.pool_config, )?; - if cli.shared_params.dev && cli.keyring.account.is_none() { - config.keys.push("//Alice".into()); - } - if let Some(account) = cli.keyring.account { - config.keys.push(format!("//{}", account)); + if cli.shared_params.dev { + config.dev_key_seed = cli.keyring.account + .map(|a| format!("//{}", a)) + .or_else(|| Some("//Alice".into())); } + let rpc_interface: &str = if cli.rpc_external { "0.0.0.0" } else { "127.0.0.1" }; let ws_interface: &str = if cli.ws_external { "0.0.0.0" } else { "127.0.0.1" }; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 04380dfa33d98..b779f278c327f 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -442,7 +442,7 @@ pub struct RunCmd { long = "password-filename", value_name = "PATH", parse(from_os_str), - raw(conflicts_with_all = r#"&[ "password-interactive", "password" ]"#) + raw(conflicts_with_all = "&[ \"password-interactive\", \"password\" ]") )] pub password_filename: Option } diff --git a/core/service/src/chain_spec.rs b/core/service/src/chain_spec.rs index ca92a4814cd51..ecd77af0829dd 100644 --- a/core/service/src/chain_spec.rs +++ b/core/service/src/chain_spec.rs @@ -34,7 +34,7 @@ enum GenesisSource { Factory(fn() -> G), } -impl Clone for GenesisSource { +impl Clone for GenesisSource { fn clone(&self) -> Self { match *self { GenesisSource::File(ref path) => GenesisSource::File(path.clone()), @@ -104,12 +104,12 @@ struct ChainSpecFile { pub type Properties = json::map::Map; /// A configuration of a chain. Can be used to build a genesis block. -pub struct ChainSpec { +pub struct ChainSpec { spec: ChainSpecFile, genesis: GenesisSource, } -impl Clone for ChainSpec { +impl Clone for ChainSpec { fn clone(&self) -> Self { ChainSpec { spec: self.spec.clone(), diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 5e45d86fb2a22..c5f1869aee972 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -31,7 +31,7 @@ use tel::TelemetryEndpoints; /// Service configuration. #[derive(Clone)] -pub struct Configuration { +pub struct Configuration { /// Implementation name pub impl_name: &'static str, /// Implementation version @@ -56,8 +56,6 @@ pub struct Configuration { pub state_cache_child_ratio: Option, /// Pruning settings. pub pruning: PruningMode, - /// Additional key seeds. - pub keys: Vec, /// Chain configuration. pub chain_spec: ChainSpec, /// Custom configuration. @@ -117,7 +115,6 @@ impl Configuration Service { None }; - //TODO: Make sure we generate for all types and apps - if let Some((keystore, seed)) = keystore.and_then(|k| config.dev_key_seed.map(|s| (k, s))) { - keystore.generate_from_seed_by_type(&seed, primitives::crypto::key_types::ED25519); - keystore.generate_from_seed_by_type(&seed, primitives::crypto::key_types::SR25519); + if let Some((keystore, seed)) = keystore.as_mut() + .and_then(|k| config.dev_key_seed.clone().map(|s| (k, s))) + { + //TODO: Make sure we generate for all types and apps + keystore.generate_from_seed::(&seed)?; + keystore.generate_from_seed::(&seed)?; } let keystore = Arc::new(keystore); diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 8375521a70210..46a6ac13ff932 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -174,12 +174,12 @@ fn node_config ( transaction_pool: Default::default(), network: network_config, keystore_path: Some(root.join("key")), + keystore_password: None, database_path: root.join("db"), database_cache_size: None, state_cache_size: 16777216, state_cache_child_ratio: None, pruning: Default::default(), - keys: keys, chain_spec: (*spec).clone(), custom: Default::default(), name: format!("Node {}", index), @@ -195,7 +195,7 @@ fn node_config ( force_authoring: false, disable_grandpa: false, grandpa_voter: false, - password: "".to_string().into(), + dev_key_seed: None, } } From 1bffafee5d2662f9a5de3c845c8e153fa605d0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 31 Jul 2019 17:04:38 +0200 Subject: [PATCH 33/80] Fixes finality grandpa --- Cargo.lock | 1 + core/finality-grandpa/Cargo.toml | 1 + core/finality-grandpa/src/authorities.rs | 15 ++++---- .../src/communication/gossip.rs | 9 ++--- .../src/communication/tests.rs | 6 ++-- core/finality-grandpa/src/finality_proof.rs | 33 +++++++++-------- core/finality-grandpa/src/light_import.rs | 18 +++++----- core/finality-grandpa/src/tests.rs | 35 +++++++++---------- 8 files changed, 62 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a2fd79d7877c..381bdf568e7ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4489,6 +4489,7 @@ dependencies = [ "sr-primitives 2.0.0", "srml-finality-tracker 2.0.0", "substrate-client 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", "substrate-consensus-common 2.0.0", "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 8477f75eddcdd..b395257b2fa24 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -32,6 +32,7 @@ grandpa = { package = "finality-grandpa", version = "0.8.1", features = ["derive network = { package = "substrate-network", path = "../network", features = ["test-helpers"] } keyring = { package = "substrate-keyring", path = "../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"} +babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } env_logger = "0.6" tokio = "0.1.17" diff --git a/core/finality-grandpa/src/authorities.rs b/core/finality-grandpa/src/authorities.rs index 8b329d4116d8f..1295640626d71 100644 --- a/core/finality-grandpa/src/authorities.rs +++ b/core/finality-grandpa/src/authorities.rs @@ -431,6 +431,7 @@ impl + Clone> PendingChange { #[cfg(test)] mod tests { use super::*; + use primitives::crypto::Public; fn static_is_descendent_of(value: bool) -> impl Fn(&A, &A) -> Result @@ -520,8 +521,8 @@ mod tests { pending_forced_changes: Vec::new(), }; - let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)]; - let set_b = vec![(AuthorityId::from_raw([2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; + let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { @@ -585,8 +586,8 @@ mod tests { pending_forced_changes: Vec::new(), }; - let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)]; - let set_c = vec![(AuthorityId::from_raw([2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; + let set_c = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; // two competing changes at the same height on different forks let change_a = PendingChange { @@ -651,7 +652,7 @@ mod tests { pending_forced_changes: Vec::new(), }; - let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; let change_a = PendingChange { next_authorities: set_a.clone(), @@ -717,8 +718,8 @@ mod tests { pending_forced_changes: Vec::new(), }; - let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)]; - let set_b = vec![(AuthorityId::from_raw([2; 32]), 5)]; + let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)]; + let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)]; let change_a = PendingChange { next_authorities: set_a.clone(), diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index 7106ac61a231d..df4c41c8958ac 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -1233,6 +1233,7 @@ mod tests { use super::environment::SharedVoterSetState; use network_gossip::Validator as GossipValidatorT; use network::test::Block; + use primitives::crypto::Public; // some random config (not really needed) fn config() -> crate::Config { @@ -1452,7 +1453,7 @@ mod tests { voter_set_state(), ); let set_id = 1; - let auth = AuthorityId::from_raw([1u8; 32]); + let auth = AuthorityId::from_slice(&[1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); @@ -1468,7 +1469,7 @@ mod tests { target_number: 10, }), signature: Default::default(), - id: AuthorityId::from_raw([2u8; 32]), + id: AuthorityId::from_slice(&[2u8; 32]), } }); @@ -1497,7 +1498,7 @@ mod tests { ); let set_id = 1; - let auth = AuthorityId::from_raw([1u8; 32]); + let auth = AuthorityId::from_slice(&[1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); @@ -1562,7 +1563,7 @@ mod tests { ); let set_id = 1; - let auth = AuthorityId::from_raw([1u8; 32]); + let auth = AuthorityId::from_slice(&[1u8; 32]); let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index cfe41acb3c68e..20eba1a414d99 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -204,7 +204,7 @@ fn make_test_network() -> ( fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { keys.iter() - .map(|key| AuthorityId(key.to_raw_public())) + .map(|key| key.clone().public().into()) .map(|id| (id, 1)) .collect() } @@ -242,7 +242,7 @@ fn good_commit_leads_to_relay() { for (i, key) in private.iter().enumerate() { precommits.push(precommit.clone()); - let signature = key.sign(&payload[..]); + let signature = fg_primitives::AuthoritySignature::from(key.sign(&payload[..])); auth_data.push((signature, public[i].0.clone())) } @@ -357,7 +357,7 @@ fn bad_commit_leads_to_report() { for (i, key) in private.iter().enumerate() { precommits.push(precommit.clone()); - let signature = key.sign(&payload[..]); + let signature = fg_primitives::AuthoritySignature::from(key.sign(&payload[..])); auth_data.push((signature, public[i].0.clone())) } diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index f174fb04f6061..f010090a899df 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -581,6 +581,7 @@ pub(crate) mod tests { use test_client::client::{backend::NewBlockState}; use test_client::client::in_mem::Blockchain as InMemoryBlockchain; use super::*; + use primitives::crypto::Public; type FinalityProof = super::FinalityProof