cumulus_client_parachain_inherent/
lib.rs1use codec::Decode;
20use cumulus_primitives_core::{
21 relay_chain::{self, Block as RelayBlock, Hash as PHash, HrmpChannelId},
22 ParaId, PersistedValidationData,
23};
24use cumulus_relay_chain_interface::RelayChainInterface;
25
26mod mock;
27
28use cumulus_primitives_core::relay_chain::Header as RelayHeader;
29pub use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER};
30pub use mock::{MockValidationDataInherentDataProvider, MockXcmConfig};
31
32const LOG_TARGET: &str = "parachain-inherent";
33
34async fn collect_relay_storage_proof(
37 relay_chain_interface: &impl RelayChainInterface,
38 para_id: ParaId,
39 relay_parent: PHash,
40 include_authorities: bool,
41 include_next_authorities: bool,
42 additional_relay_state_keys: Vec<Vec<u8>>,
43) -> Option<sp_state_machine::StorageProof> {
44 use relay_chain::well_known_keys as relay_well_known_keys;
45
46 let ingress_channels = relay_chain_interface
47 .get_storage_by_key(
48 relay_parent,
49 &relay_well_known_keys::hrmp_ingress_channel_index(para_id),
50 )
51 .await
52 .map_err(|e| {
53 tracing::error!(
54 target: LOG_TARGET,
55 relay_parent = ?relay_parent,
56 error = ?e,
57 "Cannot obtain the hrmp ingress channel."
58 )
59 })
60 .ok()?;
61
62 let ingress_channels = ingress_channels
63 .map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
64 .transpose()
65 .map_err(|e| {
66 tracing::error!(
67 target: LOG_TARGET,
68 error = ?e,
69 "Cannot decode the hrmp ingress channel index.",
70 )
71 })
72 .ok()?
73 .unwrap_or_default();
74
75 let egress_channels = relay_chain_interface
76 .get_storage_by_key(
77 relay_parent,
78 &relay_well_known_keys::hrmp_egress_channel_index(para_id),
79 )
80 .await
81 .map_err(|e| {
82 tracing::error!(
83 target: LOG_TARGET,
84 error = ?e,
85 "Cannot obtain the hrmp egress channel.",
86 )
87 })
88 .ok()?;
89
90 let egress_channels = egress_channels
91 .map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
92 .transpose()
93 .map_err(|e| {
94 tracing::error!(
95 target: LOG_TARGET,
96 error = ?e,
97 "Cannot decode the hrmp egress channel index.",
98 )
99 })
100 .ok()?
101 .unwrap_or_default();
102
103 let mut relevant_keys = vec![
104 relay_well_known_keys::CURRENT_BLOCK_RANDOMNESS.to_vec(),
105 relay_well_known_keys::ONE_EPOCH_AGO_RANDOMNESS.to_vec(),
106 relay_well_known_keys::TWO_EPOCHS_AGO_RANDOMNESS.to_vec(),
107 relay_well_known_keys::CURRENT_SLOT.to_vec(),
108 relay_well_known_keys::ACTIVE_CONFIG.to_vec(),
109 relay_well_known_keys::dmq_mqc_head(para_id),
110 #[allow(deprecated)]
114 relay_well_known_keys::relay_dispatch_queue_size(para_id),
115 relay_well_known_keys::relay_dispatch_queue_remaining_capacity(para_id).key,
116 relay_well_known_keys::hrmp_ingress_channel_index(para_id),
117 relay_well_known_keys::hrmp_egress_channel_index(para_id),
118 relay_well_known_keys::upgrade_go_ahead_signal(para_id),
119 relay_well_known_keys::upgrade_restriction_signal(para_id),
120 relay_well_known_keys::para_head(para_id),
121 ];
122 relevant_keys.extend(ingress_channels.into_iter().map(|sender| {
123 relay_well_known_keys::hrmp_channels(HrmpChannelId { sender, recipient: para_id })
124 }));
125 relevant_keys.extend(egress_channels.into_iter().map(|recipient| {
126 relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient })
127 }));
128
129 if include_authorities {
130 relevant_keys.push(relay_well_known_keys::AUTHORITIES.to_vec());
131 }
132
133 if include_next_authorities {
134 relevant_keys.push(relay_well_known_keys::NEXT_AUTHORITIES.to_vec());
135 }
136
137 let unique_keys: Vec<Vec<u8>> = additional_relay_state_keys
139 .into_iter()
140 .filter(|key| !relevant_keys.contains(key))
141 .collect();
142 relevant_keys.extend(unique_keys);
143
144 relay_chain_interface
145 .prove_read(relay_parent, &relevant_keys)
146 .await
147 .map_err(|e| {
148 tracing::error!(
149 target: LOG_TARGET,
150 relay_parent = ?relay_parent,
151 error = ?e,
152 "Cannot obtain read proof from relay chain.",
153 );
154 })
155 .ok()
156}
157
158pub struct ParachainInherentDataProvider;
159
160impl ParachainInherentDataProvider {
161 pub async fn create_at(
165 relay_parent: PHash,
166 relay_chain_interface: &impl RelayChainInterface,
167 validation_data: &PersistedValidationData,
168 para_id: ParaId,
169 relay_parent_descendants: Vec<RelayHeader>,
170 additional_relay_state_keys: Vec<Vec<u8>>,
171 ) -> Option<ParachainInherentData> {
172 let include_next_authorities = relay_parent_descendants.iter().skip(1).any(|header| {
175 sc_consensus_babe::find_next_epoch_digest::<RelayBlock>(header)
176 .ok()
177 .flatten()
178 .is_some()
179 });
180 let relay_chain_state = collect_relay_storage_proof(
181 relay_chain_interface,
182 para_id,
183 relay_parent,
184 !relay_parent_descendants.is_empty(),
185 include_next_authorities,
186 additional_relay_state_keys,
187 )
188 .await?;
189
190 let downward_messages = relay_chain_interface
191 .retrieve_dmq_contents(para_id, relay_parent)
192 .await
193 .map_err(|e| {
194 tracing::error!(
195 target: LOG_TARGET,
196 relay_parent = ?relay_parent,
197 error = ?e,
198 "An error occurred during requesting the downward messages.",
199 );
200 })
201 .ok()?;
202 let horizontal_messages = relay_chain_interface
203 .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)
204 .await
205 .map_err(|e| {
206 tracing::error!(
207 target: LOG_TARGET,
208 relay_parent = ?relay_parent,
209 error = ?e,
210 "An error occurred during requesting the inbound HRMP messages.",
211 );
212 })
213 .ok()?;
214
215 Some(ParachainInherentData {
216 downward_messages,
217 horizontal_messages,
218 validation_data: validation_data.clone(),
219 relay_chain_state,
220 relay_parent_descendants,
221 collator_peer_id: None,
222 })
223 }
224}