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 },
102 None => select_chain.best_chain().await?,
103 };
104
105 let inherent_data_providers = create_inherent_data_providers
106 .create_inherent_data_providers(parent.hash(), ())
107 .await
108 .map_err(|e| Error::Other(e))?;
109
110 let inherent_data = inherent_data_providers.create_inherent_data().await?;
111
112 let proposer = env.init(&parent).map_err(|err| Error::StringError(err.to_string())).await?;
113 let inherents_len = inherent_data.len();
114
115 let inherent_digests = if let Some(digest_provider) = digest_provider {
116 digest_provider.create_digest(&parent, &inherent_data)?
117 } else {
118 Default::default()
119 };
120
121 let storage_proof_recorder = ProofRecorder::<B>::default();
122
123 let mut extra_extensions = Extensions::default();
124 extra_extensions.register(ProofSizeExt::new(storage_proof_recorder.clone()));
126
127 let propose_args = ProposeArgs {
128 inherent_data: inherent_data.clone(),
129 inherent_digests,
130 max_duration: Duration::from_secs(MAX_PROPOSAL_DURATION),
131 storage_proof_recorder: Some(storage_proof_recorder.clone()),
132 extra_extensions,
133 ..Default::default()
134 };
135
136 let proposal = proposer
137 .propose(propose_args)
138 .map_err(|err| Error::StringError(err.to_string()))
139 .await?;
140
141 if proposal.block.extrinsics().len() == inherents_len && !create_empty {
142 return Err(Error::EmptyTransactionPool);
143 }
144
145 let proof = storage_proof_recorder.drain_storage_proof();
146
147 let (header, body) = proposal.block.deconstruct();
148 let proof_size = proof.encoded_size();
149 let mut params = BlockImportParams::new(BlockOrigin::Own, header.clone());
150 params.body = Some(body);
151 params.finalized = finalize;
152 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
153 params.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(
154 proposal.storage_changes,
155 ));
156
157 if let Some(digest_provider) = digest_provider {
158 digest_provider.append_block_import(&parent, &mut params, &inherent_data, proof)?;
159 }
160
161 let mut post_header = header.clone();
164 post_header.digest_mut().logs.extend(params.post_digests.iter().cloned());
165
166 match block_import.import_block(params).await? {
167 ImportResult::Imported(aux) => Ok(CreatedBlock {
168 hash: <B as BlockT>::Header::hash(&post_header),
169 aux,
170 proof_size,
171 }),
172 other => Err(other.into()),
173 }
174 };
175
176 rpc::send_result(&mut sender, future.await)
177}