Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A0-1823: add substrate specific chain status #844

Merged
merged 10 commits into from
Jan 9, 2023
6 changes: 4 additions & 2 deletions finality-aleph/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ pub enum BlockStatus<J: Justification> {

/// The knowledge about the chain status.
pub trait ChainStatus<J: Justification> {
type Error: Display;

/// The status of the block.
fn status_of(&self, id: <J::Header as Header>::Identifier) -> BlockStatus<J>;

/// The header of the best block.
fn best_block(&self) -> J::Header;
fn best_block(&self) -> Result<J::Header, Self::Error>;

/// The justification of the top finalized block.
fn top_finalized(&self) -> J;
fn top_finalized(&self) -> Result<J, Self::Error>;
}
147 changes: 147 additions & 0 deletions finality-aleph/src/sync/substrate/chain_status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use std::{
fmt::{Display, Error as FmtError, Formatter},
marker::PhantomData,
};

use aleph_primitives::{BlockNumber, ALEPH_ENGINE_ID};
use log::warn;
use sp_blockchain::Backend;
use sp_runtime::{
generic::BlockId as SubstrateBlockId,
traits::{Block as BlockT, Header as SubstrateHeader},
};

use crate::{
justification::backwards_compatible_decode,
sync::{substrate::Justification, BlockStatus, ChainStatus, Header, LOG_TARGET},
AlephJustification,
};

/// What can go wrong when checking chain status
#[derive(Debug)]
pub enum Error<B: BlockT> {
MissingHash(B::Hash),
MissingJustification(B::Hash),
}

impl<B: BlockT> Display for Error<B> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
use Error::*;
match self {
MissingHash(hash) => {
write!(f, "no block for hash {:?}", hash)
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
}
MissingJustification(hash) => {
write!(
f,
"no justification for finalized block with hash {:?}",
hash
)
}
}
}
}
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved

/// Substrate implementation of ChainStatus trait
struct SubstrateChainStatus<B, BE>
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
where
BE: Backend<B>,
B: BlockT,
B::Header: SubstrateHeader<Number = BlockNumber>,
{
client: BE,
_phantom: PhantomData<B>,
}

impl<B, BE> SubstrateChainStatus<B, BE>
where
BE: Backend<B>,
B: BlockT,
B::Header: SubstrateHeader<Number = BlockNumber>,
{
fn header(&self, hash: B::Hash) -> Option<B::Header> {
let id = SubstrateBlockId::<B>::Hash(hash);
self.client
.header(id)
.expect("substrate client must respond")
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
}

fn justification(&self, hash: B::Hash) -> Option<AlephJustification> {
let id = SubstrateBlockId::<B>::Hash(hash);
let justification = self
.client
.justifications(id)
.expect("substrate client must respond")
.and_then(|j| j.into_justification(ALEPH_ENGINE_ID))?;

match backwards_compatible_decode(justification) {
Ok(justification) => Some(justification),
// This should not happen, as we only import correctly encoded justification.
Err(e) => {
warn!(
target: LOG_TARGET,
"Could not decode stored justification for block {:?}: {}", hash, e
);
None
}
}
}

fn best_hash(&self) -> B::Hash {
self.client.info().best_hash
}

fn finalized_hash(&self) -> B::Hash {
self.client.info().finalized_hash
}
}

impl<B, BE> ChainStatus<Justification<B::Header>> for SubstrateChainStatus<B, BE>
where
BE: Backend<B>,
B: BlockT,
B::Header: SubstrateHeader<Number = BlockNumber>,
{
type Error = Error<B>;

fn status_of(
&self,
id: <B::Header as Header>::Identifier,
) -> BlockStatus<Justification<B::Header>> {
let header = match self.header(id.hash) {
Some(header) => header,
None => return BlockStatus::Unknown,
};

if let Some(raw_justification) = self.justification(id.hash) {
BlockStatus::Justified(Justification {
header,
raw_justification,
})
} else {
BlockStatus::Present(header)
}
}

fn best_block(&self) -> Result<B::Header, Self::Error> {
let best_hash = self.best_hash();

self.header(best_hash).ok_or(Error::MissingHash(best_hash))
}

fn top_finalized(&self) -> Result<Justification<B::Header>, Self::Error> {
let finalized_hash = self.finalized_hash();

let header = self
.header(finalized_hash)
.ok_or(Error::MissingHash(finalized_hash))?;
let raw_justification = self
.justification(finalized_hash)
.ok_or(Error::MissingJustification(finalized_hash))?;

Ok(Justification {
header,
raw_justification,
})
}
}
1 change: 1 addition & 0 deletions finality-aleph/src/sync/substrate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
AlephJustification,
};

mod chain_status;
mod status_notifier;

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down