cumulus_client_parachain_inherent/
lib.rs1mod mock;
20
21use std::collections::{HashMap, HashSet};
22
23use codec::Decode;
24use cumulus_primitives_core::{
25 relay_chain::{
26 self, ApprovedPeerId, Block as RelayBlock, Hash as PHash, Header as RelayHeader,
27 HrmpChannelId,
28 },
29 ParaId, PersistedValidationData, RelayProofRequest, RelayStorageKey,
30};
31pub use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER};
32use cumulus_relay_chain_interface::RelayChainInterface;
33pub use mock::{MockValidationDataInherentDataProvider, MockXcmConfig};
34use sc_network_types::PeerId;
35use sp_state_machine::StorageProof;
36use sp_storage::ChildInfo;
37
38const LOG_TARGET: &str = "parachain-inherent";
39
40async fn get_static_relay_storage_keys(
43 relay_chain_interface: &impl RelayChainInterface,
44 para_id: ParaId,
45 relay_parent: PHash,
46 include_authorities: bool,
47 include_next_authorities: bool,
48) -> Option<HashSet<Vec<u8>>> {
49 use relay_chain::well_known_keys as relay_well_known_keys;
50
51 let ingress_channels = relay_chain_interface
52 .get_storage_by_key(
53 relay_parent,
54 &relay_well_known_keys::hrmp_ingress_channel_index(para_id),
55 )
56 .await
57 .map_err(|e| {
58 tracing::error!(
59 target: LOG_TARGET,
60 relay_parent = ?relay_parent,
61 error = ?e,
62 "Cannot obtain the hrmp ingress channel."
63 )
64 })
65 .ok()?;
66
67 let ingress_channels = ingress_channels
68 .map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
69 .transpose()
70 .map_err(|e| {
71 tracing::error!(
72 target: LOG_TARGET,
73 error = ?e,
74 "Cannot decode the hrmp ingress channel index.",
75 )
76 })
77 .ok()?
78 .unwrap_or_default();
79
80 let egress_channels = relay_chain_interface
81 .get_storage_by_key(
82 relay_parent,
83 &relay_well_known_keys::hrmp_egress_channel_index(para_id),
84 )
85 .await
86 .map_err(|e| {
87 tracing::error!(
88 target: LOG_TARGET,
89 error = ?e,
90 "Cannot obtain the hrmp egress channel.",
91 )
92 })
93 .ok()?;
94
95 let egress_channels = egress_channels
96 .map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
97 .transpose()
98 .map_err(|e| {
99 tracing::error!(
100 target: LOG_TARGET,
101 error = ?e,
102 "Cannot decode the hrmp egress channel index.",
103 )
104 })
105 .ok()?
106 .unwrap_or_default();
107
108 let mut relevant_keys: HashSet<Vec<u8>> = HashSet::from([
109 relay_well_known_keys::CURRENT_BLOCK_RANDOMNESS.to_vec(),
110 relay_well_known_keys::ONE_EPOCH_AGO_RANDOMNESS.to_vec(),
111 relay_well_known_keys::TWO_EPOCHS_AGO_RANDOMNESS.to_vec(),
112 relay_well_known_keys::CURRENT_SLOT.to_vec(),
113 relay_well_known_keys::ACTIVE_CONFIG.to_vec(),
114 relay_well_known_keys::dmq_mqc_head(para_id),
115 #[allow(deprecated)]
119 relay_well_known_keys::relay_dispatch_queue_size(para_id),
120 relay_well_known_keys::relay_dispatch_queue_remaining_capacity(para_id).key,
121 relay_well_known_keys::hrmp_ingress_channel_index(para_id),
122 relay_well_known_keys::hrmp_egress_channel_index(para_id),
123 relay_well_known_keys::upgrade_go_ahead_signal(para_id),
124 relay_well_known_keys::upgrade_restriction_signal(para_id),
125 relay_well_known_keys::para_head(para_id),
126 ]);
127 relevant_keys.extend(ingress_channels.into_iter().map(|sender| {
128 relay_well_known_keys::hrmp_channels(HrmpChannelId { sender, recipient: para_id })
129 }));
130 relevant_keys.extend(egress_channels.into_iter().map(|recipient| {
131 relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient })
132 }));
133
134 if include_authorities {
135 relevant_keys.insert(relay_well_known_keys::AUTHORITIES.to_vec());
136 }
137
138 if include_next_authorities {
139 relevant_keys.insert(relay_well_known_keys::NEXT_AUTHORITIES.to_vec());
140 }
141
142 Some(relevant_keys)
143}
144
145async fn collect_relay_storage_proof(
148 relay_chain_interface: &impl RelayChainInterface,
149 para_id: ParaId,
150 relay_parent: PHash,
151 include_authorities: bool,
152 include_next_authorities: bool,
153 relay_proof_request: RelayProofRequest,
154) -> Option<StorageProof> {
155 let mut all_top_keys = get_static_relay_storage_keys(
157 relay_chain_interface,
158 para_id,
159 relay_parent,
160 include_authorities,
161 include_next_authorities,
162 )
163 .await?;
164
165 let RelayProofRequest { keys } = relay_proof_request;
167 let mut child_keys: HashMap<Vec<u8>, HashSet<Vec<u8>>> = HashMap::new();
168
169 for key in keys {
170 match key {
171 RelayStorageKey::Top(k) => {
172 all_top_keys.insert(k);
173 },
174 RelayStorageKey::Child { storage_key, key } => {
175 child_keys.entry(storage_key).or_default().insert(key);
176 },
177 }
178 }
179
180 let mut all_proofs = Vec::new();
182
183 let top_keys_vec: Vec<Vec<u8>> = all_top_keys.into_iter().collect();
185 match relay_chain_interface.prove_read(relay_parent, &top_keys_vec).await {
186 Ok(top_proof) => {
187 all_proofs.push(top_proof);
188 },
189 Err(e) => {
190 tracing::error!(
191 target: LOG_TARGET,
192 relay_parent = ?relay_parent,
193 error = ?e,
194 "Cannot obtain relay chain storage proof.",
195 );
196 return None;
197 },
198 }
199
200 for (storage_key, data_keys) in child_keys {
202 let child_info = ChildInfo::new_default(&storage_key);
203 let data_keys_vec: Vec<Vec<u8>> = data_keys.into_iter().collect();
204 match relay_chain_interface
205 .prove_child_read(relay_parent, &child_info, &data_keys_vec)
206 .await
207 {
208 Ok(child_proof) => {
209 all_proofs.push(child_proof);
210 },
211 Err(e) => {
212 tracing::error!(
213 target: LOG_TARGET,
214 relay_parent = ?relay_parent,
215 child_trie_id = ?child_info.storage_key(),
216 error = ?e,
217 "Cannot obtain child trie proof from relay chain.",
218 );
219 },
220 }
221 }
222
223 Some(StorageProof::merge(all_proofs))
225}
226
227pub struct ParachainInherentDataProvider;
228
229impl ParachainInherentDataProvider {
230 pub async fn create_at(
234 relay_parent: PHash,
235 relay_chain_interface: &impl RelayChainInterface,
236 validation_data: &PersistedValidationData,
237 para_id: ParaId,
238 relay_parent_descendants: Vec<RelayHeader>,
239 relay_proof_request: RelayProofRequest,
240 collator_peer_id: PeerId,
241 ) -> Option<ParachainInherentData> {
242 let collator_peer_id = ApprovedPeerId::try_from(collator_peer_id.to_bytes())
243 .inspect_err(|_e| {
244 tracing::warn!(
245 target: LOG_TARGET,
246 "Could not convert collator_peer_id into ApprovedPeerId. The collator_peer_id \
247 should contain a sequence of at most 64 bytes",
248 );
249 })
250 .ok();
251
252 let include_next_authorities = relay_parent_descendants
255 .iter()
256 .skip(1)
257 .any(sc_consensus_babe::contains_epoch_change::<RelayBlock>);
258 let relay_chain_state = collect_relay_storage_proof(
259 relay_chain_interface,
260 para_id,
261 relay_parent,
262 !relay_parent_descendants.is_empty(),
263 include_next_authorities,
264 relay_proof_request,
265 )
266 .await?;
267
268 let downward_messages = relay_chain_interface
269 .retrieve_dmq_contents(para_id, relay_parent)
270 .await
271 .map_err(|e| {
272 tracing::error!(
273 target: LOG_TARGET,
274 relay_parent = ?relay_parent,
275 error = ?e,
276 "An error occurred during requesting the downward messages.",
277 );
278 })
279 .ok()?;
280 let horizontal_messages = relay_chain_interface
281 .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)
282 .await
283 .map_err(|e| {
284 tracing::error!(
285 target: LOG_TARGET,
286 relay_parent = ?relay_parent,
287 error = ?e,
288 "An error occurred during requesting the inbound HRMP messages.",
289 );
290 })
291 .ok()?;
292
293 Some(ParachainInherentData {
294 downward_messages,
295 horizontal_messages,
296 validation_data: validation_data.clone(),
297 relay_chain_state,
298 relay_parent_descendants,
299 collator_peer_id,
300 })
301 }
302}