use astar_primitives::*;
use cumulus_primitives_core::relay_chain::PersistedValidationData;
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use fc_rpc::pending::ConsensusDataProvider;
use sc_client_api::{AuxStore, UsageProvider};
use sc_consensus::{import_queue::Verifier as VerifierT, BlockImportParams};
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_consensus_aura::{
digests::CompatibleDigestItem,
sr25519::{AuthorityId as AuraId, AuthoritySignature},
AuraApi,
};
use sp_inherents::{CreateInherentDataProviders, Error, InherentData};
use sp_runtime::{
traits::{Block as BlockT, Header as HeaderT},
Digest, DigestItem,
};
use sp_timestamp::TimestampInherentData;
use std::{marker::PhantomData, sync::Arc};
pub struct Verifier<Client> {
pub client: Arc<Client>,
pub aura_verifier: Box<dyn VerifierT<Block>>,
pub relay_chain_verifier: Box<dyn VerifierT<Block>>,
}
#[async_trait::async_trait]
impl<Client> VerifierT<Block> for Verifier<Client>
where
Client: ProvideRuntimeApi<Block> + Send + Sync,
Client::Api: AuraApi<Block, AuraId>,
{
async fn verify(
&self,
block_import: BlockImportParams<Block>,
) -> Result<BlockImportParams<Block>, String> {
if self
.client
.runtime_api()
.has_api::<dyn AuraApi<Block, AuraId>>(*block_import.header.parent_hash())
.unwrap_or(false)
{
self.aura_verifier.verify(block_import).await
} else {
self.relay_chain_verifier.verify(block_import).await
}
}
}
pub struct AuraConsensusDataProviderFallback<B, C> {
client: Arc<C>,
phantom_data: PhantomData<B>,
}
impl<B, C> AuraConsensusDataProviderFallback<B, C>
where
B: BlockT,
C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
C::Api: AuraApi<B, AuraId>,
{
pub fn new(client: Arc<C>) -> Self {
Self {
client,
phantom_data: Default::default(),
}
}
}
impl<B, C> ConsensusDataProvider<B> for AuraConsensusDataProviderFallback<B, C>
where
B: BlockT,
C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
C::Api: AuraApi<B, AuraId>,
{
fn create_digest(&self, parent: &B::Header, data: &InherentData) -> Result<Digest, Error> {
if self
.client
.runtime_api()
.has_api::<dyn AuraApi<Block, AuraId>>(parent.hash())
.unwrap_or_default()
{
let slot_duration = sc_consensus_aura::slot_duration(&*self.client)
.expect("slot_duration should be present at this point; qed.");
let timestamp = data
.timestamp_inherent_data()?
.expect("Timestamp is always present; qed");
let digest_item =
<DigestItem as CompatibleDigestItem<AuthoritySignature>>::aura_pre_digest(
sp_consensus_aura::Slot::from_timestamp(timestamp, slot_duration),
);
return Ok(Digest {
logs: vec![digest_item],
});
}
Err(Error::Application("AuraApi is not present".into()))
}
}
pub struct PendingCrateInherentDataProvider<B, C> {
client: Arc<C>,
phantom_data: PhantomData<B>,
}
impl<B, C> PendingCrateInherentDataProvider<B, C>
where
B: BlockT,
C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
C::Api: AuraApi<B, AuraId>,
{
pub fn new(client: Arc<C>) -> Self {
Self {
client,
phantom_data: Default::default(),
}
}
}
#[async_trait::async_trait]
impl<B, C> CreateInherentDataProviders<B, ()> for PendingCrateInherentDataProvider<B, C>
where
B: BlockT,
C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B> + Send + Sync,
C::Api: AuraApi<B, AuraId>,
{
type InherentDataProviders = (
sp_consensus_aura::inherents::InherentDataProvider,
sp_timestamp::InherentDataProvider,
cumulus_primitives_parachain_inherent::ParachainInherentData,
);
async fn create_inherent_data_providers(
&self,
parent: B::Hash,
_extra_args: (),
) -> Result<Self::InherentDataProviders, Box<dyn std::error::Error + Send + Sync>> {
if !self
.client
.runtime_api()
.has_api::<dyn AuraApi<Block, AuraId>>(parent)
.unwrap_or_default()
{
return Err("AuraApi is not present".into());
}
let slot_duration = sc_consensus_aura::slot_duration(&*self.client)
.expect("slot_duration should be present at this point; qed.");
let current = sp_timestamp::InherentDataProvider::from_system_time();
let next_slot = current.timestamp().as_millis() + slot_duration.as_millis();
let timestamp = sp_timestamp::InherentDataProvider::new(next_slot.into());
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
let (relay_parent_storage_root, relay_chain_state) =
RelayStateSproofBuilder::default().into_state_root_and_proof();
let vfp = PersistedValidationData {
relay_parent_number: u32::MAX,
relay_parent_storage_root,
..Default::default()
};
let parachain_inherent_data =
cumulus_primitives_parachain_inherent::ParachainInherentData {
validation_data: vfp,
relay_chain_state,
downward_messages: Default::default(),
horizontal_messages: Default::default(),
};
Ok((slot, timestamp, parachain_inherent_data))
}
}