Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Remove footgun around session keys/handlers
- `OpaqueKeys` now has an associated type `KeyTypeIdProviders`. This can
be used in the runtime as input for `SessionHandler` from the session
trait.
- `impl_opaque_keys` now works with modules and extracts the `KeyTypeId`
from the module directly.
- Added some checks to the `session` storage initialization that checks
that the `SessionHandler` and `Keys` use the same number of keys and
that the order is equal.
  • Loading branch information
bkchr committed Oct 28, 2019
commit 4c9c46e91b4103f070d703d992650ebdb2e1bf1d
20 changes: 10 additions & 10 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions core/application-crypto/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub use primitives::ed25519::*;
mod app {
use primitives::testing::ED25519;
crate::app_crypto!(super, ED25519);

impl crate::traits::BoundToRuntimeAppPublic for Public {
type Public = Self;
}
}

pub use app::Public as AppPublic;
Expand Down
4 changes: 4 additions & 0 deletions core/application-crypto/src/sr25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub use primitives::sr25519::*;
mod app {
use primitives::testing::SR25519;
crate::app_crypto!(super, SR25519);

impl crate::traits::BoundToRuntimeAppPublic for Public {
type Public = Self;
}
}

pub use app::Public as AppPublic;
Expand Down
5 changes: 5 additions & 0 deletions core/application-crypto/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,8 @@ pub trait RuntimeAppPublic: Sized {
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool;
}

/// Something that bound to a fixed `RuntimeAppPublic`.
pub trait BoundToRuntimeAppPublic {
/// The `RuntimeAppPublic` this type is bound to.
type Public: RuntimeAppPublic;
}
2 changes: 1 addition & 1 deletion core/sr-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub use generic::{DigestItem, Digest};

/// Re-export this since it's part of the API of this crate.
pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, AccountId32}};
pub use app_crypto::RuntimeAppPublic;
pub use app_crypto::{RuntimeAppPublic, BoundToRuntimeAppPublic};

/// Re-export `RuntimeDebug`, to avoid dependency clutter.
pub use primitives::RuntimeDebug;
Expand Down
10 changes: 7 additions & 3 deletions core/sr-primitives/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ impl app_crypto::RuntimeAppPublic for UintAuthorityId {
}

