use async_trait::async_trait;
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use sp_consensus::{EnableProofRecording, Environment, Proposal, Proposer as SubstrateProposer};
use sp_inherents::InherentData;
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<Proposal<Block, StorageProof>, Error>;
}
pub struct Proposer<B, T> {
inner: T,
_marker: std::marker::PhantomData<B>,
}
impl<B, T> Proposer<B, T> {
pub fn new(inner: T) -> Self {
Proposer { inner, _marker: std::marker::PhantomData }
}
}
#[async_trait]
impl<B, T> ProposerInterface<B> for Proposer<B, T>
where
B: sp_runtime::traits::Block,
T: Environment<B> + Send,
T::Error: Send + Sync + 'static,
T::Proposer: SubstrateProposer<B, ProofRecording = EnableProofRecording, Proof = StorageProof>,
<T::Proposer as SubstrateProposer<B>>::Error: Send + Sync + 'static,
{
async fn propose(
&mut self,
parent_header: &B::Header,
paras_inherent_data: &ParachainInherentData,
other_inherent_data: InherentData,
inherent_digests: Digest,
max_duration: Duration,
block_size_limit: Option<usize>,
) -> Result<Proposal<B, StorageProof>, Error> {
let proposer = self
.inner
.init(parent_header)
.await
.map_err(|e| Error::proposer_creation(anyhow::Error::new(e)))?;
let mut inherent_data = other_inherent_data;
inherent_data
.put_data(
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
¶s_inherent_data,
)
.map_err(|e| Error::proposing(anyhow::Error::new(e)))?;
proposer
.propose(inherent_data, inherent_digests, max_duration, block_size_limit)
.await
.map_err(|e| Error::proposing(anyhow::Error::new(e)).into())
}
}