// Copyright 2019-2021 Parity Technologies (UK) Ltd. // This file is part of Parity Bridges Common. // Parity Bridges Common is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity Bridges Common is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . //! Parachain heads source. use crate::parachains::{ParachainsPipelineAdapter, SubstrateParachainsPipeline}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; use bp_parachains::parachain_head_storage_key_at_source; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; use codec::Decode; use parachains_relay::parachains_loop::{ParaHashAtSource, SourceClient}; use relay_substrate_client::{ Chain, Client, Error as SubstrateError, HeaderIdOf, HeaderOf, RelayChain, }; use relay_utils::relay_loop::Client as RelayClient; use sp_runtime::traits::Header as HeaderT; /// Shared updatable reference to the maximal parachain header id that we want to sync from the /// source. pub type RequiredHeaderIdRef = Arc>>>; /// Substrate client as parachain heads source. #[derive(Clone)] pub struct ParachainsSource { client: Client, maximal_header_id: Option>, } impl ParachainsSource

{ /// Creates new parachains source client. pub fn new( client: Client, maximal_header_id: Option>, ) -> Self { ParachainsSource { client, maximal_header_id } } /// Returns reference to the underlying RPC client. pub fn client(&self) -> &Client { &self.client } /// Return decoded head of given parachain. pub async fn on_chain_parachain_header( &self, at_block: HeaderIdOf, para_id: ParaId, ) -> Result>, SubstrateError> { let storage_key = parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, para_id); let para_head = self.client.raw_storage_value(storage_key, Some(at_block.1)).await?; let para_head = para_head.map(|h| ParaHead::decode(&mut &h.0[..])).transpose()?; let para_head = match para_head { Some(para_head) => para_head, None => return Ok(None), }; Ok(Some(Decode::decode(&mut ¶_head.0[..])?)) } } #[async_trait] impl RelayClient for ParachainsSource

{ type Error = SubstrateError; async fn reconnect(&mut self) -> Result<(), SubstrateError> { self.client.reconnect().await } } #[async_trait] impl SourceClient> for ParachainsSource

where P::SourceParachain: Chain, { async fn ensure_synced(&self) -> Result { match self.client.ensure_synced().await { Ok(_) => Ok(true), Err(SubstrateError::ClientNotSynced(_)) => Ok(false), Err(e) => Err(e), } } async fn parachain_head( &self, at_block: HeaderIdOf, para_id: ParaId, ) -> Result { // we don't need to support many parachains now if para_id.0 != P::SOURCE_PARACHAIN_PARA_ID { return Err(SubstrateError::Custom(format!( "Parachain id {} is not matching expected {}", para_id.0, P::SOURCE_PARACHAIN_PARA_ID, ))) } Ok(match self.on_chain_parachain_header(at_block, para_id).await? { Some(parachain_header) => { let mut parachain_head = ParaHashAtSource::Some(parachain_header.hash()); // never return head that is larger than requested. This way we'll never sync // headers past `maximal_header_id` if let Some(ref maximal_header_id) = self.maximal_header_id { let maximal_header_id = *maximal_header_id.lock().await; match maximal_header_id { Some(maximal_header_id) if *parachain_header.number() > maximal_header_id.0 => { // we don't want this header yet => let's report previously requested // header parachain_head = ParaHashAtSource::Some(maximal_header_id.1); }, Some(_) => (), None => { // on-demand relay has not yet asked us to sync anything let's do that parachain_head = ParaHashAtSource::Unavailable; }, } } parachain_head }, None => ParaHashAtSource::None, }) } async fn prove_parachain_heads( &self, at_block: HeaderIdOf, parachains: &[ParaId], ) -> Result { let storage_keys = parachains .iter() .map(|para_id| { parachain_head_storage_key_at_source( P::SourceRelayChain::PARAS_PALLET_NAME, *para_id, ) }) .collect(); let parachain_heads_proof = self .client .prove_storage(storage_keys, at_block.1) .await? .iter_nodes() .collect(); Ok(ParaHeadsProof(parachain_heads_proof)) } }