referrerpolicy=no-referrer-when-downgrade

cumulus_client_consensus_proposer/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5// Cumulus is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9
10// Cumulus is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with Cumulus. If not, see <https://www.gnu.org/licenses/>.
17
18//! The Cumulus [`ProposerInterface`] is an extension of the Substrate [`ProposerFactory`]
19//! for creating new parachain blocks.
20//!
21//! This utility is designed to be composed within any collator consensus algorithm.
22
23use async_trait::async_trait;
24use cumulus_primitives_parachain_inherent::ParachainInherentData;
25use sc_basic_authorship::{ProposeArgs, ProposerFactory};
26use sc_block_builder::BlockBuilderApi;
27use sc_transaction_pool_api::TransactionPool;
28use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi};
29use sp_blockchain::HeaderBackend;
30use sp_consensus::{EnableProofRecording, Environment, Proposal};
31use sp_inherents::{InherentData, InherentDataProvider};
32use sp_runtime::{traits::Block as BlockT, Digest};
33use sp_state_machine::StorageProof;
34use std::{fmt::Debug, time::Duration};
35
36/// Errors that can occur when proposing a parachain block.
37#[derive(thiserror::Error, Debug)]
38#[error(transparent)]
39pub struct Error {
40	inner: anyhow::Error,
41}
42
43impl Error {
44	/// Create an error tied to the creation of a proposer.
45	pub fn proposer_creation(err: impl Into<anyhow::Error>) -> Self {
46		Error { inner: err.into().context("Proposer Creation") }
47	}
48
49	/// Create an error tied to the proposing logic itself.
50	pub fn proposing(err: impl Into<anyhow::Error>) -> Self {
51		Error { inner: err.into().context("Proposing") }
52	}
53}
54
55/// A type alias for easily referring to the type of a proposal produced by a specific
56/// [`ProposerInterface`].
57pub type ProposalOf<B> = Proposal<B, StorageProof>;
58
59/// An interface for proposers.
60#[async_trait]
61pub trait ProposerInterface<Block: BlockT> {
62	/// Propose a collation using the supplied `InherentData` and the provided
63	/// `ParachainInherentData`.
64	///
65	/// Also specify any required inherent digests, the maximum proposal duration,
66	/// and the block size limit in bytes. See the documentation on
67	/// [`sp_consensus::Proposer::propose`] for more details on how to interpret these parameters.
68	///
69	/// The `InherentData` and `Digest` are left deliberately general in order to accommodate
70	/// all possible collator selection algorithms or inherent creation mechanisms,
71	/// while the `ParachainInherentData` is made explicit so it will be constructed appropriately.
72	///
73	/// If the `InherentData` passed into this function already has a `ParachainInherentData`,
74	/// this should throw an error.
75	async fn propose(
76		&mut self,
77		parent_header: &Block::Header,
78		paras_inherent_data: &ParachainInherentData,
79		other_inherent_data: InherentData,
80		inherent_digests: Digest,
81		max_duration: Duration,
82		block_size_limit: Option<usize>,
83	) -> Result<Option<Proposal<Block, StorageProof>>, Error>;
84}
85
86#[async_trait]
87impl<Block, A, C> ProposerInterface<Block> for ProposerFactory<A, C, EnableProofRecording>
88where
89	A: TransactionPool<Block = Block> + 'static,
90	C: HeaderBackend<Block> + ProvideRuntimeApi<Block> + CallApiAt<Block> + Send + Sync + 'static,
91	C::Api: ApiExt<Block> + BlockBuilderApi<Block>,
92	Block: sp_runtime::traits::Block,
93{
94	async fn propose(
95		&mut self,
96		parent_header: &Block::Header,
97		paras_inherent_data: &ParachainInherentData,
98		other_inherent_data: InherentData,
99		inherent_digests: Digest,
100		max_duration: Duration,
101		block_size_limit: Option<usize>,
102	) -> Result<Option<Proposal<Block, StorageProof>>, Error> {
103		let proposer = self
104			.init(parent_header)
105			.await
106			.map_err(|e| Error::proposer_creation(anyhow::Error::new(e)))?;
107
108		let mut inherent_data = other_inherent_data;
109		paras_inherent_data
110			.provide_inherent_data(&mut inherent_data)
111			.await
112			.map_err(|e| Error::proposing(anyhow::Error::new(e)))?;
113
114		proposer
115			.propose_block(ProposeArgs {
116				inherent_data,
117				inherent_digests,
118				max_duration,
119				block_size_limit,
120				ignored_nodes_by_proof_recording: None,
121			})
122			.await
123			.map(Some)
124			.map_err(|e| Error::proposing(anyhow::Error::new(e)).into())
125	}
126}