>,
_phantom: PhantomData,
}
impl FinalitySource {
/// Create new headers source using given client.
pub fn new(client: Client, maximal_header_number: Option>) -> Self {
FinalitySource {
client,
maximal_header_number,
_phantom: Default::default(),
}
}
/// Returns reference to the underlying RPC client.
pub fn client(&self) -> &Client {
&self.client
}
/// Returns best finalized block number.
pub async fn on_chain_best_finalized_block_number(&self) -> Result {
// we **CAN** continue to relay finality proofs if source node is out of sync, because
// target node may be missing proofs that are already available at the source
let finalized_header_hash = self.client.best_finalized_header_hash().await?;
let finalized_header = self.client.header_by_hash(finalized_header_hash).await?;
Ok(*finalized_header.number())
}
}
impl Clone for FinalitySource {
fn clone(&self) -> Self {
FinalitySource {
client: self.client.clone(),
maximal_header_number: self.maximal_header_number.clone(),
_phantom: Default::default(),
}
}
}
#[async_trait]
impl RelayClient for FinalitySource {
type Error = Error;
async fn reconnect(&mut self) -> Result<(), Error> {
self.client.reconnect().await
}
}
#[async_trait]
impl SourceClient for FinalitySource
where
C: Chain,
C::BlockNumber: relay_utils::BlockNumberBase,
P: FinalitySyncPipeline<
Hash = C::Hash,
Number = C::BlockNumber,
Header = SyncHeader,
FinalityProof = GrandpaJustification,
>,
P::Header: SourceHeader,
{
type FinalityProofsStream = Pin> + Send>>;
async fn best_finalized_block_number(&self) -> Result {
let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?;
// never return block number larger than requested. This way we'll never sync headers
// past `maximal_header_number`
if let Some(ref maximal_header_number) = self.maximal_header_number {
let maximal_header_number = *maximal_header_number.lock().await;
if finalized_header_number > maximal_header_number {
finalized_header_number = maximal_header_number;
}
}
Ok(finalized_header_number)
}
async fn header_and_finality_proof(
&self,
number: P::Number,
) -> Result<(P::Header, Option), Error> {
let header_hash = self.client.block_hash_by_number(number).await?;
let signed_block = self.client.get_block(Some(header_hash)).await?;
let justification = signed_block
.justification()
.map(|raw_justification| GrandpaJustification::::decode(&mut raw_justification.as_slice()))
.transpose()
.map_err(Error::ResponseParseFailed)?;
Ok((signed_block.header().into(), justification))
}
async fn finality_proofs(&self) -> Result {
Ok(unfold(
self.client.clone().subscribe_justifications().await?,
move |mut subscription| async move {
loop {
let next_justification = subscription.next().await?;
let decoded_justification =
GrandpaJustification::::decode(&mut &next_justification.0[..]);
let justification = match decoded_justification {
Ok(j) => j,
Err(err) => {
log::error!(
target: "bridge",
"Failed to decode justification target from the {} justifications stream: {:?}",
P::SOURCE_NAME,
err,
);
continue;
}
};
return Some((justification, subscription));
}
},
)
.boxed())
}
}