Skip to content

Commit

Permalink
Ignore checkpoint if it contains less than 2 epochs instead
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaka committed May 25, 2023
1 parent 9f204cd commit d46ce8e
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 24 deletions.
34 changes: 18 additions & 16 deletions lib/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,15 @@ fn convert_epoch(epoch: &light_sync_state::BabeEpoch) -> BabeEpochInformation {
}

impl LightSyncState {
pub fn to_chain_information(&self) -> Result<ValidChainInformation, InvalidCheckpointError> {
pub fn to_chain_information(
&self,
) -> Result<ValidChainInformation, CheckpointToChainInformationError> {
// TODO: this code is a bit of a shitshow when it comes to corner cases and should be cleaned up after https://github.com/paritytech/substrate/issues/11184

if self.inner.finalized_block_header.number == 0 {
return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint);
}

// Create a sorted list of all regular epochs that haven't been pruned from the sync state.
let mut epochs: Vec<_> = self
.inner
Expand All @@ -444,22 +450,18 @@ impl LightSyncState {
epochs.dedup_by_key(|(_, epoch)| epoch.epoch_index);

// Get the latest two epochs.
let finalized_block_epoch_information = if epochs.len() >= 2 {
Some(convert_epoch(epochs[epochs.len() - 2].1))
} else {
None
};
if epochs.is_empty() {
return Err(InvalidCheckpointError::EmptyBabeEpochsList);
if epochs.len() < 2 {
return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint);
}
let current_epoch = epochs[epochs.len() - 2].1;
let next_epoch = epochs[epochs.len() - 1].1;

ChainInformation {
finalized_block_header: self.inner.finalized_block_header.clone(),
consensus: ChainInformationConsensus::Babe {
slots_per_epoch: NonZeroU64::new(next_epoch.duration)
.ok_or(InvalidCheckpointError::InvalidBabeSlotsPerEpoch)?,
finalized_block_epoch_information,
.ok_or(CheckpointToChainInformationError::InvalidBabeSlotsPerEpoch)?,
finalized_block_epoch_information: Some(convert_epoch(current_epoch)),
finalized_next_epoch_transition: convert_epoch(next_epoch),
},
finality: ChainInformationFinality::Grandpa {
Expand All @@ -473,7 +475,7 @@ impl LightSyncState {
Ok(crate::header::GrandpaAuthority {
public_key: authority.public_key,
weight: NonZeroU64::new(authority.weight)
.ok_or(InvalidCheckpointError::InvalidGrandpaAuthorityWeight)?,
.ok_or(CheckpointToChainInformationError::InvalidGrandpaAuthorityWeight)?,
})
})
.collect::<Result<_, _>>()?
Expand All @@ -482,7 +484,7 @@ impl LightSyncState {
},
}
.try_into()
.map_err(InvalidCheckpointError::InvalidData)
.map_err(CheckpointToChainInformationError::InvalidData)
}
}

Expand Down Expand Up @@ -515,11 +517,11 @@ pub enum FromGenesisStorageError {
UnknownStorageItems,
}

/// Error when building the chain information from the genesis storage.
/// Error when building the chain information corresponding to a checkpoint.
#[derive(Debug, derive_more::Display)]
pub enum InvalidCheckpointError {
/// The list of Babe epochs is empty.
EmptyBabeEpochsList,
pub enum CheckpointToChainInformationError {
/// The checkpoint corresponds to the genesis block.
GenesisBlockCheckpoint,
/// Found a value of 0 for the number of Babe slots per epoch.
InvalidBabeSlotsPerEpoch,
/// Found a Grandpa authority with a weight of 0.
Expand Down
19 changes: 13 additions & 6 deletions light-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,20 +464,27 @@ impl<TPlat: platform::PlatformRef, TChain> Client<TPlat, TChain> {

(Err(err), _, _) => return Err(AddChainError::InvalidGenesisStorage(err)),

(_, Some(Err(err)), _) => {
return Err(AddChainError::InvalidCheckpoint(err));
}

(Ok(genesis_ci), Some(Ok(checkpoint)), _) => {
let genesis_header = genesis_ci.as_ref().finalized_block_header.clone();
(checkpoint, genesis_header.into(), Default::default())
}

(Ok(genesis_ci), None, _) => {
(
Ok(genesis_ci),
None
| Some(Err(
chain_spec::CheckpointToChainInformationError::GenesisBlockCheckpoint,
)),
_,
) => {
let genesis_header =
header::Header::from(genesis_ci.as_ref().finalized_block_header.clone());
(genesis_ci, genesis_header, Default::default())
}

(_, Some(Err(err)), _) => {
return Err(AddChainError::InvalidCheckpoint(err));
}
}
};

Expand Down Expand Up @@ -1009,7 +1016,7 @@ pub enum AddChainError {
ChainSpecNeitherGenesisStorageNorCheckpoint,
/// Checkpoint provided in the chain specification is invalid.
#[display(fmt = "Invalid checkpoint in chain specification: {_0}")]
InvalidCheckpoint(chain_spec::InvalidCheckpointError),
InvalidCheckpoint(chain_spec::CheckpointToChainInformationError),
/// Failed to build the information about the chain from the genesis storage. This indicates
/// invalid data in the genesis storage.
#[display(fmt = "Failed to build genesis chain information: {_0}")]
Expand Down
4 changes: 2 additions & 2 deletions wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

### Fixed

- Fix panic when the checkpoint in the chain specification contains an empty list of Babe epochs, which can normally only happen if the checkpoint was modified manually. ([#603](https://github.com/smol-dot/smoldot/pull/603))
- Fix panic when the checkpoint in the chain specification contains only one Babe epoch, which can happen if the checkpoint was generated before any block was authored. ([#603](https://github.com/smol-dot/smoldot/pull/603))
- Fix panic when the checkpoint in the chain specification is invalid, which can normally only happen if the checkpoint was modified manually. ([#603](https://github.com/smol-dot/smoldot/pull/603))
- Fix panic when the checkpoint in the chain specification contains zero or one Babe epochs, which can happen if the checkpoint was generated before any block was authored. ([#603](https://github.com/smol-dot/smoldot/pull/603))

## 1.0.6 - 2023-05-09

Expand Down

0 comments on commit d46ce8e

Please sign in to comment.