cumulus_client_parachain_inherent/
mock.rs1use crate::ParachainInherentData;
18use codec::Decode;
19use cumulus_primitives_core::{
20 relay_chain,
21 relay_chain::{Slot, UpgradeGoAhead},
22 InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
23};
24use cumulus_primitives_parachain_inherent::MessageQueueChain;
25use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
26use sc_client_api::{Backend, StorageProvider};
27use sp_crypto_hashing::twox_128;
28use sp_inherents::{InherentData, InherentDataProvider};
29use sp_runtime::traits::Block;
30use std::collections::BTreeMap;
31
32#[derive(Default)]
47pub struct MockValidationDataInherentDataProvider<R = ()> {
48 pub current_para_block: u32,
50 pub para_id: ParaId,
52 pub current_para_block_head: Option<cumulus_primitives_core::relay_chain::HeadData>,
54 pub relay_offset: u32,
57 pub relay_blocks_per_para_block: u32,
60 pub para_blocks_per_relay_epoch: u32,
63 pub relay_randomness_config: R,
65 pub xcm_config: MockXcmConfig,
67 pub raw_downward_messages: Vec<Vec<u8>>,
69 pub raw_horizontal_messages: Vec<(ParaId, Vec<u8>)>,
71 pub additional_key_values: Option<Vec<(Vec<u8>, Vec<u8>)>>,
73 pub upgrade_go_ahead: Option<UpgradeGoAhead>,
75}
76
77pub trait GenerateRandomness<I> {
79 fn generate_randomness(&self, input: I) -> relay_chain::Hash;
81}
82
83impl GenerateRandomness<u64> for () {
84 fn generate_randomness(&self, input: u64) -> relay_chain::Hash {
87 let mut mock_randomness: [u8; 32] = [0u8; 32];
88 mock_randomness[..8].copy_from_slice(&input.to_be_bytes());
89 mock_randomness.into()
90 }
91}
92
93#[derive(Default)]
98pub struct MockXcmConfig {
99 pub starting_dmq_mqc_head: relay_chain::Hash,
101 pub starting_hrmp_mqc_heads: BTreeMap<ParaId, relay_chain::Hash>,
103}
104
105pub struct ParachainSystemName(pub Vec<u8>);
112
113impl Default for ParachainSystemName {
114 fn default() -> Self {
115 Self(b"ParachainSystem".to_vec())
116 }
117}
118
119impl MockXcmConfig {
120 pub fn new<B: Block, BE: Backend<B>, C: StorageProvider<B, BE>>(
123 client: &C,
124 parent_block: B::Hash,
125 parachain_system_name: ParachainSystemName,
126 ) -> Self {
127 let starting_dmq_mqc_head = client
128 .storage(
129 parent_block,
130 &sp_storage::StorageKey(
131 [twox_128(¶chain_system_name.0), twox_128(b"LastDmqMqcHead")]
132 .concat()
133 .to_vec(),
134 ),
135 )
136 .expect("We should be able to read storage from the parent block.")
137 .map(|ref mut raw_data| {
138 Decode::decode(&mut &raw_data.0[..]).expect("Stored data should decode correctly")
139 })
140 .unwrap_or_default();
141
142 let starting_hrmp_mqc_heads = client
143 .storage(
144 parent_block,
145 &sp_storage::StorageKey(
146 [twox_128(¶chain_system_name.0), twox_128(b"LastHrmpMqcHeads")]
147 .concat()
148 .to_vec(),
149 ),
150 )
151 .expect("We should be able to read storage from the parent block.")
152 .map(|ref mut raw_data| {
153 Decode::decode(&mut &raw_data.0[..]).expect("Stored data should decode correctly")
154 })
155 .unwrap_or_default();
156
157 Self { starting_dmq_mqc_head, starting_hrmp_mqc_heads }
158 }
159}
160
161#[async_trait::async_trait]
162impl<R: Send + Sync + GenerateRandomness<u64>> InherentDataProvider
163 for MockValidationDataInherentDataProvider<R>
164{
165 async fn provide_inherent_data(
166 &self,
167 inherent_data: &mut InherentData,
168 ) -> Result<(), sp_inherents::Error> {
169 let mut sproof_builder =
171 RelayStateSproofBuilder { para_id: self.para_id, ..Default::default() };
172
173 let relay_parent_number =
175 self.relay_offset + self.relay_blocks_per_para_block * self.current_para_block;
176 sproof_builder.current_slot = Slot::from(relay_parent_number as u64);
177
178 sproof_builder.upgrade_go_ahead = self.upgrade_go_ahead;
179 let mut downward_messages = Vec::new();
181 let mut dmq_mqc = MessageQueueChain::new(self.xcm_config.starting_dmq_mqc_head);
182 for msg in &self.raw_downward_messages {
183 let wrapped = InboundDownwardMessage { sent_at: relay_parent_number, msg: msg.clone() };
184
185 dmq_mqc.extend_downward(&wrapped);
186 downward_messages.push(wrapped);
187 }
188 sproof_builder.dmq_mqc_head = Some(dmq_mqc.head());
189
190 let mut horizontal_messages = BTreeMap::<ParaId, Vec<InboundHrmpMessage>>::new();
193 for (para_id, msg) in &self.raw_horizontal_messages {
194 let wrapped = InboundHrmpMessage { sent_at: relay_parent_number, data: msg.clone() };
195
196 horizontal_messages.entry(*para_id).or_default().push(wrapped);
197 }
198
199 for (para_id, messages) in &horizontal_messages {
201 let mut channel_mqc = MessageQueueChain::new(
202 *self
203 .xcm_config
204 .starting_hrmp_mqc_heads
205 .get(para_id)
206 .unwrap_or(&relay_chain::Hash::default()),
207 );
208 for message in messages {
209 channel_mqc.extend_hrmp(message);
210 }
211 sproof_builder.upsert_inbound_channel(*para_id).mqc_head = Some(channel_mqc.head());
212 }
213
214 sproof_builder.current_epoch = if self.para_blocks_per_relay_epoch == 0 {
216 self.current_para_block.into()
218 } else {
219 (self.current_para_block / self.para_blocks_per_relay_epoch).into()
220 };
221 sproof_builder.randomness =
223 self.relay_randomness_config.generate_randomness(self.current_para_block.into());
224
225 if let Some(key_values) = &self.additional_key_values {
226 sproof_builder.additional_key_values = key_values.clone()
227 }
228
229 sproof_builder.included_para_head = self.current_para_block_head.clone();
231
232 let (relay_parent_storage_root, proof) = sproof_builder.into_state_root_and_proof();
233 let parachain_inherent_data = ParachainInherentData {
234 validation_data: PersistedValidationData {
235 parent_head: Default::default(),
236 relay_parent_storage_root,
237 relay_parent_number,
238 max_pov_size: Default::default(),
239 },
240 downward_messages,
241 horizontal_messages,
242 relay_chain_state: proof,
243 relay_parent_descendants: Default::default(),
244 collator_peer_id: None,
245 };
246
247 parachain_inherent_data.provide_inherent_data(inherent_data).await
248 }
249
250 async fn try_handle_error(
252 &self,
253 _: &sp_inherents::InherentIdentifier,
254 _: &[u8],
255 ) -> Option<Result<(), sp_inherents::Error>> {
256 None
257 }
258}