referrerpolicy=no-referrer-when-downgrade

cumulus_client_parachain_inherent/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Client side code for generating the parachain inherent.
18
19use 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
34/// Collect the relevant relay chain state in form of a proof for putting it into the validation
35/// data inherent.
36async 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		// TODO paritytech/polkadot#6283: Remove all usages of `relay_dispatch_queue_size`
111		// We need to keep this here until all parachains have migrated to
112		// `relay_dispatch_queue_remaining_capacity`.
113		#[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	// Add additional relay state keys
138	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	/// Create the [`ParachainInherentData`] at the given `relay_parent`.
162	///
163	/// Returns `None` if the creation failed.
164	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		// Only include next epoch authorities when the descendants include an epoch digest.
173		// Skip the first entry because this is the relay parent itself.
174		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}