impl OpaqueKeys for UintAuthorityId {
type KeyTypeIds = std::iter::Cloned<std::slice::Iter<'static, KeyTypeId>>;
type KeyTypeIdProviders = ();

fn key_ids() -> Self::KeyTypeIds {
[key_types::DUMMY].iter().cloned()
fn key_ids() -> &'static [KeyTypeId] {
&[key_types::DUMMY]
}

fn get_raw(&self, _: KeyTypeId) -> &[u8] {
Expand All @@ -132,6 +132,10 @@ impl OpaqueKeys for UintAuthorityId {
}
}

impl crate::BoundToRuntimeAppPublic for UintAuthorityId {
type Public = Self;
}

/// Digest item
pub type DigestItem = generic::DigestItem<H256>;

Expand Down
69 changes: 44 additions & 25 deletions core/sr-primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,14 +979,14 @@ pub trait ValidateUnsigned {
fn validate_unsigned(call: &Self::Call) -> TransactionValidity;
}

/// Opaque datatype that may be destructured into a series of raw byte slices (which represent
/// Opaque datatype that may be destructed into a series of raw byte slices (which represent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Destructured is correct here.

/// individual keys).
pub trait OpaqueKeys: Clone {
/// An iterator over the type IDs of keys that this holds.
type KeyTypeIds: IntoIterator<Item=super::KeyTypeId>;
/// Types bound to this opaque keys that provide the key type ids returned.
type KeyTypeIdProviders;

/// Return an iterator over the key-type IDs supported by this set.
fn key_ids() -> Self::KeyTypeIds;
/// Return the key-type IDs supported by this set.
fn key_ids() -> &'static [crate::KeyTypeId];
/// Get the raw bytes of key with key-type ID `i`.
fn get_raw(&self, i: super::KeyTypeId) -> &[u8];
/// Get the decoded key with index `i`.
Expand Down Expand Up @@ -1086,22 +1086,25 @@ macro_rules! count {
}

/// Implement `OpaqueKeys` for a described struct.
/// Would be much nicer for this to be converted to `derive` code.
///
/// Every field type must be equivalent implement `as_ref()`, which is expected
/// to hold the standard SCALE-encoded form of that key. This is typically
/// just the bytes of the key.
/// Every field type must implement [`BoundToRuntimeAppPublic`](crate::BoundToRuntimeAppPublic).
/// `KeyTypeIdProviders` is set to the types given as fields.
///
/// ```rust
/// use sr_primitives::{impl_opaque_keys, KeyTypeId, app_crypto::{sr25519, ed25519}};
/// use primitives::testing::{SR25519, ED25519};
/// use sr_primitives::{
/// impl_opaque_keys, KeyTypeId, BoundToRuntimeAppPublic, app_crypto::{sr25519, ed25519}
/// };
///
/// pub struct KeyModule;
/// impl BoundToRuntimeAppPublic for KeyModule { type Public = ed25519::AppPublic; }
///
/// pub struct KeyModule2;
/// impl BoundToRuntimeAppPublic for KeyModule2 { type Public = sr25519::AppPublic; }
///
/// impl_opaque_keys! {
/// pub struct Keys {
/// #[id(ED25519)]
/// pub ed25519: ed25519::AppPublic,
/// #[id(SR25519)]
/// pub sr25519: sr25519::AppPublic,
/// pub key_module: KeyModule,
/// pub key_module2: KeyModule2,
/// }
/// }
/// ```
Expand All @@ -1110,7 +1113,6 @@ macro_rules! impl_opaque_keys {
(
pub struct $name:ident {
$(
#[id($key_id:expr)]
pub $field:ident: $type:ty,
)*
}
Expand All @@ -1119,12 +1121,12 @@ macro_rules! impl_opaque_keys {
Default, Clone, PartialEq, Eq,
$crate::codec::Encode,
$crate::codec::Decode,
$crate::RuntimeDebug
$crate::RuntimeDebug,
)]
#[cfg_attr(feature = "std", derive($crate::serde::Serialize, $crate::serde::Deserialize))]
pub struct $name {
$(
pub $field: $type,
pub $field: <$type as $crate::BoundToRuntimeAppPublic>::Public,
)*
}

Expand All @@ -1137,25 +1139,42 @@ macro_rules! impl_opaque_keys {
pub fn generate(seed: Option<&str>) -> $crate::rstd::vec::Vec<u8> {
let keys = Self{
$(
$field: <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed),
$field: <
<
$type as $crate::BoundToRuntimeAppPublic
>::Public as $crate::RuntimeAppPublic
>::generate_pair(seed),
)*
};
$crate::codec::Encode::encode(&keys)
}
}

impl $crate::traits::OpaqueKeys for $name {
type KeyTypeIds = $crate::rstd::iter::Cloned<
$crate::rstd::slice::Iter<'static, $crate::KeyTypeId>
>;
type KeyTypeIdProviders = ( $( $type, )* );

fn key_ids() -> Self::KeyTypeIds {
[ $($key_id),* ].iter().cloned()
fn key_ids() -> &'static [$crate::KeyTypeId] {
&[
$(
<
<
$type as $crate::BoundToRuntimeAppPublic
>::Public as $crate::RuntimeAppPublic
>::ID
),*
]
}

fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] {
match i {
$( i if i == $key_id => self.$field.as_ref(), )*
$(
i if i == <
<
$type as $crate::BoundToRuntimeAppPublic
>::Public as $crate::RuntimeAppPublic
>::ID =>
self.$field.as_ref(),
)*
_ => &[],
}
}
Expand Down
12 changes: 1 addition & 11 deletions core/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,7 @@ pub mod system;
use rstd::{prelude::*, marker::PhantomData};
use codec::{Encode, Decode, Input, Error};

use primitives::{
Blake2Hasher,
OpaqueMetadata,
RuntimeDebug,
testing::{
ED25519,
SR25519,
}
};
use primitives::{Blake2Hasher, OpaqueMetadata, RuntimeDebug};
use app_crypto::{ed25519, sr25519, RuntimeAppPublic};
pub use app_crypto;
use trie_db::{TrieMut, Trie};
Expand Down Expand Up @@ -454,9 +446,7 @@ fn code_using_trie() -> u64 {

impl_opaque_keys! {
pub struct SessionKeys {
#[id(ED25519)]
pub ed25519: ed25519::AppPublic,
#[id(SR25519)]
pub sr25519: sr25519::AppPublic,
}
}
Expand Down
8 changes: 3 additions & 5 deletions node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

use rstd::prelude::*;
use primitives::{OpaqueMetadata, crypto::key_types};
use primitives::OpaqueMetadata;
use sr_primitives::{
ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str,
impl_opaque_keys, MultiSignature
Expand Down Expand Up @@ -84,10 +84,8 @@ pub mod opaque {

impl_opaque_keys! {
pub struct SessionKeys {
#[id(key_types::AURA)]
pub aura: AuraId,
#[id(key_types::GRANDPA)]
pub grandpa: GrandpaId,
pub aura: Aura,
pub grandpa: Grandpa,
}
}
}
Expand Down
27 changes: 6 additions & 21 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,18 @@ use node_primitives::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
Moment, Signature,
};
use babe_primitives::AuthorityId as BabeId;
use grandpa::fg_primitives;
use client::{
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
runtime_api as client_api, impl_runtime_apis
};
use sr_primitives::{
Permill, Perbill, ApplyResult, impl_opaque_keys, generic, create_runtime_str, key_types
};
use sr_primitives::{Permill, Perbill, ApplyResult, impl_opaque_keys, generic, create_runtime_str};
use sr_primitives::curve::PiecewiseLinear;
use sr_primitives::transaction_validity::TransactionValidity;
use sr_primitives::weights::Weight;
use sr_primitives::traits::{
self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion,
OpaqueKeys,
};
use version::RuntimeVersion;
#[cfg(any(feature = "std", test))]
Expand Down Expand Up @@ -209,34 +207,21 @@ impl authorship::Trait for Runtime {
type EventHandler = Staking;
}

// !!!!!!!!!!!!!
// WARNING!!!!!! SEE NOTE BELOW BEFORE TOUCHING THIS CODE
// !!!!!!!!!!!!!
type SessionHandlers = (Grandpa, Babe, ImOnline);

impl_opaque_keys! {
pub struct SessionKeys {
#[id(key_types::GRANDPA)]
pub grandpa: GrandpaId,
#[id(key_types::BABE)]
pub babe: BabeId,
#[id(key_types::IM_ONLINE)]
pub im_online: ImOnlineId,
pub grandpa: Grandpa,
pub babe: Babe,
pub im_online: ImOnline,
}
}

// NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler.
// The number and order of items in `SessionHandler` *MUST* be the same number and order of keys in
// `SessionKeys`.
// TODO: Introduce some structure to tie these together to make it a bit less of a footgun. This
// should be easy, since OneSessionHandler trait provides the `Key` as an associated type. #2858
parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
}

impl session::Trait for Runtime {
type OnSessionEnding = Staking;
type SessionHandler = SessionHandlers;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type ShouldEndSession = Babe;
type Event = Event;
type Keys = SessionKeys;
Expand Down
Loading