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