1#![warn(missing_docs)]
28
29mod custom_api;
30mod genesis_block_builder;
31
32use crate::custom_api::{TrieBackendApi, TrieDeltaBackendFor};
33pub use custom_api::{CollectedStorageChanges, DeltaBackend, create_delta_backend};
34pub use genesis_block_builder::CustomGenesisBlockBuilder;
35use parity_scale_codec::Encode;
36use sc_client_api::{ExecutorProvider, backend};
37use sp_api::{ProvideRuntimeApi, TransactionOutcome};
38pub use sp_block_builder::BlockBuilder as BlockBuilderApi;
39use sp_blockchain::{ApplyExtrinsicFailed, Error};
40use sp_core::traits::CodeExecutor;
41use sp_runtime::Digest;
42use sp_runtime::traits::{Block as BlockT, Hash, HashingFor, Header as HeaderT, NumberFor, One};
43use sp_state_machine::OverlayedChanges;
44use std::collections::VecDeque;
45use std::sync::Arc;
46
47pub struct BuiltBlock<Block: BlockT> {
52 pub block: Block,
54 pub storage_changes: CollectedStorageChanges<HashingFor<Block>>,
56}
57
58impl<Block: BlockT> BuiltBlock<Block> {
59 pub fn into_inner(self) -> (Block, CollectedStorageChanges<HashingFor<Block>>) {
61 (self.block, self.storage_changes)
62 }
63}
64
65pub struct BlockBuilder<Client, Block: BlockT, Backend: backend::Backend<Block>, Exec> {
67 extrinsics: VecDeque<Block::Extrinsic>,
68 api: TrieBackendApi<Client, Block, Backend, Exec>,
69}
70
71impl<Client, Block, Backend, Exec> BlockBuilder<Client, Block, Backend, Exec>
72where
73 Block: BlockT,
74 Client: ProvideRuntimeApi<Block> + ExecutorProvider<Block>,
75 Client::Api: BlockBuilderApi<Block>,
76 Backend: backend::Backend<Block>,
77 Exec: CodeExecutor,
78{
79 #[allow(clippy::too_many_arguments)]
85 pub fn new(
86 client: Arc<Client>,
87 parent_hash: Block::Hash,
88 parent_number: NumberFor<Block>,
89 inherent_digests: Digest,
90 backend: Arc<Backend>,
91 exec: Arc<Exec>,
92 mut extrinsics: VecDeque<Block::Extrinsic>,
93 maybe_inherent_data: Option<sp_inherents::InherentData>,
94 ) -> Result<Self, Error> {
95 let mut api = TrieBackendApi::new(parent_hash, parent_number, client, backend, exec)?;
96 let header = <Block::Header as HeaderT>::new(
97 parent_number + One::one(),
98 Default::default(),
99 Default::default(),
100 parent_hash,
101 inherent_digests,
102 );
103
104 api.execute_in_transaction(
105 |api: &TrieBackendApi<Client, Block, Backend, Exec>,
106 backend: &TrieDeltaBackendFor<Backend::State, Block>,
107 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>| {
108 match api.initialize_block(header, backend, overlayed_changes) {
109 Ok(_) => TransactionOutcome::Commit(Ok(())),
110 Err(e) => TransactionOutcome::Rollback(Err(e)),
111 }
112 },
113 )?;
114
115 if let Some(inherent_data) = maybe_inherent_data {
116 let inherent_extrinsics = Self::create_inherents(&mut api, inherent_data)?;
117
118 for inherent_extrinsic in inherent_extrinsics.into_iter().rev() {
120 extrinsics.push_front(inherent_extrinsic)
121 }
122 }
123
124 Ok(Self { extrinsics, api })
125 }
126
127 fn execute_extrinsics(&mut self) -> Result<(), Error> {
129 for (index, xt) in self.extrinsics.iter().enumerate() {
130 let res = self.api.execute_in_transaction(
131 |api: &TrieBackendApi<Client, Block, Backend, Exec>,
132 backend: &TrieDeltaBackendFor<Backend::State, Block>,
133 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>| {
134 match api.apply_extrinsic(xt.clone(), backend, overlayed_changes) {
135 Ok(Ok(_)) => TransactionOutcome::Commit(Ok(())),
136 Ok(Err(tx_validity)) => TransactionOutcome::Rollback(Err(
137 ApplyExtrinsicFailed::Validity(tx_validity).into(),
138 )),
139 Err(e) => TransactionOutcome::Rollback(Err(e)),
140 }
141 },
142 );
143
144 if let Err(e) = res {
145 tracing::debug!("Apply extrinsic at index {index} failed: {e}");
146 }
147 }
148
149 Ok(())
150 }
151
152 fn collect_storage_changes(&mut self) -> Option<CollectedStorageChanges<HashingFor<Block>>> {
153 self.api.collect_storage_changes()
154 }
155
156 pub fn prepare_storage_changes_before(
158 &mut self,
159 extrinsic_index: usize,
160 ) -> Result<CollectedStorageChanges<HashingFor<Block>>, Error> {
161 for (index, xt) in self.extrinsics.iter().enumerate() {
162 if index == extrinsic_index {
163 return self
164 .collect_storage_changes()
165 .ok_or(Error::Execution(Box::new("No execution is done")));
166 }
167
168 self.api.execute_in_transaction(
170 |api: &TrieBackendApi<Client, Block, Backend, Exec>,
171 backend: &TrieDeltaBackendFor<Backend::State, Block>,
172 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>| {
173 match api.apply_extrinsic(xt.clone(), backend, overlayed_changes) {
174 Ok(Ok(_)) => TransactionOutcome::Commit(Ok(())),
175 Ok(Err(tx_validity)) => TransactionOutcome::Rollback(Err(
176 ApplyExtrinsicFailed::Validity(tx_validity).into(),
177 )),
178 Err(e) => TransactionOutcome::Rollback(Err(e)),
179 }
180 },
181 )?;
182 }
183
184 Err(Error::Execution(Box::new(format!(
185 "Invalid extrinsic index, got: {}, max: {}",
186 extrinsic_index,
187 self.extrinsics.len()
188 ))))
189 }
190
191 pub fn prepare_storage_changes_before_finalize_block(
193 &mut self,
194 ) -> Result<CollectedStorageChanges<HashingFor<Block>>, Error> {
195 self.execute_extrinsics()?;
196 self.collect_storage_changes()
197 .ok_or(Error::Execution(Box::new("No execution is done")))
198 }
199
200 pub fn build(mut self) -> Result<BuiltBlock<Block>, Error> {
206 self.execute_extrinsics()?;
207 let header = self.api.execute_in_transaction(
208 |api: &TrieBackendApi<Client, Block, Backend, Exec>,
209 backend: &TrieDeltaBackendFor<Backend::State, Block>,
210 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>| {
211 match api.finalize_block(backend, overlayed_changes) {
212 Ok(header) => TransactionOutcome::Commit(Ok(header)),
213 Err(e) => TransactionOutcome::Rollback(Err(e)),
214 }
215 },
216 )?;
217
218 debug_assert_eq!(
219 header.extrinsics_root().clone(),
220 HashingFor::<Block>::ordered_trie_root(
221 self.extrinsics.iter().map(Encode::encode).collect(),
222 sp_core::storage::StateVersion::V1
223 ),
224 );
225
226 let storage_changes = self
227 .collect_storage_changes()
228 .expect("must always have the storage changes due to execution above");
229
230 Ok(BuiltBlock {
231 block: Block::new(header, self.extrinsics.into()),
232 storage_changes,
233 })
234 }
235
236 pub(crate) fn create_inherents(
240 api: &mut TrieBackendApi<Client, Block, Backend, Exec>,
241 inherent_data: sp_inherents::InherentData,
242 ) -> Result<VecDeque<Block::Extrinsic>, Error> {
243 let exts = api.execute_in_transaction(
244 |api: &TrieBackendApi<Client, Block, Backend, Exec>,
245 backend: &TrieDeltaBackendFor<Backend::State, Block>,
246 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>| {
247 TransactionOutcome::Rollback(api.inherent_extrinsics(
250 inherent_data,
251 backend,
252 overlayed_changes,
253 ))
254 },
255 )?;
256 Ok(VecDeque::from(exts))
257 }
258}
259
260