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