Skip to content

Commit 05ad300

Browse files
andresilvaGeneral-Beck
authored andcommitted
grandpa: support for hard forking any pending standard changes (paritytech#5306)
* grandpa: support for hard forking any pending standard changes * grandpa: expose authority_set_hard_forks in block import constructor * grandpa: don't break the public api
1 parent 781ce91 commit 05ad300

File tree

2 files changed

+104
-6
lines changed

2 files changed

+104
-6
lines changed

client/finality-grandpa/src/import.rs

+50-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use sp_consensus::{
3030
BlockCheckParams, BlockImportParams, ImportResult, JustificationImport,
3131
SelectChain,
3232
};
33-
use sp_finality_grandpa::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog};
33+
use sp_finality_grandpa::{ConsensusLog, ScheduledChange, SetId, GRANDPA_ENGINE_ID};
3434
use sp_runtime::Justification;
3535
use sp_runtime::generic::{BlockId, OpaqueDigestItemId};
3636
use sp_runtime::traits::{
@@ -59,6 +59,7 @@ pub struct GrandpaBlockImport<Backend, Block: BlockT, Client, SC> {
5959
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
6060
send_voter_commands: mpsc::UnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
6161
consensus_changes: SharedConsensusChanges<Block::Hash, NumberFor<Block>>,
62+
authority_set_hard_forks: HashMap<Block::Hash, PendingChange<Block::Hash, NumberFor<Block>>>,
6263
_phantom: PhantomData<Backend>,
6364
}
6465

@@ -72,6 +73,7 @@ impl<Backend, Block: BlockT, Client, SC: Clone> Clone for
7273
authority_set: self.authority_set.clone(),
7374
send_voter_commands: self.send_voter_commands.clone(),
7475
consensus_changes: self.consensus_changes.clone(),
76+
authority_set_hard_forks: self.authority_set_hard_forks.clone(),
7577
_phantom: PhantomData,
7678
}
7779
}
@@ -212,9 +214,16 @@ where
212214
Client: crate::ClientForGrandpa<Block, BE>,
213215
{
214216
// check for a new authority set change.
215-
fn check_new_change(&self, header: &Block::Header, hash: Block::Hash)
216-
-> Option<PendingChange<Block::Hash, NumberFor<Block>>>
217-
{
217+
fn check_new_change(
218+
&self,
219+
header: &Block::Header,
220+
hash: Block::Hash,
221+
) -> Option<PendingChange<Block::Hash, NumberFor<Block>>> {
222+
// check for forced authority set hard forks
223+
if let Some(change) = self.authority_set_hard_forks.get(&hash) {
224+
return Some(change.clone());
225+
}
226+
218227
// check for forced change.
219228
if let Some((median_last_finalized, change)) = find_forced_change::<Block>(header) {
220229
return Some(PendingChange {
@@ -529,13 +538,50 @@ impl<Backend, Block: BlockT, Client, SC> GrandpaBlockImport<Backend, Block, Clie
529538
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
530539
send_voter_commands: mpsc::UnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
531540
consensus_changes: SharedConsensusChanges<Block::Hash, NumberFor<Block>>,
541+
authority_set_hard_forks: Vec<(SetId, PendingChange<Block::Hash, NumberFor<Block>>)>,
532542
) -> GrandpaBlockImport<Backend, Block, Client, SC> {
543+
// check for and apply any forced authority set hard fork that applies
544+
// to the *current* authority set.
545+
if let Some((_, change)) = authority_set_hard_forks
546+
.iter()
547+
.find(|(set_id, _)| *set_id == authority_set.set_id())
548+
{
549+
let mut authority_set = authority_set.inner().write();
550+
authority_set.current_authorities = change.next_authorities.clone();
551+
}
552+
553+
// index authority set hard forks by block hash so that they can be used
554+
// by any node syncing the chain and importing a block hard fork
555+
// authority set changes.
556+
let authority_set_hard_forks = authority_set_hard_forks
557+
.into_iter()
558+
.map(|(_, change)| (change.canon_hash, change))
559+
.collect::<HashMap<_, _>>();
560+
561+
// check for and apply any forced authority set hard fork that apply to
562+
// any *pending* standard changes, checking by the block hash at which
563+
// they were announced.
564+
{
565+
let mut authority_set = authority_set.inner().write();
566+
567+
authority_set.pending_standard_changes = authority_set
568+
.pending_standard_changes
569+
.clone()
570+
.map(&mut |hash, _, original| {
571+
authority_set_hard_forks
572+
.get(&hash)
573+
.cloned()
574+
.unwrap_or(original)
575+
});
576+
}
577+
533578
GrandpaBlockImport {
534579
inner,
535580
select_chain,
536581
authority_set,
537582
send_voter_commands,
538583
consensus_changes,
584+
authority_set_hard_forks,
539585
_phantom: PhantomData,
540586
}
541587
}

client/finality-grandpa/src/lib.rs

+54-2
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,43 @@ pub fn block_import<BE, Block: BlockT, Client, SC>(
417417
client: Arc<Client>,
418418
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
419419
select_chain: SC,
420-
) -> Result<(
420+
) -> Result<
421+
(
421422
GrandpaBlockImport<BE, Block, Client, SC>,
422423
LinkHalf<Block, Client, SC>,
423-
), ClientError>
424+
),
425+
ClientError,
426+
>
427+
where
428+
SC: SelectChain<Block>,
429+
BE: Backend<Block> + 'static,
430+
Client: ClientForGrandpa<Block, BE> + 'static,
431+
{
432+
block_import_with_authority_set_hard_forks(
433+
client,
434+
genesis_authorities_provider,
435+
select_chain,
436+
Default::default(),
437+
)
438+
}
439+
440+
/// Make block importer and link half necessary to tie the background voter to
441+
/// it. A vector of authority set hard forks can be passed, any authority set
442+
/// change signaled at the given block (either already signalled or in a further
443+
/// block when importing it) will be replaced by a standard change with the
444+
/// given static authorities.
445+
pub fn block_import_with_authority_set_hard_forks<BE, Block: BlockT, Client, SC>(
446+
client: Arc<Client>,
447+
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
448+
select_chain: SC,
449+
authority_set_hard_forks: Vec<(SetId, (Block::Hash, NumberFor<Block>), AuthorityList)>,
450+
) -> Result<
451+
(
452+
GrandpaBlockImport<BE, Block, Client, SC>,
453+
LinkHalf<Block, Client, SC>,
454+
),
455+
ClientError,
456+
>
424457
where
425458
SC: SelectChain<Block>,
426459
BE: Backend<Block> + 'static,
@@ -444,13 +477,32 @@ where
444477

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

480+
// create pending change objects with 0 delay and enacted on finality
481+
// (i.e. standard changes) for each authority set hard fork.
482+
let authority_set_hard_forks = authority_set_hard_forks
483+
.into_iter()
484+
.map(|(set_id, (hash, number), authorities)| {
485+
(
486+
set_id,
487+
authorities::PendingChange {
488+
next_authorities: authorities,
489+
delay: Zero::zero(),
490+
canon_hash: hash,
491+
canon_height: number,
492+
delay_kind: authorities::DelayKind::Finalized,
493+
},
494+
)
495+
})
496+
.collect();
497+
447498
Ok((
448499
GrandpaBlockImport::new(
449500
client.clone(),
450501
select_chain.clone(),
451502
persistent_data.authority_set.clone(),
452503
voter_commands_tx,
453504
persistent_data.consensus_changes.clone(),
505+
authority_set_hard_forks,
454506
),
455507
LinkHalf {
456508
client,

0 commit comments

Comments
 (0)