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
beefy: add support to configure BEEFY genesis
  • Loading branch information
acatangiu committed Jan 23, 2023
commit e07af4e240e5e0a8b4a4ad32e34202b7541b37ea
34 changes: 21 additions & 13 deletions client/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use sp_keystore::SyncCryptoStorePtr;
use sp_mmr_primitives::MmrApi;
use sp_runtime::{
generic::BlockId,
traits::{Block, One, Zero},
traits::{Block, Zero},
};
use std::{collections::VecDeque, marker::PhantomData, sync::Arc};

Expand Down Expand Up @@ -344,6 +344,12 @@ where
R: ProvideRuntimeApi<B>,
R::Api: BeefyApi<B>,
{
let beefy_genesis = runtime
.runtime_api()
.beefy_genesis(&BlockId::hash(best_grandpa.hash()))
.ok()
.flatten()
.ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into()))?;
// Walk back the imported blocks and initialize voter either, at the last block with
// a BEEFY justification, or at pallet genesis block; voter will resume from there.
let blockchain = backend.blockchain();
Expand Down Expand Up @@ -376,19 +382,18 @@ where
break state
}

if *header.number() == One::one() {
// We've reached chain genesis, initialize voter here.
let genesis_num = *header.number();
if *header.number() == beefy_genesis {
// We've reached BEEFY genesis, initialize voter here.
let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash()))
.and_then(genesis_set_sanity_check)?;
info!(
target: "beefy",
"🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \
Starting voting rounds at block {:?}, genesis validator set {:?}.",
genesis_num, genesis_set,
beefy_genesis, genesis_set,
);

sessions.push_front(Rounds::new(genesis_num, genesis_set));
sessions.push_front(Rounds::new(beefy_genesis, genesis_set));
break PersistedState::checked_new(best_grandpa, Zero::zero(), sessions, min_block_delta)
.ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))?
}
Expand Down Expand Up @@ -441,13 +446,16 @@ where
None => break
};
let at = BlockId::hash(notif.header.hash());
if let Some(active) = runtime.runtime_api().validator_set(&at).ok().flatten() {
// Beefy pallet available, return best grandpa at the time.
info!(
target: "beefy", "🥩 BEEFY pallet available: block {:?} validator set {:?}",
notif.header.number(), active
);
return Ok(notif.header)
if let Some(start) = runtime.runtime_api().beefy_genesis(&at).ok().flatten() {
if *notif.header.number() >= start {
// Beefy pallet available, return header for best grandpa at the time.
info!(
target: "beefy",
"🥩 BEEFY pallet available: block {:?} beefy genesis {:?}",
notif.header.number(), start
);
return Ok(notif.header)
}
}
},
_ = gossip_engine => {
Expand Down
4 changes: 4 additions & 0 deletions client/beefy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ macro_rules! create_test_api {
}
sp_api::mock_impl_runtime_apis! {
impl BeefyApi<Block> for RuntimeApi {
fn beefy_genesis() -> Option<NumberFor<Block>> {
Some(sp_runtime::traits::One::one())
}

fn validator_set() -> Option<BeefyValidatorSet> {
BeefyValidatorSet::new(make_beefy_ids(&[$($inits),+]), 0)
}
Expand Down
16 changes: 15 additions & 1 deletion frame/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub use pallet::*;
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::BlockNumberFor;

#[pallet::config]
pub trait Config: frame_system::Config {
Expand Down Expand Up @@ -91,15 +92,27 @@ pub mod pallet {
pub(super) type NextAuthorities<T: Config> =
StorageValue<_, BoundedVec<T::BeefyId, T::MaxAuthorities>, ValueQuery>;

/// Block number where BEEFY consensus is enabled/started
#[pallet::storage]
#[pallet::getter(fn genesis_block)]
pub(super) type GenesisBlock<T: Config> =
StorageValue<_, Option<BlockNumberFor<T>>, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// Initial set of BEEFY authorities.
pub authorities: Vec<T::BeefyId>,
/// Block number where BEEFY consensus should start.
/// Should match the session where initial authorities are active.
/// *Note:* Ideally use block number where GRANDPA authorities are changed,
/// to guarantee the client gets a finality notification for exactly this block.
pub genesis_block: Option<BlockNumberFor<T>>,
}

#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self { authorities: Vec::new() }
Self { authorities: Vec::new(), genesis_block: None }
}
}

Expand All @@ -110,6 +123,7 @@ pub mod pallet {
// we panic here as runtime maintainers can simply reconfigure genesis and restart
// the chain easily
.expect("Authorities vec too big");
<GenesisBlock<T>>::put(&self.genesis_block);
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion primitives/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use codec::{Codec, Decode, Encode};
use scale_info::TypeInfo;
use sp_application_crypto::RuntimeAppPublic;
use sp_core::H256;
use sp_runtime::traits::Hash;
use sp_runtime::traits::{Hash, NumberFor};
use sp_std::prelude::*;

/// Key type for BEEFY module.
Expand Down Expand Up @@ -201,6 +201,9 @@ sp_api::decl_runtime_apis! {
/// API necessary for BEEFY voters.
pub trait BeefyApi
{
/// Return the block number where BEEFY consensus is enabled/started
fn beefy_genesis() -> Option<NumberFor<Block>>;

/// Return the current active BEEFY validator set
fn validator_set() -> Option<ValidatorSet<crypto::AuthorityId>>;
}
Expand Down
4 changes: 4 additions & 0 deletions test-utils/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,10 @@ cfg_if! {
}

impl beefy_primitives::BeefyApi<Block> for Runtime {
fn beefy_genesis() -> Option<BlockNumber> {
None
}

fn validator_set() -> Option<beefy_primitives::ValidatorSet<beefy_primitives::crypto::AuthorityId>> {
None
}
Expand Down