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

Commit cd715e6

Browse files
committed
sc-consensus-beefy: fix initialization when BEEFY genesis state unavailable
When BEEFY voter is initialized from scratch (no aux db persistent data present), it needs to find BEEFY genesis block and all subsequent Mandatory blocks and sync justifications for them. The initialization code was getting active validator sets for these older blocks from state, but in cases such as 'fast sync', state is unavailable. This commit adds a fallback initialization mechanism when state is unavailable: parse header Digests looking for validator set change log deposits. Signed-off-by: Adrian Catangiu <adrian@parity.io>
1 parent aedfdc9 commit cd715e6

File tree

1 file changed

+24
-15
lines changed
  • client/consensus/beefy/src

1 file changed

+24
-15
lines changed

client/consensus/beefy/src/lib.rs

+24-15
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ where
404404
let best_beefy = *header.number();
405405
// If no session boundaries detected so far, just initialize new rounds here.
406406
if sessions.is_empty() {
407-
let active_set = expect_validator_set(runtime, header.hash())?;
407+
let active_set = expect_validator_set(runtime, backend, &header, beefy_genesis)?;
408408
let mut rounds = Rounds::new(best_beefy, active_set);
409409
// Mark the round as already finalized.
410410
rounds.conclude(best_beefy);
@@ -423,7 +423,7 @@ where
423423

424424
if *header.number() == beefy_genesis {
425425
// We've reached BEEFY genesis, initialize voter here.
426-
let genesis_set = expect_validator_set(runtime, header.hash())?;
426+
let genesis_set = expect_validator_set(runtime, backend, &header, beefy_genesis)?;
427427
info!(
428428
target: LOG_TARGET,
429429
"🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \
@@ -452,16 +452,8 @@ where
452452
sessions.push_front(Rounds::new(*header.number(), active));
453453
}
454454

455-
// Check if state is still available if we move up the chain.
456-
let parent_hash = *header.parent_hash();
457-
runtime.runtime_api().validator_set(parent_hash).ok().flatten().ok_or_else(|| {
458-
let msg = format!("{}. Could not initialize BEEFY voter.", parent_hash);
459-
error!(target: LOG_TARGET, "🥩 {}", msg);
460-
ClientError::Consensus(sp_consensus::Error::StateUnavailable(msg))
461-
})?;
462-
463455
// Move up the chain.
464-
header = blockchain.expect_header(parent_hash)?;
456+
header = blockchain.expect_header(*header.parent_hash())?;
465457
};
466458

467459
aux_schema::write_current_version(backend)?;
@@ -512,19 +504,36 @@ where
512504
Err(ClientError::Backend(err_msg))
513505
}
514506

515-
fn expect_validator_set<B, R>(
507+
fn expect_validator_set<B, BE, R>(
516508
runtime: &R,
517-
at_hash: B::Hash,
509+
backend: &BE,
510+
at_header: &B::Header,
511+
beefy_genesis: NumberFor<B>,
518512
) -> ClientResult<ValidatorSet<AuthorityId>>
519513
where
520514
B: Block,
515+
BE: Backend<B>,
521516
R: ProvideRuntimeApi<B>,
522517
R::Api: BeefyApi<B, AuthorityId>,
523518
{
524519
runtime
525520
.runtime_api()
526-
.validator_set(at_hash)
521+
.validator_set(at_header.hash())
527522
.ok()
528523
.flatten()
529-
.ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into()))
524+
.or_else(|| {
525+
// if state unavailable, fallback to walking up the chain looking for the header
526+
// Digest emitted when validator set active 'at_header' was enacted.
527+
let blockchain = backend.blockchain();
528+
let mut header = at_header.clone();
529+
while *header.number() >= beefy_genesis {
530+
match worker::find_authorities_change::<B>(&header) {
531+
Some(active) => return Some(active),
532+
// Move up the chain.
533+
None => header = blockchain.expect_header(*header.parent_hash()).ok()?,
534+
}
535+
}
536+
None
537+
})
538+
.ok_or_else(|| ClientError::Backend("Could not find initial validator set".into()))
530539
}

0 commit comments

Comments
 (0)