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

grandpa: support for hard forking any pending standard changes #5306

Merged
merged 3 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
54 changes: 50 additions & 4 deletions client/finality-grandpa/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use sp_consensus::{
BlockCheckParams, BlockImportParams, ImportResult, JustificationImport,
SelectChain,
};
use sp_finality_grandpa::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog};
use sp_finality_grandpa::{ConsensusLog, ScheduledChange, SetId, GRANDPA_ENGINE_ID};
use sp_runtime::Justification;
use sp_runtime::generic::{BlockId, OpaqueDigestItemId};
use sp_runtime::traits::{
Expand Down Expand Up @@ -59,6 +59,7 @@ pub struct GrandpaBlockImport<Backend, Block: BlockT, Client, SC> {
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
send_voter_commands: mpsc::UnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
consensus_changes: SharedConsensusChanges<Block::Hash, NumberFor<Block>>,
authority_set_hard_forks: HashMap<Block::Hash, PendingChange<Block::Hash, NumberFor<Block>>>,
_phantom: PhantomData<Backend>,
}

Expand All @@ -72,6 +73,7 @@ impl<Backend, Block: BlockT, Client, SC: Clone> Clone for
authority_set: self.authority_set.clone(),
send_voter_commands: self.send_voter_commands.clone(),
consensus_changes: self.consensus_changes.clone(),
authority_set_hard_forks: self.authority_set_hard_forks.clone(),
_phantom: PhantomData,
}
}
Expand Down Expand Up @@ -212,9 +214,16 @@ where
Client: crate::ClientForGrandpa<Block, BE>,
{
// check for a new authority set change.
fn check_new_change(&self, header: &Block::Header, hash: Block::Hash)
-> Option<PendingChange<Block::Hash, NumberFor<Block>>>
{
fn check_new_change(
&self,
header: &Block::Header,
hash: Block::Hash,
) -> Option<PendingChange<Block::Hash, NumberFor<Block>>> {
// check for forced authority set hard forks
if let Some(change) = self.authority_set_hard_forks.get(&hash) {
return Some(change.clone());
}

// check for forced change.
if let Some((median_last_finalized, change)) = find_forced_change::<Block>(header) {
return Some(PendingChange {
Expand Down Expand Up @@ -529,13 +538,50 @@ impl<Backend, Block: BlockT, Client, SC> GrandpaBlockImport<Backend, Block, Clie
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
send_voter_commands: mpsc::UnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
consensus_changes: SharedConsensusChanges<Block::Hash, NumberFor<Block>>,
authority_set_hard_forks: Vec<(SetId, PendingChange<Block::Hash, NumberFor<Block>>)>,
) -> GrandpaBlockImport<Backend, Block, Client, SC> {
// check for and apply any forced authority set hard fork that applies
// to the *current* authority set.
if let Some((_, change)) = authority_set_hard_forks
.iter()
.find(|(set_id, _)| *set_id == authority_set.set_id())
{
let mut authority_set = authority_set.inner().write();
authority_set.current_authorities = change.next_authorities.clone();
}

// index authority set hard forks by block hash so that they can be used
// by any node syncing the chain and importing a block hard fork
// authority set changes.
let authority_set_hard_forks = authority_set_hard_forks
.into_iter()
.map(|(_, change)| (change.canon_hash, change))
.collect::<HashMap<_, _>>();

// check for and apply any forced authority set hard fork that apply to
// any *pending* standard changes, checking by the block hash at which
// they were announced.
{
let mut authority_set = authority_set.inner().write();

authority_set.pending_standard_changes = authority_set
.pending_standard_changes
.clone()
.map(&mut |hash, _, original| {
authority_set_hard_forks
.get(&hash)
.cloned()
.unwrap_or(original)
});
}

GrandpaBlockImport {
inner,
select_chain,
authority_set,
send_voter_commands,
consensus_changes,
authority_set_hard_forks,
_phantom: PhantomData,
}
}
Expand Down
56 changes: 54 additions & 2 deletions client/finality-grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,43 @@ pub fn block_import<BE, Block: BlockT, Client, SC>(
client: Arc<Client>,
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
select_chain: SC,
) -> Result<(
) -> Result<
(
GrandpaBlockImport<BE, Block, Client, SC>,
LinkHalf<Block, Client, SC>,
), ClientError>
),
ClientError,
>
where
SC: SelectChain<Block>,
BE: Backend<Block> + 'static,
Client: ClientForGrandpa<Block, BE> + 'static,
{
block_import_with_authority_set_hard_forks(
client,
genesis_authorities_provider,
select_chain,
Default::default(),
)
}

/// Make block importer and link half necessary to tie the background voter to
/// it. A vector of authority set hard forks can be passed, any authority set
/// change signaled at the given block (either already signalled or in a further
/// block when importing it) will be replaced by a standard change with the
/// given static authorities.
pub fn block_import_with_authority_set_hard_forks<BE, Block: BlockT, Client, SC>(
client: Arc<Client>,
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
select_chain: SC,
authority_set_hard_forks: Vec<(SetId, (Block::Hash, NumberFor<Block>), AuthorityList)>,
) -> Result<
(
GrandpaBlockImport<BE, Block, Client, SC>,
LinkHalf<Block, Client, SC>,
),
ClientError,
>
where
SC: SelectChain<Block>,
BE: Backend<Block> + 'static,
Expand All @@ -444,13 +477,32 @@ where

let (voter_commands_tx, voter_commands_rx) = mpsc::unbounded();

// create pending change objects with 0 delay and enacted on finality
// (i.e. standard changes) for each authority set hard fork.
let authority_set_hard_forks = authority_set_hard_forks
.into_iter()
.map(|(set_id, (hash, number), authorities)| {
(
set_id,
authorities::PendingChange {
next_authorities: authorities,
delay: Zero::zero(),
canon_hash: hash,
canon_height: number,
delay_kind: authorities::DelayKind::Finalized,
},
)
})
.collect();

Ok((
GrandpaBlockImport::new(
client.clone(),
select_chain.clone(),
persistent_data.authority_set.clone(),
voter_commands_tx,
persistent_data.consensus_changes.clone(),
authority_set_hard_forks,
),
LinkHalf {
client,
Expand Down