sc_consensus_manual_seal/
seal_block.rs1use crate::{rpc, ConsensusDataProvider, CreatedBlock, Error};
22use codec::Encode;
23use futures::prelude::*;
24use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction};
25use sc_transaction_pool_api::TransactionPool;
26use sp_api::{ProofRecorder, ProvideRuntimeApi};
27use sp_blockchain::HeaderBackend;
28use sp_consensus::{self, BlockOrigin, Environment, ProposeArgs, Proposer, SelectChain};
29use sp_externalities::Extensions;
30use sp_inherents::{CreateInherentDataProviders, InherentDataProvider};
31use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
32use sp_trie::proof_size_extension::ProofSizeExt;
33use std::{sync::Arc, time::Duration};
34
35pub const MAX_PROPOSAL_DURATION: u64 = 10;
37
38pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi<B>, E, TP, CIDP> {
40 pub create_empty: bool,
43 pub finalize: bool,
45 pub parent_hash: Option<<B as BlockT>::Hash>,
47 pub sender: rpc::Sender<CreatedBlock<<B as BlockT>::Hash>>,
49 pub pool: Arc<TP>,
51 pub client: Arc<C>,
53 pub env: &'a mut E,
55 pub select_chain: &'a SC,
57 pub consensus_data_provider: Option<&'a dyn ConsensusDataProvider<B>>,
59 pub block_import: &'a mut BI,
61 pub create_inherent_data_providers: &'a CIDP,
63}
64
65pub async fn seal_block<B, BI, SC, C, E, TP, CIDP>(
67 SealBlockParams {
68 create_empty,
69 finalize,
70 pool,
71 parent_hash,
72 client,
73 select_chain,
74 block_import,
75 env,
76 create_inherent_data_providers,
77 consensus_data_provider: digest_provider,
78 mut sender,
79 }: SealBlockParams<'_, B, BI, SC, C, E, TP, CIDP>,
80) where
81 B: BlockT,
82 BI: BlockImport<B, Error = sp_consensus::Error> + Send + Sync + 'static,
83 C: HeaderBackend<B> + ProvideRuntimeApi<B>,
84 E: Environment<B>,
85 E::Proposer: Proposer<B>,
86 TP: TransactionPool<Block = B>,
87 SC: SelectChain<B>,
88 CIDP: CreateInherentDataProviders<B, ()>,
89{
90 let future = async {
91 if pool.status().ready == 0 && !create_empty {
92 return Err(Error::EmptyTransactionPool)
93 }
94
95 let parent = match parent_hash {
99 Some(hash) =>
100 client.header(hash)?.ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?,
101 None => select_chain.best_chain().await?,
102 };
103
104 let inherent_data_providers = create_inherent_data_providers
105 .create_inherent_data_providers(parent.hash(), ())
106 .await
107 .map_err(|e| Error::Other(e))?;
108
109 let inherent_data = inherent_data_providers.create_inherent_data().await?;
110
111 let proposer = env.init(&parent).map_err(|err| Error::StringError(err.to_string())).await?;
112 let inherents_len = inherent_data.len();
113
114 let inherent_digests = if let Some(digest_provider) = digest_provider {
115 digest_provider.create_digest(&parent, &inherent_data)?
116 } else {
117 Default::default()
118 };
119
120 let storage_proof_recorder = ProofRecorder::<B>::default();
121
122 let mut extra_extensions = Extensions::default();
123 extra_extensions.register(ProofSizeExt::new(storage_proof_recorder.clone()));
125
126 let propose_args = ProposeArgs {
127 inherent_data: inherent_data.clone(),
128 inherent_digests,
129 max_duration: Duration::from_secs(MAX_PROPOSAL_DURATION),
130 storage_proof_recorder: Some(storage_proof_recorder.clone()),
131 extra_extensions,
132 ..Default::default()
133 };
134
135 let proposal = proposer
136 .propose(propose_args)
137 .map_err(|err| Error::StringError(err.to_string()))
138 .await?;
139
140 if proposal.block.extrinsics().len() == inherents_len && !create_empty {
141 return Err(Error::EmptyTransactionPool)
142 }
143
144 let proof = storage_proof_recorder.drain_storage_proof();
145
146 let (header, body) = proposal.block.deconstruct();
147 let proof_size = proof.encoded_size();
148 let mut params = BlockImportParams::new(BlockOrigin::Own, header.clone());
149 params.body = Some(body);
150 params.finalized = finalize;
151 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
152 params.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(
153 proposal.storage_changes,
154 ));
155
156 if let Some(digest_provider) = digest_provider {
157 digest_provider.append_block_import(&parent, &mut params, &inherent_data, proof)?;
158 }
159
160 let mut post_header = header.clone();
163 post_header.digest_mut().logs.extend(params.post_digests.iter().cloned());
164
165 match block_import.import_block(params).await? {
166 ImportResult::Imported(aux) => Ok(CreatedBlock {
167 hash: <B as BlockT>::Header::hash(&post_header),
168 aux,
169 proof_size,
170 }),
171 other => Err(other.into()),
172 }
173 };
174
175 rpc::send_result(&mut sender, future.await)
176}