Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
grandpa: Write AuthorityList to storage with encoding version.
Browse files Browse the repository at this point in the history
We expect the AuthorityList type may change (eg. key changes). To make
upgrades smoother, include a version in the stored value.
  • Loading branch information
jimpo committed Oct 4, 2019
1 parent 48f7b7c commit 0349a8b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 8 deletions.
54 changes: 52 additions & 2 deletions core/finality-grandpa/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ extern crate alloc;

#[cfg(feature = "std")]
use serde::Serialize;
use codec::{Encode, Decode, Codec};
use codec::{Encode, Decode, Input, Codec};
use sr_primitives::ConsensusEngineId;
use rstd::borrow::Cow;
use rstd::vec::Vec;

mod app {
Expand All @@ -46,7 +47,7 @@ pub type AuthoritySignature = app::Signature;
pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK";

/// The storage key for the current set of weighted Grandpa authorities.
/// The value stored is an encoded AuthorityList.
/// The value stored is an encoded VersionedAuthorityList.
pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities";

/// The weight of an authority.
Expand Down Expand Up @@ -159,3 +160,52 @@ impl<N: Codec> ConsensusLog<N> {
pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change";
/// WASM function call to get current GRANDPA authorities.
pub const AUTHORITIES_CALL: &str = "grandpa_authorities";

/// The current version of the stored AuthorityList type. The encoding version MUST be updated any
/// time the AuthorityList type changes.
const AUTHORITIES_VERISON: u8 = 1;

/// An AuthorityList that is encoded with a version specifier. The encoding version is updated any
/// time the AuthorityList type changes. This ensures that encodings of different versions of an
/// AuthorityList are differentiable. Attempting to decode an authority list with an unknown
/// version will fail.
#[derive(Default)]
pub struct VersionedAuthorityList<'a>(Cow<'a, AuthorityList>);

impl<'a> From<AuthorityList> for VersionedAuthorityList<'a> {
fn from(authorities: AuthorityList) -> Self {
VersionedAuthorityList(Cow::Owned(authorities))
}
}

impl<'a> From<&'a AuthorityList> for VersionedAuthorityList<'a> {
fn from(authorities: &'a AuthorityList) -> Self {
VersionedAuthorityList(Cow::Borrowed(authorities))
}
}

impl<'a> Into<AuthorityList> for VersionedAuthorityList<'a> {
fn into(self) -> AuthorityList {
self.0.into_owned()
}
}

impl<'a> Encode for VersionedAuthorityList<'a> {
fn size_hint(&self) -> usize {
(AUTHORITIES_VERISON, self.0.as_ref()).size_hint()
}

fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
(AUTHORITIES_VERISON, self.0.as_ref()).using_encoded(f)
}
}

impl<'a> Decode for VersionedAuthorityList<'a> {
fn decode<I: Input>(value: &mut I) -> Result<Self, codec::Error> {
let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?;
if version != AUTHORITIES_VERISON {
return Err("unknown Grandpa authorities version".into());
}
Ok(authorities.into())
}
}
10 changes: 7 additions & 3 deletions core/finality-grandpa/src/finality_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use sr_primitives::{
};
use primitives::{H256, Blake2Hasher, storage::StorageKey};
use substrate_telemetry::{telemetry, CONSENSUS_INFO};
use fg_primitives::{AuthorityId, AuthorityList, GRANDPA_AUTHORITIES_KEY};
use fg_primitives::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY};

use crate::justification::GrandpaJustification;

Expand All @@ -76,7 +76,8 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> AuthoritySetForFinalityProver<Block> fo
fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList> {
let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec());
self.storage(block, &storage_key)?
.and_then(|encoded| AuthorityList::decode(&mut encoded.0.as_slice()).ok())
.and_then(|encoded| VersionedAuthorityList::decode(&mut encoded.0.as_slice()).ok())
.map(|versioned| versioned.into())
.ok_or(ClientError::InvalidAuthoritiesSet)
}

Expand Down Expand Up @@ -122,7 +123,10 @@ impl<Block: BlockT> AuthoritySetForFinalityChecker<Block> for Arc<dyn FetchCheck
);
maybe_encoded
.as_ref()
.and_then(|encoded| AuthorityList::decode(&mut encoded.as_slice()).ok())
.and_then(|encoded| {
VersionedAuthorityList::decode(&mut encoded.as_slice()).ok()
})
.map(|versioned| versioned.into())
.ok_or(ClientError::InvalidAuthoritiesSet)
})
}
Expand Down
9 changes: 6 additions & 3 deletions srml/grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use sr_staking_primitives::{
use fg_primitives::{
GRANDPA_AUTHORITIES_KEY, GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber,
};
pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight};
pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList};
use system::{ensure_signed, DigestOf};

mod mock;
Expand Down Expand Up @@ -249,12 +249,15 @@ decl_module! {
impl<T: Trait> Module<T> {
/// Get the current set of authorities, along with their respective weights.
pub fn grandpa_authorities() -> AuthorityList {
storage::unhashed::get_or_default(GRANDPA_AUTHORITIES_KEY)
storage::unhashed::get_or_default::<VersionedAuthorityList>(GRANDPA_AUTHORITIES_KEY).into()
}

/// Set the current set of authorities, along with their respective weights.
fn set_grandpa_authorities(authorities: &AuthorityList) {
storage::unhashed::put(GRANDPA_AUTHORITIES_KEY, authorities)
storage::unhashed::put(
GRANDPA_AUTHORITIES_KEY,
&VersionedAuthorityList::from(authorities),
);
}

/// Schedule GRANDPA to pause starting in the given number of blocks.
Expand Down

0 comments on commit 0349a8b

Please sign in to comment.