1use crate::Client;
18use codec::Encode;
19use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
20use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER};
21use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
22use cumulus_test_runtime::{Block, GetLastTimestamp, Hash, Header};
23use polkadot_primitives::{BlockNumber as PBlockNumber, Hash as PHash};
24use sc_block_builder::BlockBuilderBuilder;
25use sp_api::{ProofRecorder, ProofRecorderIgnoredNodes, ProvideRuntimeApi};
26use sp_consensus_aura::{AuraApi, Slot};
27use sp_runtime::{traits::Header as HeaderT, Digest, DigestItem};
28
29pub struct BlockBuilderAndSupportData<'a> {
31 pub block_builder: sc_block_builder::BlockBuilder<'a, Block, Client>,
32 pub persisted_validation_data: PersistedValidationData<PHash, PBlockNumber>,
33}
34
35pub trait InitBlockBuilder {
37 fn init_block_builder(
48 &self,
49 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
50 relay_sproof_builder: RelayStateSproofBuilder,
51 ) -> BlockBuilderAndSupportData;
52
53 fn init_block_builder_at(
58 &self,
59 at: Hash,
60 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
61 relay_sproof_builder: RelayStateSproofBuilder,
62 ) -> BlockBuilderAndSupportData;
63
64 fn init_block_builder_with_pre_digests(
69 &self,
70 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
71 relay_sproof_builder: RelayStateSproofBuilder,
72 pre_digests: Vec<DigestItem>,
73 ) -> BlockBuilderAndSupportData;
74 fn init_block_builder_with_ignored_nodes(
79 &self,
80 at: Hash,
81 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
82 relay_sproof_builder: RelayStateSproofBuilder,
83 timestamp: u64,
84 ignored_nodes: ProofRecorderIgnoredNodes<Block>,
85 ) -> BlockBuilderAndSupportData;
86
87 fn init_block_builder_with_timestamp(
93 &self,
94 at: Hash,
95 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
96 relay_sproof_builder: RelayStateSproofBuilder,
97 timestamp: u64,
98 ) -> BlockBuilderAndSupportData;
99}
100
101fn init_block_builder(
102 client: &Client,
103 at: Hash,
104 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
105 mut relay_sproof_builder: RelayStateSproofBuilder,
106 timestamp: Option<u64>,
107 extra_pre_digests: Option<Vec<DigestItem>>,
108 ignored_nodes: Option<ProofRecorderIgnoredNodes<Block>>,
109) -> BlockBuilderAndSupportData<'_> {
110 let timestamp = timestamp.unwrap_or_else(|| {
111 let last_timestamp =
112 client.runtime_api().get_last_timestamp(at).expect("Get last timestamp");
113
114 if last_timestamp == 0 {
115 if relay_sproof_builder.current_slot != 0u64 {
116 *relay_sproof_builder.current_slot * 6_000
117 } else {
118 std::time::SystemTime::now()
119 .duration_since(std::time::SystemTime::UNIX_EPOCH)
120 .expect("Time is always after UNIX_EPOCH; qed")
121 .as_millis() as u64
122 }
123 } else {
124 last_timestamp + client.runtime_api().slot_duration(at).unwrap().as_millis()
125 }
126 });
127
128 let slot: Slot =
129 (timestamp / client.runtime_api().slot_duration(at).unwrap().as_millis()).into();
130
131 if relay_sproof_builder.current_slot == 0u64 {
132 relay_sproof_builder.current_slot = (timestamp / 6_000).into();
133 }
134
135 let pre_digests = Digest {
136 logs: extra_pre_digests
137 .unwrap_or_default()
138 .into_iter()
139 .chain(std::iter::once(DigestItem::PreRuntime(
140 sp_consensus_aura::AURA_ENGINE_ID,
141 slot.encode(),
142 )))
143 .collect::<Vec<_>>(),
144 };
145
146 let mut block_builder = BlockBuilderBuilder::new(client)
147 .on_parent_block(at)
148 .fetch_parent_block_number(client)
149 .unwrap()
150 .with_proof_recorder(Some(ProofRecorder::<Block>::with_ignored_nodes(
151 ignored_nodes.unwrap_or_default(),
152 )))
153 .with_inherent_digests(pre_digests)
154 .build()
155 .expect("Creates new block builder for test runtime");
156
157 let mut inherent_data = sp_inherents::InherentData::new();
158
159 inherent_data
160 .put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp)
161 .expect("Put timestamp failed");
162
163 let (relay_parent_storage_root, relay_chain_state) =
164 relay_sproof_builder.into_state_root_and_proof();
165
166 let mut validation_data = validation_data.unwrap_or_default();
167 validation_data.relay_parent_storage_root = relay_parent_storage_root;
168
169 inherent_data
170 .put_data(
171 INHERENT_IDENTIFIER,
172 &ParachainInherentData {
173 validation_data: validation_data.clone(),
174 relay_chain_state,
175 downward_messages: Default::default(),
176 horizontal_messages: Default::default(),
177 relay_parent_descendants: Default::default(),
178 collator_peer_id: None,
179 },
180 )
181 .expect("Put validation function params failed");
182
183 let inherents = block_builder.create_inherents(inherent_data).expect("Creates inherents");
184
185 inherents
186 .into_iter()
187 .for_each(|ext| block_builder.push(ext).expect("Pushes inherent"));
188
189 BlockBuilderAndSupportData { block_builder, persisted_validation_data: validation_data }
190}
191
192impl InitBlockBuilder for Client {
193 fn init_block_builder(
194 &self,
195 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
196 relay_sproof_builder: RelayStateSproofBuilder,
197 ) -> BlockBuilderAndSupportData {
198 let chain_info = self.chain_info();
199 self.init_block_builder_at(chain_info.best_hash, validation_data, relay_sproof_builder)
200 }
201
202 fn init_block_builder_with_pre_digests(
203 &self,
204 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
205 relay_sproof_builder: RelayStateSproofBuilder,
206 pre_digests: Vec<DigestItem>,
207 ) -> BlockBuilderAndSupportData {
208 let chain_info = self.chain_info();
209 init_block_builder(
210 self,
211 chain_info.best_hash,
212 validation_data,
213 relay_sproof_builder,
214 None,
215 Some(pre_digests),
216 None,
217 )
218 }
219
220 fn init_block_builder_at(
221 &self,
222 at: Hash,
223 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
224 relay_sproof_builder: RelayStateSproofBuilder,
225 ) -> BlockBuilderAndSupportData {
226 init_block_builder(self, at, validation_data, relay_sproof_builder, None, None, None)
227 }
228
229 fn init_block_builder_with_ignored_nodes(
230 &self,
231 at: Hash,
232 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
233 relay_sproof_builder: RelayStateSproofBuilder,
234 timestamp: u64,
235 ignored_nodes: ProofRecorderIgnoredNodes<Block>,
236 ) -> BlockBuilderAndSupportData {
237 init_block_builder(
238 self,
239 at,
240 validation_data,
241 relay_sproof_builder,
242 Some(timestamp),
243 None,
244 Some(ignored_nodes),
245 )
246 }
247
248 fn init_block_builder_with_timestamp(
249 &self,
250 at: Hash,
251 validation_data: Option<PersistedValidationData<PHash, PBlockNumber>>,
252 relay_sproof_builder: RelayStateSproofBuilder,
253 timestamp: u64,
254 ) -> BlockBuilderAndSupportData {
255 init_block_builder(
256 self,
257 at,
258 validation_data,
259 relay_sproof_builder,
260 Some(timestamp),
261 None,
262 None,
263 )
264 }
265}
266
267pub trait BuildParachainBlockData {
270 fn build_parachain_block(self, parent_state_root: Hash) -> ParachainBlockData<Block>;
273}
274
275impl<'a> BuildParachainBlockData for sc_block_builder::BlockBuilder<'a, Block, Client> {
276 fn build_parachain_block(self, parent_state_root: Hash) -> ParachainBlockData<Block> {
277 let built_block = self.build().expect("Builds the block");
278
279 let storage_proof = built_block
280 .proof
281 .expect("We enabled proof recording before.")
282 .into_compact_proof::<<Header as HeaderT>::Hashing>(parent_state_root)
283 .expect("Creates the compact proof");
284
285 ParachainBlockData::new(vec![built_block.block], storage_proof)
286 }
287}