grandpa: Use storage proofs for Grandpa authorities (#3985)

This commit is contained in:
Jim Posen
2019-11-07 14:31:17 +01:00
committed by GitHub
parent bb6b3db57e
commit 021f3a3f06
16 changed files with 289 additions and 149 deletions
@@ -23,9 +23,10 @@ extern crate alloc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use serde::Serialize; use serde::Serialize;
use codec::{Encode, Decode, Codec}; use codec::{Encode, Decode, Input, Codec};
use sr_primitives::{ConsensusEngineId, RuntimeDebug}; use sr_primitives::{ConsensusEngineId, RuntimeDebug};
use client::decl_runtime_apis; use client::decl_runtime_apis;
use rstd::borrow::Cow;
use rstd::vec::Vec; use rstd::vec::Vec;
mod app { mod app {
@@ -46,6 +47,10 @@ pub type AuthoritySignature = app::Signature;
/// The `ConsensusEngineId` of GRANDPA. /// The `ConsensusEngineId` of GRANDPA.
pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; 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 VersionedAuthorityList.
pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities";
/// The weight of an authority. /// The weight of an authority.
pub type AuthorityWeight = u64; pub type AuthorityWeight = u64;
@@ -58,12 +63,15 @@ pub type SetId = u64;
/// The round indicator. /// The round indicator.
pub type RoundNumber = u64; pub type RoundNumber = u64;
/// A list of Grandpa authorities with associated weights.
pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>;
/// A scheduled change of authority set. /// A scheduled change of authority set.
#[cfg_attr(feature = "std", derive(Serialize))] #[cfg_attr(feature = "std", derive(Serialize))]
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
pub struct ScheduledChange<N> { pub struct ScheduledChange<N> {
/// The new authorities after the change, along with their respective weights. /// The new authorities after the change, along with their respective weights.
pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, pub next_authorities: AuthorityList,
/// The number of blocks to delay. /// The number of blocks to delay.
pub delay: N, pub delay: N,
} }
@@ -154,6 +162,55 @@ pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change";
/// WASM function call to get current GRANDPA authorities. /// WASM function call to get current GRANDPA authorities.
pub const AUTHORITIES_CALL: &str = "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())
}
}
decl_runtime_apis! { decl_runtime_apis! {
/// APIs for integrating the GRANDPA finality gadget into runtimes. /// APIs for integrating the GRANDPA finality gadget into runtimes.
/// This should be implemented on the runtime side. /// This should be implemented on the runtime side.
@@ -172,6 +229,6 @@ decl_runtime_apis! {
/// When called at block B, it will return the set of authorities that should be /// When called at block B, it will return the set of authorities that should be
/// used to finalize descendants of this block (B+1, B+2, ...). The block B itself /// used to finalize descendants of this block (B+1, B+2, ...). The block B itself
/// is finalized by the authorities from block B-1. /// is finalized by the authorities from block B-1.
fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)>; fn grandpa_authorities() -> AuthorityList;
} }
} }
@@ -22,7 +22,7 @@ use grandpa::voter_set::VoterSet;
use codec::{Encode, Decode}; use codec::{Encode, Decode};
use log::{debug, info}; use log::{debug, info};
use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use substrate_telemetry::{telemetry, CONSENSUS_INFO};
use fg_primitives::AuthorityId; use fg_primitives::{AuthorityId, AuthorityList};
use std::cmp::Ord; use std::cmp::Ord;
use std::fmt::Debug; use std::fmt::Debug;
@@ -86,7 +86,7 @@ pub(crate) struct Status<H, N> {
/// A set of authorities. /// A set of authorities.
#[derive(Debug, Clone, Encode, Decode, PartialEq)] #[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub(crate) struct AuthoritySet<H, N> { pub(crate) struct AuthoritySet<H, N> {
pub(crate) current_authorities: Vec<(AuthorityId, u64)>, pub(crate) current_authorities: AuthorityList,
pub(crate) set_id: u64, pub(crate) set_id: u64,
// Tree of pending standard changes across forks. Standard changes are // Tree of pending standard changes across forks. Standard changes are
// enacted on finality and must be enacted (i.e. finalized) in-order across // enacted on finality and must be enacted (i.e. finalized) in-order across
@@ -103,7 +103,7 @@ where H: PartialEq,
N: Ord, N: Ord,
{ {
/// Get a genesis set with given authorities. /// Get a genesis set with given authorities.
pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { pub(crate) fn genesis(initial: AuthorityList) -> Self {
AuthoritySet { AuthoritySet {
current_authorities: initial, current_authorities: initial,
set_id: 0, set_id: 0,
@@ -390,7 +390,7 @@ pub(crate) enum DelayKind<N> {
#[derive(Debug, Clone, Encode, PartialEq)] #[derive(Debug, Clone, Encode, PartialEq)]
pub(crate) struct PendingChange<H, N> { pub(crate) struct PendingChange<H, N> {
/// The new authorities and weights to apply. /// The new authorities and weights to apply.
pub(crate) next_authorities: Vec<(AuthorityId, u64)>, pub(crate) next_authorities: AuthorityList,
/// How deep in the chain the announcing block must be /// How deep in the chain the announcing block must be
/// before the change is applied. /// before the change is applied.
pub(crate) delay: N, pub(crate) delay: N,
@@ -25,7 +25,7 @@ use fork_tree::ForkTree;
use grandpa::round::State as RoundState; use grandpa::round::State as RoundState;
use sr_primitives::traits::{Block as BlockT, NumberFor}; use sr_primitives::traits::{Block as BlockT, NumberFor};
use log::{info, warn}; use log::{info, warn};
use fg_primitives::{AuthorityId, AuthorityWeight, SetId, RoundNumber}; use fg_primitives::{AuthorityList, SetId, RoundNumber};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind}; use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind};
use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges}; use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges};
@@ -55,7 +55,7 @@ type V0VoterSetState<H, N> = (RoundNumber, RoundState<H, N>);
#[derive(Debug, Clone, Encode, Decode, PartialEq)] #[derive(Debug, Clone, Encode, Decode, PartialEq)]
struct V0PendingChange<H, N> { struct V0PendingChange<H, N> {
next_authorities: Vec<(AuthorityId, AuthorityWeight)>, next_authorities: AuthorityList,
delay: N, delay: N,
canon_height: N, canon_height: N,
canon_hash: H, canon_hash: H,
@@ -63,7 +63,7 @@ struct V0PendingChange<H, N> {
#[derive(Debug, Clone, Encode, Decode, PartialEq)] #[derive(Debug, Clone, Encode, Decode, PartialEq)]
struct V0AuthoritySet<H, N> { struct V0AuthoritySet<H, N> {
current_authorities: Vec<(AuthorityId, AuthorityWeight)>, current_authorities: AuthorityList,
set_id: SetId, set_id: SetId,
pending_changes: Vec<V0PendingChange<H, N>>, pending_changes: Vec<V0PendingChange<H, N>>,
} }
@@ -266,7 +266,7 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
-> ClientResult<PersistentData<Block>> -> ClientResult<PersistentData<Block>>
where where
B: AuxStore, B: AuxStore,
G: FnOnce() -> ClientResult<Vec<(AuthorityId, AuthorityWeight)>>, G: FnOnce() -> ClientResult<AuthorityList>,
{ {
let version: Option<u32> = load_decode(backend, VERSION_KEY)?; let version: Option<u32> = load_decode(backend, VERSION_KEY)?;
let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)? let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)?
@@ -426,6 +426,7 @@ pub(crate) fn load_authorities<B: AuxStore, H: Decode, N: Decode>(backend: &B)
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use fg_primitives::AuthorityId;
use primitives::H256; use primitives::H256;
use test_client; use test_client;
use super::*; use super::*;
@@ -28,6 +28,7 @@ use codec::Encode;
use sr_primitives::traits::NumberFor; use sr_primitives::traits::NumberFor;
use crate::environment::SharedVoterSetState; use crate::environment::SharedVoterSetState;
use fg_primitives::AuthorityList;
use super::gossip::{self, GossipValidator}; use super::gossip::{self, GossipValidator};
use super::{AuthorityId, VoterSet, Round, SetId}; use super::{AuthorityId, VoterSet, Round, SetId};
@@ -200,7 +201,7 @@ fn make_test_network() -> (
) )
} }
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
keys.iter() keys.iter()
.map(|key| key.clone().public().into()) .map(|key| key.clone().public().into())
.map(|id| (id, 1)) .map(|id| (id, 1))
@@ -34,13 +34,14 @@
//! finality proof (that finalizes some block C that is ancestor of the B and descendant //! finality proof (that finalizes some block C that is ancestor of the B and descendant
//! of the U) could be returned. //! of the U) could be returned.
use std::iter;
use std::sync::Arc; use std::sync::Arc;
use log::{trace, warn}; use log::{trace, warn};
use client::{ use client::{
backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client, backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client,
error::{Error as ClientError, Result as ClientResult}, error::{Error as ClientError, Result as ClientResult},
light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy, light::fetcher::{FetchChecker, RemoteReadRequest, StorageProof},
}; };
use codec::{Encode, Decode}; use codec::{Encode, Decode};
use grandpa::BlockNumberOps; use grandpa::BlockNumberOps;
@@ -48,9 +49,9 @@ use sr_primitives::{
Justification, generic::BlockId, Justification, generic::BlockId,
traits::{NumberFor, Block as BlockT, Header as HeaderT, One}, traits::{NumberFor, Block as BlockT, Header as HeaderT, One},
}; };
use primitives::{H256, Blake2Hasher}; use primitives::{H256, Blake2Hasher, storage::StorageKey};
use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use substrate_telemetry::{telemetry, CONSENSUS_INFO};
use fg_primitives::AuthorityId; use fg_primitives::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY};
use crate::justification::GrandpaJustification; use crate::justification::GrandpaJustification;
@@ -59,9 +60,9 @@ const MAX_FRAGMENTS_IN_PROOF: usize = 8;
/// GRANDPA authority set related methods for the finality proof provider. /// GRANDPA authority set related methods for the finality proof provider.
pub trait AuthoritySetForFinalityProver<Block: BlockT>: Send + Sync { pub trait AuthoritySetForFinalityProver<Block: BlockT>: Send + Sync {
/// Call GrandpaApi::grandpa_authorities at given block. /// Read GRANDPA_AUTHORITIES_KEY from storage at given block.
fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>>; fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList>;
/// Prove call of GrandpaApi::grandpa_authorities at given block. /// Prove storage read of GRANDPA_AUTHORITIES_KEY at given block.
fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof>; fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof>;
} }
@@ -72,33 +73,28 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> AuthoritySetForFinalityProver<Block> fo
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync, E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: Send + Sync, RA: Send + Sync,
{ {
fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>> { fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList> {
self.executor().call( let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec());
block, self.storage(block, &storage_key)?
"GrandpaApi_grandpa_authorities", .and_then(|encoded| VersionedAuthorityList::decode(&mut encoded.0.as_slice()).ok())
&[], .map(|versioned| versioned.into())
ExecutionStrategy::NativeElseWasm, .ok_or(ClientError::InvalidAuthoritiesSet)
None,
).and_then(|call_result| Decode::decode(&mut &call_result[..])
.map_err(|err| ClientError::CallResultDecode(
"failed to decode GRANDPA authorities set proof".into(), err
)))
} }
fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof> { fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof> {
self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof) self.read_proof(block, iter::once(GRANDPA_AUTHORITIES_KEY))
} }
} }
/// GRANDPA authority set related methods for the finality proof checker. /// GRANDPA authority set related methods for the finality proof checker.
pub trait AuthoritySetForFinalityChecker<Block: BlockT>: Send + Sync { pub trait AuthoritySetForFinalityChecker<Block: BlockT>: Send + Sync {
/// Check execution proof of Grandpa::grandpa_authorities at given block. /// Check storage read proof of GRANDPA_AUTHORITIES_KEY at given block.
fn check_authorities_proof( fn check_authorities_proof(
&self, &self,
hash: Block::Hash, hash: Block::Hash,
header: Block::Header, header: Block::Header,
proof: StorageProof, proof: StorageProof,
) -> ClientResult<Vec<(AuthorityId, u64)>>; ) -> ClientResult<AuthorityList>;
} }
/// FetchChecker-based implementation of AuthoritySetForFinalityChecker. /// FetchChecker-based implementation of AuthoritySetForFinalityChecker.
@@ -108,22 +104,30 @@ impl<Block: BlockT> AuthoritySetForFinalityChecker<Block> for Arc<dyn FetchCheck
hash: Block::Hash, hash: Block::Hash,
header: Block::Header, header: Block::Header,
proof: StorageProof, proof: StorageProof,
) -> ClientResult<Vec<(AuthorityId, u64)>> { ) -> ClientResult<AuthorityList> {
let request = RemoteCallRequest { let storage_key = GRANDPA_AUTHORITIES_KEY.to_vec();
let request = RemoteReadRequest {
block: hash, block: hash,
header, header,
method: "GrandpaApi_grandpa_authorities".into(), keys: vec![storage_key.clone()],
call_data: vec![],
retry_count: None, retry_count: None,
}; };
self.check_execution_proof(&request, proof) self.check_read_proof(&request, proof)
.and_then(|authorities| { .and_then(|results| {
let authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &authorities[..]) let maybe_encoded = results.get(&storage_key)
.map_err(|err| ClientError::CallResultDecode( .expect(
"failed to decode GRANDPA authorities set proof".into(), err "storage_key is listed in the request keys; \
))?; check_read_proof must return a value for each requested key;
Ok(authorities.into_iter().collect()) qed"
);
maybe_encoded
.as_ref()
.and_then(|encoded| {
VersionedAuthorityList::decode(&mut encoded.as_slice()).ok()
})
.map(|versioned| versioned.into())
.ok_or(ClientError::InvalidAuthoritiesSet)
}) })
} }
} }
@@ -189,7 +193,7 @@ pub struct FinalityEffects<Header: HeaderT> {
/// New authorities set id that should be applied starting from block. /// New authorities set id that should be applied starting from block.
pub new_set_id: u64, pub new_set_id: u64,
/// New authorities set that should be applied starting from block. /// New authorities set that should be applied starting from block.
pub new_authorities: Vec<(AuthorityId, u64)>, pub new_authorities: AuthorityList,
} }
/// Single fragment of proof-of-finality. /// Single fragment of proof-of-finality.
@@ -408,7 +412,7 @@ pub(crate) fn prove_finality<Block: BlockT<Hash=H256>, B: BlockchainBackend<Bloc
pub(crate) fn check_finality_proof<Block: BlockT<Hash=H256>, B>( pub(crate) fn check_finality_proof<Block: BlockT<Hash=H256>, B>(
blockchain: &B, blockchain: &B,
current_set_id: u64, current_set_id: u64,
current_authorities: Vec<(AuthorityId, u64)>, current_authorities: AuthorityList,
authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>, authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>,
remote_proof: Vec<u8>, remote_proof: Vec<u8>,
) -> ClientResult<FinalityEffects<Block::Header>> ) -> ClientResult<FinalityEffects<Block::Header>>
@@ -427,7 +431,7 @@ pub(crate) fn check_finality_proof<Block: BlockT<Hash=H256>, B>(
fn do_check_finality_proof<Block: BlockT<Hash=H256>, B, J>( fn do_check_finality_proof<Block: BlockT<Hash=H256>, B, J>(
blockchain: &B, blockchain: &B,
current_set_id: u64, current_set_id: u64,
current_authorities: Vec<(AuthorityId, u64)>, current_authorities: AuthorityList,
authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>, authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>,
remote_proof: Vec<u8>, remote_proof: Vec<u8>,
) -> ClientResult<FinalityEffects<Block::Header>> ) -> ClientResult<FinalityEffects<Block::Header>>
@@ -522,12 +526,12 @@ fn check_finality_proof_fragment<Block: BlockT<Hash=H256>, B, J>(
/// Authorities set from initial authorities set or finality effects. /// Authorities set from initial authorities set or finality effects.
enum AuthoritiesOrEffects<Header: HeaderT> { enum AuthoritiesOrEffects<Header: HeaderT> {
Authorities(u64, Vec<(AuthorityId, u64)>), Authorities(u64, AuthorityList),
Effects(FinalityEffects<Header>), Effects(FinalityEffects<Header>),
} }
impl<Header: HeaderT> AuthoritiesOrEffects<Header> { impl<Header: HeaderT> AuthoritiesOrEffects<Header> {
pub fn extract_authorities(self) -> (u64, Vec<(AuthorityId, u64)>) { pub fn extract_authorities(self) -> (u64, AuthorityList) {
match self { match self {
AuthoritiesOrEffects::Authorities(set_id, authorities) => (set_id, authorities), AuthoritiesOrEffects::Authorities(set_id, authorities) => (set_id, authorities),
AuthoritiesOrEffects::Effects(effects) => (effects.new_set_id, effects.new_authorities), AuthoritiesOrEffects::Effects(effects) => (effects.new_set_id, effects.new_authorities),
@@ -581,10 +585,10 @@ pub(crate) mod tests {
impl<GetAuthorities, ProveAuthorities> AuthoritySetForFinalityProver<Block> for (GetAuthorities, ProveAuthorities) impl<GetAuthorities, ProveAuthorities> AuthoritySetForFinalityProver<Block> for (GetAuthorities, ProveAuthorities)
where where
GetAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>>, GetAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<AuthorityList>,
ProveAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<StorageProof>, ProveAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<StorageProof>,
{ {
fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>> { fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList> {
self.0(*block) self.0(*block)
} }
@@ -597,14 +601,14 @@ pub(crate) mod tests {
impl<Closure> AuthoritySetForFinalityChecker<Block> for ClosureAuthoritySetForFinalityChecker<Closure> impl<Closure> AuthoritySetForFinalityChecker<Block> for ClosureAuthoritySetForFinalityChecker<Closure>
where where
Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult<Vec<(AuthorityId, u64)>>, Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult<AuthorityList>,
{ {
fn check_authorities_proof( fn check_authorities_proof(
&self, &self,
hash: H256, hash: H256,
header: Header, header: Header,
proof: StorageProof, proof: StorageProof
) -> ClientResult<Vec<(AuthorityId, u64)>> { ) -> ClientResult<AuthorityList> {
self.0(hash, header, proof) self.0(hash, header, proof)
} }
} }
+43 -17
View File
@@ -57,14 +57,12 @@ use log::{debug, error, info};
use futures::sync::mpsc; use futures::sync::mpsc;
use client::{ use client::{
BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError, BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError,
ExecutionStrategy,
}; };
use client::blockchain::HeaderBackend; use client::blockchain::HeaderBackend;
use codec::Encode; use codec::{Decode, Encode};
use sr_primitives::generic::BlockId; use sr_primitives::generic::BlockId;
use sr_primitives::traits::{ use sr_primitives::traits::{NumberFor, Block as BlockT, DigestFor, Zero};
NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi
};
use fg_primitives::{GrandpaApi, AuthorityPair};
use keystore::KeyStorePtr; use keystore::KeyStorePtr;
use inherents::InherentDataProviders; use inherents::InherentDataProviders;
use consensus_common::SelectChain; use consensus_common::SelectChain;
@@ -108,7 +106,7 @@ use environment::{Environment, VoterSetState};
use import::GrandpaBlockImport; use import::GrandpaBlockImport;
use until_imported::UntilGlobalMessageBlocksImported; use until_imported::UntilGlobalMessageBlocksImported;
use communication::NetworkBridge; use communication::NetworkBridge;
use fg_primitives::{AuthoritySignature, SetId, AuthorityWeight}; use fg_primitives::{AuthorityList, AuthorityPair, AuthoritySignature, SetId};
// Re-export these two because it's just so damn convenient. // Re-export these two because it's just so damn convenient.
pub use fg_primitives::{AuthorityId, ScheduledChange}; pub use fg_primitives::{AuthorityId, ScheduledChange};
@@ -295,7 +293,7 @@ pub(crate) struct NewAuthoritySet<H, N> {
pub(crate) canon_number: N, pub(crate) canon_number: N,
pub(crate) canon_hash: H, pub(crate) canon_hash: H,
pub(crate) set_id: SetId, pub(crate) set_id: SetId,
pub(crate) authorities: Vec<(AuthorityId, AuthorityWeight)>, pub(crate) authorities: AuthorityList,
} }
/// Commands issued to the voter. /// Commands issued to the voter.
@@ -367,11 +365,44 @@ pub struct LinkHalf<B, E, Block: BlockT<Hash=H256>, RA, SC> {
voter_commands_rx: mpsc::UnboundedReceiver<VoterCommand<Block::Hash, NumberFor<Block>>>, voter_commands_rx: mpsc::UnboundedReceiver<VoterCommand<Block::Hash, NumberFor<Block>>>,
} }
/// Provider for the Grandpa authority set configured on the genesis block.
pub trait GenesisAuthoritySetProvider<Block: BlockT> {
/// Get the authority set at the genesis block.
fn get(&self) -> Result<AuthorityList, ClientError>;
}
impl<B, E, Block: BlockT<Hash=H256>, RA> GenesisAuthoritySetProvider<Block> for Client<B, E, Block, RA>
where
B: Backend<Block, Blake2Hasher> + Send + Sync + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: Send + Sync,
{
fn get(&self) -> Result<AuthorityList, ClientError> {
// This implementation uses the Grandpa runtime API instead of reading directly from the
// `GRANDPA_AUTHORITIES_KEY` as the data may have been migrated since the genesis block of
// the chain, whereas the runtime API is backwards compatible.
self.executor()
.call(
&BlockId::Number(Zero::zero()),
"GrandpaApi_grandpa_authorities",
&[],
ExecutionStrategy::NativeElseWasm,
None,
)
.and_then(|call_result| {
Decode::decode(&mut &call_result[..])
.map_err(|err| ClientError::CallResultDecode(
"failed to decode GRANDPA authorities set proof".into(), err
))
})
}
}
/// Make block importer and link half necessary to tie the background voter /// Make block importer and link half necessary to tie the background voter
/// to it. /// to it.
pub fn block_import<B, E, Block: BlockT<Hash=H256>, RA, PRA, SC>( pub fn block_import<B, E, Block: BlockT<Hash=H256>, RA, SC>(
client: Arc<Client<B, E, Block, RA>>, client: Arc<Client<B, E, Block, RA>>,
api: &PRA, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
select_chain: SC, select_chain: SC,
) -> Result<( ) -> Result<(
GrandpaBlockImport<B, E, Block, RA, SC>, GrandpaBlockImport<B, E, Block, RA, SC>,
@@ -381,12 +412,8 @@ where
B: Backend<Block, Blake2Hasher> + 'static, B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync, E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: Send + Sync, RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
SC: SelectChain<Block>, SC: SelectChain<Block>,
{ {
use sr_primitives::traits::Zero;
let chain_info = client.info(); let chain_info = client.info();
let genesis_hash = chain_info.chain.genesis_hash; let genesis_hash = chain_info.chain.genesis_hash;
@@ -395,12 +422,11 @@ where
genesis_hash, genesis_hash,
<NumberFor<Block>>::zero(), <NumberFor<Block>>::zero(),
|| { || {
let genesis_authorities = api.runtime_api() let authorities = genesis_authorities_provider.get()?;
.grandpa_authorities(&BlockId::number(Zero::zero()))?;
telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities"; telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities";
"authorities_len" => ?genesis_authorities.len() "authorities_len" => ?authorities.len()
); );
Ok(genesis_authorities) Ok(authorities)
} }
)?; )?;
@@ -34,17 +34,18 @@ use consensus_common::{
}; };
use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder}; use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder};
use sr_primitives::Justification; use sr_primitives::Justification;
use sr_primitives::traits::{ use sr_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT, DigestFor};
NumberFor, Block as BlockT, Header as HeaderT, ProvideRuntimeApi, DigestFor, use fg_primitives::{self, AuthorityList};
};
use fg_primitives::{self, GrandpaApi, AuthorityId};
use sr_primitives::generic::BlockId; use sr_primitives::generic::BlockId;
use primitives::{H256, Blake2Hasher}; use primitives::{H256, Blake2Hasher};
use crate::GenesisAuthoritySetProvider;
use crate::aux_schema::load_decode; use crate::aux_schema::load_decode;
use crate::consensus_changes::ConsensusChanges; use crate::consensus_changes::ConsensusChanges;
use crate::environment::canonical_at_height; use crate::environment::canonical_at_height;
use crate::finality_proof::{AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request}; use crate::finality_proof::{
AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request,
};
use crate::justification::GrandpaJustification; use crate::justification::GrandpaJustification;
/// LightAuthoritySet is saved under this key in aux storage. /// LightAuthoritySet is saved under this key in aux storage.
@@ -53,21 +54,23 @@ const LIGHT_AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters";
const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes";
/// Create light block importer. /// Create light block importer.
pub fn light_block_import<B, E, Block: BlockT<Hash=H256>, RA, PRA>( pub fn light_block_import<B, E, Block: BlockT<Hash=H256>, RA>(
client: Arc<Client<B, E, Block, RA>>, client: Arc<Client<B, E, Block, RA>>,
backend: Arc<B>, backend: Arc<B>,
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>, authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>,
api: Arc<PRA>,
) -> Result<GrandpaLightBlockImport<B, E, Block, RA>, ClientError> ) -> Result<GrandpaLightBlockImport<B, E, Block, RA>, ClientError>
where where
B: Backend<Block, Blake2Hasher> + 'static, B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync, E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: Send + Sync, RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
{ {
let info = client.info(); let info = client.info();
let import_data = load_aux_import_data(info.chain.finalized_hash, &*client, api)?; let import_data = load_aux_import_data(
info.chain.finalized_hash,
&*client,
genesis_authorities_provider,
)?;
Ok(GrandpaLightBlockImport { Ok(GrandpaLightBlockImport {
client, client,
backend, backend,
@@ -110,7 +113,7 @@ struct LightImportData<Block: BlockT<Hash=H256>> {
#[derive(Debug, Encode, Decode)] #[derive(Debug, Encode, Decode)]
struct LightAuthoritySet { struct LightAuthoritySet {
set_id: u64, set_id: u64,
authorities: Vec<(AuthorityId, u64)>, authorities: AuthorityList,
} }
impl<B, E, Block: BlockT<Hash=H256>, RA> GrandpaLightBlockImport<B, E, Block, RA> { impl<B, E, Block: BlockT<Hash=H256>, RA> GrandpaLightBlockImport<B, E, Block, RA> {
@@ -194,7 +197,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> FinalityProofImport<Block>
impl LightAuthoritySet { impl LightAuthoritySet {
/// Get a genesis set with given authorities. /// Get a genesis set with given authorities.
pub fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { pub fn genesis(initial: AuthorityList) -> Self {
LightAuthoritySet { LightAuthoritySet {
set_id: fg_primitives::SetId::default(), set_id: fg_primitives::SetId::default(),
authorities: initial, authorities: initial,
@@ -207,12 +210,12 @@ impl LightAuthoritySet {
} }
/// Get latest authorities set. /// Get latest authorities set.
pub fn authorities(&self) -> Vec<(AuthorityId, u64)> { pub fn authorities(&self) -> AuthorityList {
self.authorities.clone() self.authorities.clone()
} }
/// Set new authorities set. /// Set new authorities set.
pub fn update(&mut self, set_id: u64, authorities: Vec<(AuthorityId, u64)>) { pub fn update(&mut self, set_id: u64, authorities: AuthorityList) {
self.set_id = set_id; self.set_id = set_id;
std::mem::replace(&mut self.authorities, authorities); std::mem::replace(&mut self.authorities, authorities);
} }
@@ -472,17 +475,14 @@ fn do_finalize_block<B, C, Block: BlockT<Hash=H256>>(
} }
/// Load light import aux data from the store. /// Load light import aux data from the store.
fn load_aux_import_data<B, Block: BlockT<Hash=H256>, PRA>( fn load_aux_import_data<B, Block: BlockT<Hash=H256>>(
last_finalized: Block::Hash, last_finalized: Block::Hash,
aux_store: &B, aux_store: &B,
api: Arc<PRA>, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
) -> Result<LightImportData<Block>, ClientError> ) -> Result<LightImportData<Block>, ClientError>
where where
B: AuxStore, B: AuxStore,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
{ {
use sr_primitives::traits::Zero;
let authority_set = match load_decode(aux_store, LIGHT_AUTHORITY_SET_KEY)? { let authority_set = match load_decode(aux_store, LIGHT_AUTHORITY_SET_KEY)? {
Some(authority_set) => authority_set, Some(authority_set) => authority_set,
None => { None => {
@@ -490,7 +490,7 @@ fn load_aux_import_data<B, Block: BlockT<Hash=H256>, PRA>(
from genesis on what appears to be first startup."); from genesis on what appears to be first startup.");
// no authority set on disk: fetch authorities from genesis state // no authority set on disk: fetch authorities from genesis state
let genesis_authorities = api.runtime_api().grandpa_authorities(&BlockId::number(Zero::zero()))?; let genesis_authorities = genesis_authorities_provider.get()?;
let authority_set = LightAuthoritySet::genesis(genesis_authorities); let authority_set = LightAuthoritySet::genesis(genesis_authorities);
let encoded = authority_set.encode(); let encoded = authority_set.encode();
@@ -546,6 +546,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus
pub mod tests { pub mod tests {
use super::*; use super::*;
use consensus_common::ForkChoiceStrategy; use consensus_common::ForkChoiceStrategy;
use fg_primitives::AuthorityId;
use primitives::{H256, crypto::Public}; use primitives::{H256, crypto::Public};
use test_client::client::in_mem::Blockchain as InMemoryAuxStore; use test_client::client::in_mem::Blockchain as InMemoryAuxStore;
use test_client::runtime::{Block, Header}; use test_client::runtime::{Block, Header};
@@ -622,20 +623,19 @@ pub mod tests {
} }
/// Creates light block import that ignores justifications that came outside of finality proofs. /// Creates light block import that ignores justifications that came outside of finality proofs.
pub fn light_block_import_without_justifications<B, E, Block: BlockT<Hash=H256>, RA, PRA>( pub fn light_block_import_without_justifications<B, E, Block: BlockT<Hash=H256>, RA>(
client: Arc<Client<B, E, Block, RA>>, client: Arc<Client<B, E, Block, RA>>,
backend: Arc<B>, backend: Arc<B>,
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>, authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>,
api: Arc<PRA>,
) -> Result<NoJustificationsImport<B, E, Block, RA>, ClientError> ) -> Result<NoJustificationsImport<B, E, Block, RA>, ClientError>
where where
B: Backend<Block, Blake2Hasher> + 'static, B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync, E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: Send + Sync, RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
{ {
light_block_import(client, backend, authority_set_provider, api).map(NoJustificationsImport) light_block_import(client, backend, genesis_authorities_provider, authority_set_provider)
.map(NoJustificationsImport)
} }
fn import_block( fn import_block(
@@ -729,14 +729,14 @@ pub mod tests {
#[test] #[test]
fn aux_data_updated_on_start() { fn aux_data_updated_on_start() {
let aux_store = InMemoryAuxStore::<Block>::new(); let aux_store = InMemoryAuxStore::<Block>::new();
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]);
// when aux store is empty initially // when aux store is empty initially
assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none()); assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none());
assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_none()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_none());
// it is updated on importer start // it is updated on importer start
load_aux_import_data(Default::default(), &aux_store, api).unwrap(); load_aux_import_data(Default::default(), &aux_store, &api).unwrap();
assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_some()); assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_some());
assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_some()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_some());
} }
@@ -744,7 +744,7 @@ pub mod tests {
#[test] #[test]
fn aux_data_loaded_on_restart() { fn aux_data_loaded_on_restart() {
let aux_store = InMemoryAuxStore::<Block>::new(); let aux_store = InMemoryAuxStore::<Block>::new();
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]);
// when aux store is non-empty initially // when aux store is non-empty initially
let mut consensus_changes = ConsensusChanges::<H256, u64>::empty(); let mut consensus_changes = ConsensusChanges::<H256, u64>::empty();
@@ -766,7 +766,7 @@ pub mod tests {
).unwrap(); ).unwrap();
// importer uses it on start // importer uses it on start
let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap(); let data = load_aux_import_data(Default::default(), &aux_store, &api).unwrap();
assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[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())]); assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]);
} }
+15 -14
View File
@@ -39,7 +39,7 @@ use codec::Decode;
use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT};
use sr_primitives::generic::{BlockId, DigestItem}; use sr_primitives::generic::{BlockId, DigestItem};
use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public};
use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId}; use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityList, GrandpaApi};
use state_machine::{backend::InMemory, prove_read, read_proof_check}; use state_machine::{backend::InMemory, prove_read, read_proof_check};
use authorities::AuthoritySet; use authorities::AuthoritySet;
@@ -137,8 +137,8 @@ impl TestNetFactory for GrandpaTestNet {
let import = light_block_import_without_justifications( let import = light_block_import_without_justifications(
client.clone(), client.clone(),
backend.clone(), backend.clone(),
&self.test_config,
authorities_provider, authorities_provider,
Arc::new(self.test_config.clone())
).expect("Could not create block import for fresh peer."); ).expect("Could not create block import for fresh peer.");
let finality_proof_req_builder = import.0.create_finality_proof_request_builder(); let finality_proof_req_builder = import.0.create_finality_proof_request_builder();
let proof_import = Box::new(import.clone()); let proof_import = Box::new(import.clone());
@@ -188,11 +188,11 @@ impl Future for Exit {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub(crate) struct TestApi { pub(crate) struct TestApi {
genesis_authorities: Vec<(AuthorityId, u64)>, genesis_authorities: AuthorityList,
} }
impl TestApi { impl TestApi {
pub fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self { pub fn new(genesis_authorities: AuthorityList) -> Self {
TestApi { TestApi {
genesis_authorities, genesis_authorities,
} }
@@ -271,19 +271,20 @@ impl GrandpaApi<Block> for RuntimeApi {
_: ExecutionContext, _: ExecutionContext,
_: Option<()>, _: Option<()>,
_: Vec<u8>, _: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<(AuthorityId, u64)>>> { ) -> Result<NativeOrEncoded<AuthorityList>> {
Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native) Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
} }
} }
impl GenesisAuthoritySetProvider<Block> for TestApi {
fn get(&self) -> Result<AuthorityList> {
Ok(self.genesis_authorities.clone())
}
}
impl AuthoritySetForFinalityProver<Block> for TestApi { impl AuthoritySetForFinalityProver<Block> for TestApi {
fn authorities(&self, block: &BlockId<Block>) -> Result<Vec<(AuthorityId, u64)>> { fn authorities(&self, _block: &BlockId<Block>) -> Result<AuthorityList> {
let runtime_api = RuntimeApi { inner: self.clone() }; Ok(self.genesis_authorities.clone())
runtime_api.GrandpaApi_grandpa_authorities_runtime_api_impl(block, ExecutionContext::Syncing, None, Vec::new())
.map(|v| match v {
NativeOrEncoded::Native(value) => value,
_ => unreachable!("only providing native values"),
})
} }
fn prove_authorities(&self, block: &BlockId<Block>) -> Result<StorageProof> { fn prove_authorities(&self, block: &BlockId<Block>) -> Result<StorageProof> {
@@ -303,7 +304,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
_hash: <Block as BlockT>::Hash, _hash: <Block as BlockT>::Hash,
header: <Block as BlockT>::Header, header: <Block as BlockT>::Header,
proof: StorageProof, proof: StorageProof,
) -> Result<Vec<(AuthorityId, u64)>> { ) -> Result<AuthorityList> {
let results = read_proof_check::<Blake2Hasher, _>( let results = read_proof_check::<Blake2Hasher, _>(
*header.state_root(), proof, vec![b"authorities"] *header.state_root(), proof, vec![b"authorities"]
) )
@@ -320,7 +321,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect()
} }
+2 -2
View File
@@ -23,7 +23,7 @@ use client::{
runtime_api as client_api, impl_runtime_apis runtime_api as client_api, impl_runtime_apis
}; };
use aura_primitives::sr25519::AuthorityId as AuraId; use aura_primitives::sr25519::AuthorityId as AuraId;
use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use grandpa::AuthorityList as GrandpaAuthorityList;
use grandpa::fg_primitives; use grandpa::fg_primitives;
use version::RuntimeVersion; use version::RuntimeVersion;
#[cfg(feature = "std")] #[cfg(feature = "std")]
@@ -355,7 +355,7 @@ impl_runtime_apis! {
} }
impl fg_primitives::GrandpaApi<Block> for Runtime { impl fg_primitives::GrandpaApi<Block> for Runtime {
fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities() Grandpa::grandpa_authorities()
} }
} }
+3 -3
View File
@@ -48,7 +48,7 @@ macro_rules! new_full_start {
.ok_or_else(|| substrate_service::Error::SelectChainRequired)?; .ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
let (grandpa_block_import, grandpa_link) = let (grandpa_block_import, grandpa_link) =
grandpa::block_import::<_, _, _, runtime::RuntimeApi, _, _>( grandpa::block_import::<_, _, _, runtime::RuntimeApi, _>(
client.clone(), &*client, select_chain client.clone(), &*client, select_chain
)?; )?;
@@ -197,8 +197,8 @@ pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisCo
let fetch_checker = fetcher let fetch_checker = fetcher
.map(|fetcher| fetcher.checker().clone()) .map(|fetcher| fetcher.checker().clone())
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?; .ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
client.clone(), backend, Arc::new(fetch_checker), client.clone() client.clone(), backend, &*client.clone(), Arc::new(fetch_checker),
)?; )?;
let finality_proof_import = grandpa_block_import.clone(); let finality_proof_import = grandpa_block_import.clone();
let finality_proof_request_builder = let finality_proof_request_builder =
+10 -6
View File
@@ -69,10 +69,11 @@ macro_rules! new_full_start {
.with_import_queue(|_config, client, mut select_chain, _transaction_pool| { .with_import_queue(|_config, client, mut select_chain, _transaction_pool| {
let select_chain = select_chain.take() let select_chain = select_chain.take()
.ok_or_else(|| substrate_service::Error::SelectChainRequired)?; .ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
let (grandpa_block_import, grandpa_link) = let (grandpa_block_import, grandpa_link) = grandpa::block_import(
grandpa::block_import::<_, _, _, node_runtime::RuntimeApi, _, _>( client.clone(),
client.clone(), &*client, select_chain &*client,
)?; select_chain,
)?;
let justification_import = grandpa_block_import.clone(); let justification_import = grandpa_block_import.clone();
let (block_import, babe_link) = babe::block_import( let (block_import, babe_link) = babe::block_import(
@@ -291,8 +292,11 @@ pub fn new_light<C: Send + Default + 'static>(config: NodeConfiguration<C>)
let fetch_checker = fetcher let fetch_checker = fetcher
.map(|fetcher| fetcher.checker().clone()) .map(|fetcher| fetcher.checker().clone())
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?; .ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
client.clone(), backend, Arc::new(fetch_checker), client.clone() client.clone(),
backend,
&*client,
Arc::new(fetch_checker),
)?; )?;
let finality_proof_import = grandpa_block_import.clone(); let finality_proof_import = grandpa_block_import.clone();
+5 -5
View File
@@ -29,7 +29,6 @@ use node_primitives::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
Moment, Signature, Moment, Signature,
}; };
use grandpa::fg_primitives;
use client::{ use client::{
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
runtime_api as client_api, impl_runtime_apis runtime_api as client_api, impl_runtime_apis
@@ -46,7 +45,8 @@ use version::RuntimeVersion;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
use version::NativeVersion; use version::NativeVersion;
use primitives::OpaqueMetadata; use primitives::OpaqueMetadata;
use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use grandpa::AuthorityList as GrandpaAuthorityList;
use grandpa::fg_primitives;
use im_online::sr25519::{AuthorityId as ImOnlineId}; use im_online::sr25519::{AuthorityId as ImOnlineId};
use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
use contracts_rpc_runtime_api::ContractExecResult; use contracts_rpc_runtime_api::ContractExecResult;
@@ -81,8 +81,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to equal spec_version. If only runtime // and set impl_version to equal spec_version. If only runtime
// implementation changes and behavior does not, then leave spec_version as // implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version. // is and increment impl_version.
spec_version: 192, spec_version: 193,
impl_version: 191, impl_version: 193,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
@@ -617,7 +617,7 @@ impl_runtime_apis! {
} }
impl fg_primitives::GrandpaApi<Block> for Runtime { impl fg_primitives::GrandpaApi<Block> for Runtime {
fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities() Grandpa::grandpa_authorities()
} }
} }
+1
View File
@@ -35,3 +35,4 @@ std = [
"session/std", "session/std",
"finality-tracker/std", "finality-tracker/std",
] ]
migrate-authorities = []
+45 -18
View File
@@ -32,9 +32,7 @@ pub use substrate_finality_grandpa_primitives as fg_primitives;
use rstd::prelude::*; use rstd::prelude::*;
use codec::{self as codec, Encode, Decode, Error}; use codec::{self as codec, Encode, Decode, Error};
use support::{ use support::{decl_event, decl_storage, decl_module, dispatch::Result, storage};
decl_event, decl_storage, decl_module, dispatch::Result,
};
use sr_primitives::{ use sr_primitives::{
generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill, generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill,
}; };
@@ -42,8 +40,10 @@ use sr_staking_primitives::{
SessionIndex, SessionIndex,
offence::{Offence, Kind}, offence::{Offence, Kind},
}; };
use fg_primitives::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber}; use fg_primitives::{
pub use fg_primitives::{AuthorityId, AuthorityWeight}; GRANDPA_AUTHORITIES_KEY, GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber,
};
pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList};
use system::{ensure_signed, DigestOf}; use system::{ensure_signed, DigestOf};
mod mock; mod mock;
@@ -64,7 +64,7 @@ pub struct OldStoredPendingChange<N> {
/// The delay in blocks until it will be applied. /// The delay in blocks until it will be applied.
pub delay: N, pub delay: N,
/// The next authority set. /// The next authority set.
pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, pub next_authorities: AuthorityList,
} }
/// A stored pending change. /// A stored pending change.
@@ -75,7 +75,7 @@ pub struct StoredPendingChange<N> {
/// The delay in blocks until it will be applied. /// The delay in blocks until it will be applied.
pub delay: N, pub delay: N,
/// The next authority set. /// The next authority set.
pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, pub next_authorities: AuthorityList,
/// If defined it means the change was forced and the given block number /// If defined it means the change was forced and the given block number
/// indicates the median last finalized block when the change was signaled. /// indicates the median last finalized block when the change was signaled.
pub forced: Option<N>, pub forced: Option<N>,
@@ -126,7 +126,7 @@ pub enum StoredState<N> {
decl_event!( decl_event!(
pub enum Event { pub enum Event {
/// New authority set has been applied. /// New authority set has been applied.
NewAuthorities(Vec<(AuthorityId, AuthorityWeight)>), NewAuthorities(AuthorityList),
/// Current authority set has been paused. /// Current authority set has been paused.
Paused, Paused,
/// Current authority set has been resumed. /// Current authority set has been resumed.
@@ -136,8 +136,12 @@ decl_event!(
decl_storage! { decl_storage! {
trait Store for Module<T: Trait> as GrandpaFinality { trait Store for Module<T: Trait> as GrandpaFinality {
/// The current authority set. /// DEPRECATED
Authorities get(fn authorities): Vec<(AuthorityId, AuthorityWeight)>; ///
/// This used to store the current authority set, which has been migrated to the well-known
/// GRANDPA_AUTHORITES_KEY unhashed key.
#[cfg(feature = "migrate-authorities")]
pub(crate) Authorities get(fn authorities): AuthorityList;
/// State of the current authority set. /// State of the current authority set.
State get(fn state): StoredState<T::BlockNumber> = StoredState::Live; State get(fn state): StoredState<T::BlockNumber> = StoredState::Live;
@@ -159,7 +163,7 @@ decl_storage! {
SetIdSession get(fn session_for_set): map SetId => Option<SessionIndex>; SetIdSession get(fn session_for_set): map SetId => Option<SessionIndex>;
} }
add_extra_genesis { add_extra_genesis {
config(authorities): Vec<(AuthorityId, AuthorityWeight)>; config(authorities): AuthorityList;
build(|config| Module::<T>::initialize_authorities(&config.authorities)) build(|config| Module::<T>::initialize_authorities(&config.authorities))
} }
} }
@@ -174,6 +178,11 @@ decl_module! {
// FIXME: https://github.com/paritytech/substrate/issues/1112 // FIXME: https://github.com/paritytech/substrate/issues/1112
} }
fn on_initialize() {
#[cfg(feature = "migrate-authorities")]
Self::migrate_authorities();
}
fn on_finalize(block_number: T::BlockNumber) { fn on_finalize(block_number: T::BlockNumber) {
// check for scheduled pending authority set changes // check for scheduled pending authority set changes
if let Some(pending_change) = <PendingChange<T>>::get() { if let Some(pending_change) = <PendingChange<T>>::get() {
@@ -199,7 +208,7 @@ decl_module! {
// enact the change if we've reached the enacting block // enact the change if we've reached the enacting block
if block_number == pending_change.scheduled_at + pending_change.delay { if block_number == pending_change.scheduled_at + pending_change.delay {
Authorities::put(&pending_change.next_authorities); Self::set_grandpa_authorities(&pending_change.next_authorities);
Self::deposit_event( Self::deposit_event(
Event::NewAuthorities(pending_change.next_authorities) Event::NewAuthorities(pending_change.next_authorities)
); );
@@ -241,8 +250,16 @@ decl_module! {
impl<T: Trait> Module<T> { impl<T: Trait> Module<T> {
/// Get the current set of authorities, along with their respective weights. /// Get the current set of authorities, along with their respective weights.
pub fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)> { pub fn grandpa_authorities() -> AuthorityList {
Authorities::get() 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,
&VersionedAuthorityList::from(authorities),
);
} }
/// Schedule GRANDPA to pause starting in the given number of blocks. /// Schedule GRANDPA to pause starting in the given number of blocks.
@@ -293,7 +310,7 @@ impl<T: Trait> Module<T> {
/// No change should be signaled while any change is pending. Returns /// No change should be signaled while any change is pending. Returns
/// an error if a change is already pending. /// an error if a change is already pending.
pub fn schedule_change( pub fn schedule_change(
next_authorities: Vec<(AuthorityId, AuthorityWeight)>, next_authorities: AuthorityList,
in_blocks: T::BlockNumber, in_blocks: T::BlockNumber,
forced: Option<T::BlockNumber>, forced: Option<T::BlockNumber>,
) -> Result { ) -> Result {
@@ -329,10 +346,20 @@ impl<T: Trait> Module<T> {
<system::Module<T>>::deposit_log(log.into()); <system::Module<T>>::deposit_log(log.into());
} }
fn initialize_authorities(authorities: &[(AuthorityId, AuthorityWeight)]) { fn initialize_authorities(authorities: &AuthorityList) {
if !authorities.is_empty() { if !authorities.is_empty() {
assert!(Authorities::get().is_empty(), "Authorities are already initialized!"); assert!(
Authorities::put(authorities); Self::grandpa_authorities().is_empty(),
"Authorities are already initialized!"
);
Self::set_grandpa_authorities(authorities);
}
}
#[cfg(feature = "migrate-authorities")]
fn migrate_authorities() {
if Authorities::exists() {
Self::set_grandpa_authorities(&Authorities::take());
} }
} }
} }
+2 -2
View File
@@ -23,7 +23,7 @@ use runtime_io;
use support::{impl_outer_origin, impl_outer_event, parameter_types}; use support::{impl_outer_origin, impl_outer_event, parameter_types};
use primitives::H256; use primitives::H256;
use codec::{Encode, Decode}; use codec::{Encode, Decode};
use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; use crate::{AuthorityId, AuthorityList, GenesisConfig, Trait, Module, ConsensusLog};
use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID;
impl_outer_origin!{ impl_outer_origin!{
@@ -75,7 +75,7 @@ impl_outer_event!{
} }
} }
pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { pub fn to_authorities(vec: Vec<(u64, u64)>) -> AuthorityList {
vec.into_iter() vec.into_iter()
.map(|(id, weight)| (UintAuthorityId(id).to_public_key::<AuthorityId>(), weight)) .map(|(id, weight)| (UintAuthorityId(id).to_public_key::<AuthorityId>(), weight))
.collect() .collect()
+18
View File
@@ -308,3 +308,21 @@ fn time_slot_have_sane_ord() {
]; ];
assert!(FIXTURE.windows(2).all(|f| f[0] < f[1])); assert!(FIXTURE.windows(2).all(|f| f[0] < f[1]));
} }
#[test]
#[cfg(feature = "migrate-authorities")]
fn authorities_migration() {
use sr_primitives::traits::OnInitialize;
with_externalities(&mut new_test_ext(vec![]), || {
let authorities = to_authorities(vec![(1, 1), (2, 1), (3, 1)]);
Authorities::put(authorities.clone());
assert!(Grandpa::grandpa_authorities().is_empty());
Grandpa::on_initialize(1);
assert!(!Authorities::exists());
assert_eq!(Grandpa::grandpa_authorities(), authorities);
});
}