cumulus_client_consensus_relay_chain/
lib.rs1use cumulus_client_consensus_common::{
39 ParachainBlockImportMarker, ParachainCandidate, ParachainConsensus,
40};
41use cumulus_primitives_core::{relay_chain::Hash as PHash, ParaId, PersistedValidationData};
42use cumulus_relay_chain_interface::RelayChainInterface;
43
44use sc_consensus::{BlockImport, BlockImportParams};
45use sp_consensus::{
46 BlockOrigin, EnableProofRecording, Environment, ProofRecording, Proposal, Proposer,
47};
48use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
49use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
50
51use parking_lot::Mutex;
52use std::{marker::PhantomData, sync::Arc, time::Duration};
53
54mod import_queue;
55pub use import_queue::{import_queue, Verifier};
56
57const LOG_TARGET: &str = "cumulus-consensus-relay-chain";
58
59pub struct RelayChainConsensus<B, PF, BI, RCInterface, CIDP> {
61 para_id: ParaId,
62 proposer_factory: Arc<Mutex<PF>>,
63 create_inherent_data_providers: Arc<CIDP>,
64 block_import: Arc<futures::lock::Mutex<BI>>,
65 relay_chain_interface: RCInterface,
66 _phantom: PhantomData<B>,
67}
68
69impl<B, PF, BI, RCInterface, CIDP> Clone for RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
70where
71 RCInterface: Clone,
72{
73 fn clone(&self) -> Self {
74 Self {
75 para_id: self.para_id,
76 proposer_factory: self.proposer_factory.clone(),
77 create_inherent_data_providers: self.create_inherent_data_providers.clone(),
78 block_import: self.block_import.clone(),
79 relay_chain_interface: self.relay_chain_interface.clone(),
80 _phantom: PhantomData,
81 }
82 }
83}
84
85impl<B, PF, BI, RCInterface, CIDP> RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
86where
87 B: BlockT,
88 BI: ParachainBlockImportMarker,
89 RCInterface: RelayChainInterface,
90 CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)>,
91{
92 pub fn new(
94 para_id: ParaId,
95 proposer_factory: PF,
96 create_inherent_data_providers: CIDP,
97 block_import: BI,
98 relay_chain_interface: RCInterface,
99 ) -> Self {
100 Self {
101 para_id,
102 proposer_factory: Arc::new(Mutex::new(proposer_factory)),
103 create_inherent_data_providers: Arc::new(create_inherent_data_providers),
104 block_import: Arc::new(futures::lock::Mutex::new(block_import)),
105 relay_chain_interface,
106 _phantom: PhantomData,
107 }
108 }
109
110 async fn inherent_data(
112 &self,
113 parent: B::Hash,
114 validation_data: &PersistedValidationData,
115 relay_parent: PHash,
116 ) -> Option<InherentData> {
117 let inherent_data_providers = self
118 .create_inherent_data_providers
119 .create_inherent_data_providers(parent, (relay_parent, validation_data.clone()))
120 .await
121 .map_err(|e| {
122 tracing::error!(
123 target: LOG_TARGET,
124 error = ?e,
125 "Failed to create inherent data providers.",
126 )
127 })
128 .ok()?;
129
130 inherent_data_providers
131 .create_inherent_data()
132 .await
133 .map_err(|e| {
134 tracing::error!(
135 target: LOG_TARGET,
136 error = ?e,
137 "Failed to create inherent data.",
138 )
139 })
140 .ok()
141 }
142}
143
144#[async_trait::async_trait]
145impl<B, PF, BI, RCInterface, CIDP> ParachainConsensus<B>
146 for RelayChainConsensus<B, PF, BI, RCInterface, CIDP>
147where
148 B: BlockT,
149 RCInterface: RelayChainInterface + Clone,
150 BI: BlockImport<B> + ParachainBlockImportMarker + Send + Sync,
151 PF: Environment<B> + Send + Sync,
152 PF::Proposer: Proposer<
153 B,
154 ProofRecording = EnableProofRecording,
155 Proof = <EnableProofRecording as ProofRecording>::Proof,
156 >,
157 CIDP: CreateInherentDataProviders<B, (PHash, PersistedValidationData)>,
158{
159 async fn produce_candidate(
160 &mut self,
161 parent: &B::Header,
162 relay_parent: PHash,
163 validation_data: &PersistedValidationData,
164 ) -> Option<ParachainCandidate<B>> {
165 let proposer_future = self.proposer_factory.lock().init(parent);
166
167 let proposer = proposer_future
168 .await
169 .map_err(
170 |e| tracing::error!(target: LOG_TARGET, error = ?e, "Could not create proposer."),
171 )
172 .ok()?;
173
174 let inherent_data =
175 self.inherent_data(parent.hash(), validation_data, relay_parent).await?;
176
177 let Proposal { block, storage_changes, proof } = proposer
178 .propose(
179 inherent_data,
180 Default::default(),
181 Duration::from_millis(500),
183 Some((validation_data.max_pov_size / 2) as usize),
188 )
189 .await
190 .map_err(|e| tracing::error!(target: LOG_TARGET, error = ?e, "Proposing failed."))
191 .ok()?;
192
193 let (header, extrinsics) = block.clone().deconstruct();
194
195 let mut block_import_params = BlockImportParams::new(BlockOrigin::Own, header);
196 block_import_params.body = Some(extrinsics);
197 block_import_params.state_action = sc_consensus::StateAction::ApplyChanges(
198 sc_consensus::StorageChanges::Changes(storage_changes),
199 );
200
201 if let Err(err) = self.block_import.lock().await.import_block(block_import_params).await {
202 tracing::error!(
203 target: LOG_TARGET,
204 at = ?parent.hash(),
205 error = ?err,
206 "Error importing build block.",
207 );
208
209 return None
210 }
211
212 Some(ParachainCandidate { block, proof })
213 }
214}
215
216pub struct BuildRelayChainConsensusParams<PF, BI, CIDP, RCInterface> {
218 pub para_id: ParaId,
219 pub proposer_factory: PF,
220 pub create_inherent_data_providers: CIDP,
221 pub block_import: BI,
222 pub relay_chain_interface: RCInterface,
223}
224
225pub fn build_relay_chain_consensus<Block, PF, BI, CIDP, RCInterface>(
229 BuildRelayChainConsensusParams {
230 para_id,
231 proposer_factory,
232 create_inherent_data_providers,
233 block_import,
234 relay_chain_interface,
235 }: BuildRelayChainConsensusParams<PF, BI, CIDP, RCInterface>,
236) -> Box<dyn ParachainConsensus<Block>>
237where
238 Block: BlockT,
239 PF: Environment<Block> + Send + Sync + 'static,
240 PF::Proposer: Proposer<
241 Block,
242 ProofRecording = EnableProofRecording,
243 Proof = <EnableProofRecording as ProofRecording>::Proof,
244 >,
245 BI: BlockImport<Block> + ParachainBlockImportMarker + Send + Sync + 'static,
246 CIDP: CreateInherentDataProviders<Block, (PHash, PersistedValidationData)> + 'static,
247 RCInterface: RelayChainInterface + Clone + 'static,
248{
249 Box::new(RelayChainConsensus::new(
250 para_id,
251 proposer_factory,
252 create_inherent_data_providers,
253 block_import,
254 relay_chain_interface,
255 ))
256}