use async_trait::async_trait;
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use sc_basic_authorship::{ProposeArgs, ProposerFactory};
use sc_block_builder::BlockBuilderApi;
use sc_transaction_pool_api::TransactionPool;
use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_consensus::{EnableProofRecording, Environment, Proposal};
use sp_inherents::{InherentData, InherentDataProvider};
use sp_runtime::{traits::Block as BlockT, Digest};
use sp_state_machine::StorageProof;
use std::{fmt::Debug, time::Duration};
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub struct Error {
inner: anyhow::Error,
}
impl Error {
pub fn proposer_creation(err: impl Into<anyhow::Error>) -> Self {
Error { inner: err.into().context("Proposer Creation") }
}
pub fn proposing(err: impl Into<anyhow::Error>) -> Self {
Error { inner: err.into().context("Proposing") }
}
}
pub type ProposalOf<B> = Proposal<B, StorageProof>;
#[async_trait]
pub trait ProposerInterface<Block: BlockT> {
async fn propose(
&mut self,
parent_header: &Block::Header,
paras_inherent_data: &ParachainInherentData,
other_inherent_data: InherentData,
inherent_digests: Digest,
max_duration: Duration,
block_size_limit: Option<usize>,
) -> Result<Option<Proposal<Block, StorageProof>>, Error>;
}
#[async_trait]
impl<Block, A, C> ProposerInterface<Block> for ProposerFactory<A, C, EnableProofRecording>
where
A: TransactionPool<Block = Block> + 'static,
C: HeaderBackend<Block> + ProvideRuntimeApi<Block> + CallApiAt<Block> + Send + Sync + 'static,
C::Api: ApiExt<Block> + BlockBuilderApi<Block>,
Block: sp_runtime::traits::Block,
{
async fn propose(
&mut self,
parent_header: &Block::Header,
paras_inherent_data: &ParachainInherentData,
other_inherent_data: InherentData,
inherent_digests: Digest,
max_duration: Duration,
block_size_limit: Option<usize>,
) -> Result<Option<Proposal<Block, StorageProof>>, Error> {
let proposer = self
.init(parent_header)
.await
.map_err(|e| Error::proposer_creation(anyhow::Error::new(e)))?;
let mut inherent_data = other_inherent_data;
paras_inherent_data
.provide_inherent_data(&mut inherent_data)
.await
.map_err(|e| Error::proposing(anyhow::Error::new(e)))?;
proposer
.propose_block(ProposeArgs {
inherent_data,
inherent_digests,
max_duration,
block_size_limit,
ignored_nodes_by_proof_recording: None,
})
.await
.map(Some)
.map_err(|e| Error::proposing(anyhow::Error::new(e)).into())
}
}