soil_client/block_builder/
mod.rs1#![warn(missing_docs)]
16
17use codec::Encode;
18
19use crate::blockchain::{ApplyExtrinsicFailed, Error, HeaderBackend};
20use std::marker::PhantomData;
21use subsoil::api::{
22 ApiExt, ApiRef, CallApiAt, Core, ProofRecorder, ProvideRuntimeApi, StorageChanges,
23 TransactionOutcome,
24};
25use subsoil::core::traits::CallContext;
26use subsoil::externalities::Extensions;
27use subsoil::runtime::{
28 legacy,
29 traits::{Block as BlockT, Hash, HashingFor, Header as HeaderT, NumberFor, One},
30 Digest, ExtrinsicInclusionMode,
31};
32
33pub use subsoil::block_builder::BlockBuilder as BlockBuilderApi;
34
35pub struct BlockBuilderBuilder<'a, B, C> {
37 call_api_at: &'a C,
38 _phantom: PhantomData<B>,
39}
40
41impl<'a, B, C> BlockBuilderBuilder<'a, B, C>
42where
43 B: BlockT,
44{
45 pub fn new(call_api_at: &'a C) -> Self {
49 Self { call_api_at, _phantom: PhantomData }
50 }
51
52 pub fn on_parent_block(self, parent_block: B::Hash) -> BlockBuilderBuilderStage1<'a, B, C> {
54 BlockBuilderBuilderStage1 { call_api_at: self.call_api_at, parent_block }
55 }
56}
57
58pub struct BlockBuilderBuilderStage1<'a, B: BlockT, C> {
63 call_api_at: &'a C,
64 parent_block: B::Hash,
65}
66
67impl<'a, B, C> BlockBuilderBuilderStage1<'a, B, C>
68where
69 B: BlockT,
70{
71 pub fn fetch_parent_block_number<H: HeaderBackend<B>>(
78 self,
79 header_backend: &H,
80 ) -> Result<BlockBuilderBuilderStage2<'a, B, C>, Error> {
81 let parent_number = header_backend.number(self.parent_block)?.ok_or_else(|| {
82 Error::Backend(format!(
83 "Could not fetch block number for block: {:?}",
84 self.parent_block
85 ))
86 })?;
87
88 Ok(BlockBuilderBuilderStage2 {
89 call_api_at: self.call_api_at,
90 proof_recorder: None,
91 inherent_digests: Default::default(),
92 parent_block: self.parent_block,
93 parent_number,
94 extra_extensions: Extensions::new(),
95 })
96 }
97
98 pub fn with_parent_block_number(
103 self,
104 parent_number: NumberFor<B>,
105 ) -> BlockBuilderBuilderStage2<'a, B, C> {
106 BlockBuilderBuilderStage2 {
107 call_api_at: self.call_api_at,
108 proof_recorder: None,
109 inherent_digests: Default::default(),
110 parent_block: self.parent_block,
111 parent_number,
112 extra_extensions: Extensions::new(),
113 }
114 }
115}
116
117pub struct BlockBuilderBuilderStage2<'a, B: BlockT, C> {
122 call_api_at: &'a C,
123 proof_recorder: Option<ProofRecorder<B>>,
124 inherent_digests: Digest,
125 parent_block: B::Hash,
126 parent_number: NumberFor<B>,
127 extra_extensions: Extensions,
128}
129
130impl<'a, B: BlockT, C> BlockBuilderBuilderStage2<'a, B, C> {
131 pub fn with_proof_recorder(
133 mut self,
134 proof_recorder: impl Into<Option<ProofRecorder<B>>>,
135 ) -> Self {
136 self.proof_recorder = proof_recorder.into();
137 self
138 }
139
140 pub fn enable_proof_recording(mut self) -> Self {
142 self.proof_recorder = Some(Default::default());
143 self
144 }
145
146 pub fn with_inherent_digests(mut self, inherent_digests: Digest) -> Self {
148 self.inherent_digests = inherent_digests;
149 self
150 }
151
152 pub fn with_extra_extensions(mut self, extra_extensions: impl Into<Extensions>) -> Self {
154 self.extra_extensions = extra_extensions.into();
155 self
156 }
157
158 pub fn build(self) -> Result<BlockBuilder<'a, B, C>, Error>
160 where
161 C: CallApiAt<B> + ProvideRuntimeApi<B>,
162 C::Api: BlockBuilderApi<B>,
163 {
164 BlockBuilder::new(
165 self.call_api_at,
166 self.parent_block,
167 self.parent_number,
168 self.proof_recorder,
169 self.inherent_digests,
170 self.extra_extensions,
171 )
172 }
173}
174
175pub struct BuiltBlock<Block: BlockT> {
180 pub block: Block,
182 pub storage_changes: StorageChanges<Block>,
184}
185
186impl<Block: BlockT> BuiltBlock<Block> {
187 pub fn into_inner(self) -> (Block, StorageChanges<Block>) {
189 (self.block, self.storage_changes)
190 }
191}
192
193pub struct BlockBuilder<'a, Block: BlockT, C: ProvideRuntimeApi<Block> + 'a> {
195 extrinsics: Vec<Block::Extrinsic>,
196 api: ApiRef<'a, C::Api>,
197 call_api_at: &'a C,
198 version: u32,
200 parent_hash: Block::Hash,
201 estimated_header_size: usize,
203 extrinsic_inclusion_mode: ExtrinsicInclusionMode,
204}
205
206impl<'a, Block, C> BlockBuilder<'a, Block, C>
207where
208 Block: BlockT,
209 C: CallApiAt<Block> + ProvideRuntimeApi<Block> + 'a,
210 C::Api: BlockBuilderApi<Block>,
211{
212 fn new(
218 call_api_at: &'a C,
219 parent_hash: Block::Hash,
220 parent_number: NumberFor<Block>,
221 proof_recorder: Option<ProofRecorder<Block>>,
222 inherent_digests: Digest,
223 extra_extensions: Extensions,
224 ) -> Result<Self, Error> {
225 let header = <<Block as BlockT>::Header as HeaderT>::new(
226 parent_number + One::one(),
227 Default::default(),
228 Default::default(),
229 parent_hash,
230 inherent_digests,
231 );
232
233 let estimated_header_size = header.encoded_size();
234
235 let mut api = call_api_at.runtime_api();
236
237 if let Some(recorder) = proof_recorder {
238 api.record_proof_with_recorder(recorder);
239 }
240
241 extra_extensions.into_extensions().for_each(|e| {
242 api.register_extension(e);
243 });
244
245 api.set_call_context(CallContext::Onchain);
246
247 let core_version = api
248 .api_version::<dyn Core<Block>>(parent_hash)?
249 .ok_or_else(|| Error::VersionInvalid("Core".to_string()))?;
250
251 let extrinsic_inclusion_mode = if core_version >= 5 {
252 api.initialize_block(parent_hash, &header)?
253 } else {
254 #[allow(deprecated)]
255 api.initialize_block_before_version_5(parent_hash, &header)?;
256 ExtrinsicInclusionMode::AllExtrinsics
257 };
258
259 let bb_version = api
260 .api_version::<dyn BlockBuilderApi<Block>>(parent_hash)?
261 .ok_or_else(|| Error::VersionInvalid("BlockBuilderApi".to_string()))?;
262
263 Ok(Self {
264 parent_hash,
265 extrinsics: Vec::new(),
266 api,
267 version: bb_version,
268 estimated_header_size,
269 call_api_at,
270 extrinsic_inclusion_mode,
271 })
272 }
273
274 pub fn extrinsic_inclusion_mode(&self) -> ExtrinsicInclusionMode {
276 self.extrinsic_inclusion_mode
277 }
278
279 pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> Result<(), Error> {
283 let parent_hash = self.parent_hash;
284 let extrinsics = &mut self.extrinsics;
285 let version = self.version;
286
287 self.api.execute_in_transaction(|api| {
288 let res = if version < 6 {
289 #[allow(deprecated)]
290 api.apply_extrinsic_before_version_6(parent_hash, xt.clone())
291 .map(legacy::byte_sized_error::convert_to_latest)
292 } else {
293 api.apply_extrinsic(parent_hash, xt.clone())
294 };
295
296 match res {
297 Ok(Ok(_)) => {
298 extrinsics.push(xt);
299 TransactionOutcome::Commit(Ok(()))
300 },
301 Ok(Err(tx_validity)) => TransactionOutcome::Rollback(Err(
302 ApplyExtrinsicFailed::Validity(tx_validity).into(),
303 )),
304 Err(e) => TransactionOutcome::Rollback(Err(Error::from(e))),
305 }
306 })
307 }
308
309 pub fn build(self) -> Result<BuiltBlock<Block>, Error> {
315 let header = self.api.finalize_block(self.parent_hash)?;
316
317 debug_assert_eq!(
318 header.extrinsics_root().clone(),
319 HashingFor::<Block>::ordered_trie_root(
320 self.extrinsics.iter().map(Encode::encode).collect(),
321 self.api.version(self.parent_hash)?.extrinsics_root_state_version(),
322 ),
323 );
324
325 let state = self.call_api_at.state_at(self.parent_hash)?;
326
327 let storage_changes = self
328 .api
329 .into_storage_changes(&state, self.parent_hash)
330 .map_err(crate::blockchain::Error::StorageChanges)?;
331
332 Ok(BuiltBlock { block: <Block as BlockT>::new(header, self.extrinsics), storage_changes })
333 }
334
335 pub fn create_inherents(
339 &mut self,
340 inherent_data: subsoil::inherents::InherentData,
341 ) -> Result<Vec<Block::Extrinsic>, Error> {
342 let parent_hash = self.parent_hash;
343 self.api
344 .execute_in_transaction(move |api| {
345 TransactionOutcome::Rollback(api.inherent_extrinsics(parent_hash, inherent_data))
348 })
349 .map_err(|e| Error::Application(Box::new(e)))
350 }
351
352 pub fn estimate_block_size(&self) -> usize {
357 let size = self.estimated_header_size + self.extrinsics.encoded_size();
358
359 size + self.api.proof_recorder().map_or(0, |pr| pr.estimate_encoded_size())
360 }
361
362 pub fn proof_recorder(&self) -> Option<ProofRecorder<Block>> {
364 self.api.proof_recorder()
365 }
366}
367
368