;
}
+
+/// Errors that can occur while following the polkadot relay-chain.
+#[derive(Debug)]
+pub enum Error {
+ /// An underlying client error.
+ Client(ClientError),
+ /// Polkadot client error.
+ Polkadot(P),
+ /// Head data returned was not for our parachain.
+ InvalidHeadData,
+}
+
+/// A parachain head update.
+pub struct HeadUpdate {
+ /// The relay-chain's block hash where the parachain head updated.
+ pub relay_hash: PHash,
+ /// The relay-chain's block number where the parachain head updated.
+ pub relay_number: PBlockNumber,
+ /// The parachain head-data.
+ pub head_data: Vec,
+}
+
+/// Helper for the Polkadot client.
+pub trait PolkadotClient {
+ /// The error type for interacting with the Polkadot client.
+ type Error: std::fmt::Debug + Send;
+
+ /// A stream that yields updates to the parachain head.
+ type HeadUpdates: Stream- + Send;
+ /// A stream that yields finalized head-data for a certain parachain.
+ type Finalized: Stream
- ,Error=Self::Error> + Send;
+
+ /// Get a stream of head updates.
+ fn head_updates(&self, para_id: ParaId) -> Self::HeadUpdates;
+ /// Get a stream of finalized heads.
+ fn finalized_heads(&self, para_id: ParaId) -> Self::Finalized;
+}
+
+/// Spawns a future that follows the Polkadot relay chain for the given parachain.
+pub fn follow_polkadot<'a, L: 'a, P: 'a>(para_id: ParaId, local: Arc, polkadot: Arc
)
+ -> impl Future- + Send + 'a
+ where
+ L: LocalClient + Send + Sync,
+ P: PolkadotClient + Send + Sync,
+{
+ let head_updates = polkadot.head_updates(para_id);
+ let finalized_heads = polkadot.finalized_heads(para_id);
+
+ let follow_best = {
+ let local = local.clone();
+
+ head_updates
+ .map_err(Error::Polkadot)
+ .and_then(|update| {
+ ::Header::decode(&mut &update.head_data[..])
+ .ok_or_else(|| Error::InvalidHeadData)
+ })
+ .for_each(move |p_head| {
+ let _synced = local.mark_best(p_head.hash()).map_err(Error::Client)?;
+ Ok(())
+ })
+ };
+
+ let follow_finalized = {
+ let local = local.clone();
+
+ finalized_heads
+ .map_err(Error::Polkadot)
+ .and_then(|head_data| {
+ ::Header::decode(&mut &head_data[..])
+ .ok_or_else(|| Error::InvalidHeadData)
+ })
+ .for_each(move |p_head| {
+ let _synced = local.finalize(p_head.hash()).map_err(Error::Client)?;
+ Ok(())
+ })
+ };
+
+ follow_best.join(follow_finalized)
+ .map_err(|e| warn!("Could not follow relay-chain: {:?}", e))
+ .map(|((), ())| ())
+}
\ No newline at end of file