referrerpolicy=no-referrer-when-downgrade

bridge_runtime_common/
integrity.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Integrity tests for chain constants and pallets configuration.
18//!
19//! Most of the tests in this module assume that the bridge is using standard (see `crate::messages`
20//! module for details) configuration.
21
22use bp_header_chain::ChainWithGrandpa;
23use bp_messages::{ChainWithMessages, InboundLaneData, MessageNonce};
24use bp_runtime::{AccountIdOf, Chain};
25use codec::Encode;
26use frame_support::{storage::generator::StorageValue, traits::Get, weights::Weight};
27use frame_system::limits;
28use pallet_bridge_messages::{ThisChainOf, WeightInfoExt as _};
29
30// Re-export to avoid include all dependencies everywhere.
31#[doc(hidden)]
32pub mod __private {
33	pub use static_assertions;
34}
35
36/// Macro that ensures that the runtime configuration and chain primitives crate are sharing
37/// the same types (nonce, block number, hash, hasher, account id and header).
38#[macro_export]
39macro_rules! assert_chain_types(
40	( runtime: $r:path, this_chain: $this:path ) => {
41		{
42			use frame_system::{Config as SystemConfig, pallet_prelude::{BlockNumberFor, HeaderFor}};
43			use $crate::integrity::__private::static_assertions::assert_type_eq_all;
44
45			// if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard
46			// configuration is used), or something has broke existing configuration (meaning that all bridged chains
47			// and relays will stop functioning)
48
49			assert_type_eq_all!(<$r as SystemConfig>::Nonce, bp_runtime::NonceOf<$this>);
50			assert_type_eq_all!(BlockNumberFor<$r>, bp_runtime::BlockNumberOf<$this>);
51			assert_type_eq_all!(<$r as SystemConfig>::Hash, bp_runtime::HashOf<$this>);
52			assert_type_eq_all!(<$r as SystemConfig>::Hashing, bp_runtime::HasherOf<$this>);
53			assert_type_eq_all!(<$r as SystemConfig>::AccountId, bp_runtime::AccountIdOf<$this>);
54			assert_type_eq_all!(HeaderFor<$r>, bp_runtime::HeaderOf<$this>);
55		}
56	}
57);
58
59/// Macro that ensures that the bridge messages pallet is configured properly to bridge using given
60/// configuration.
61#[macro_export]
62macro_rules! assert_bridge_messages_pallet_types(
63	(
64		runtime: $r:path,
65		with_bridged_chain_messages_instance: $i:path,
66		this_chain: $this:path,
67		bridged_chain: $bridged:path,
68		expected_payload_type: $payload:path,
69	) => {
70		{
71			use $crate::integrity::__private::static_assertions::assert_type_eq_all;
72			use bp_messages::ChainWithMessages;
73			use bp_runtime::Chain;
74			use pallet_bridge_messages::Config as BridgeMessagesConfig;
75
76			// if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard
77			// configuration is used), or something has broke existing configuration (meaning that all bridged chains
78			// and relays will stop functioning)
79
80			assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::ThisChain, $this);
81			assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::BridgedChain, $bridged);
82
83			assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::OutboundPayload, $payload);
84			assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::InboundPayload, $payload);
85		}
86	}
87);
88
89/// Macro that combines four other macro calls - `assert_chain_types`, `assert_bridge_types`,
90/// and `assert_bridge_messages_pallet_types`. It may be used
91/// at the chain that is implementing standard messages bridge with messages pallets deployed.
92#[macro_export]
93macro_rules! assert_complete_bridge_types(
94	(
95		runtime: $r:path,
96		with_bridged_chain_messages_instance: $mi:path,
97		this_chain: $this:path,
98		bridged_chain: $bridged:path,
99		expected_payload_type: $payload:path,
100	) => {
101		$crate::assert_chain_types!(runtime: $r, this_chain: $this);
102		$crate::assert_bridge_messages_pallet_types!(
103			runtime: $r,
104			with_bridged_chain_messages_instance: $mi,
105			this_chain: $this,
106			bridged_chain: $bridged,
107			expected_payload_type: $payload,
108		);
109	}
110);
111
112/// Parameters for asserting chain-related constants.
113#[derive(Debug)]
114pub struct AssertChainConstants {
115	/// Block length limits of the chain.
116	pub block_length: limits::BlockLength,
117	/// Block weight limits of the chain.
118	pub block_weights: limits::BlockWeights,
119}
120
121/// Test that our hardcoded, chain-related constants, are matching chain runtime configuration.
122///
123/// In particular, this test ensures that:
124///
125/// 1) block weight limits are matching;
126/// 2) block size limits are matching.
127pub fn assert_chain_constants<R>(params: AssertChainConstants)
128where
129	R: frame_system::Config,
130{
131	// we don't check runtime version here, because in our case we'll be building relay from one
132	// repo and runtime will live in another repo, along with outdated relay version. To avoid
133	// unneeded commits, let's not raise an error in case of version mismatch.
134
135	// if one of following assert fails, it means that we may need to upgrade bridged chain and
136	// relay to use updated constants. If constants are now smaller than before, it may lead to
137	// undeliverable messages.
138
139	// `BlockLength` struct is not implementing `PartialEq`, so we compare encoded values here.
140	assert_eq!(
141		R::BlockLength::get().encode(),
142		params.block_length.encode(),
143		"BlockLength from runtime ({:?}) differ from hardcoded: {:?}",
144		R::BlockLength::get(),
145		params.block_length,
146	);
147	// `BlockWeights` struct is not implementing `PartialEq`, so we compare encoded values here
148	assert_eq!(
149		R::BlockWeights::get().encode(),
150		params.block_weights.encode(),
151		"BlockWeights from runtime ({:?}) differ from hardcoded: {:?}",
152		R::BlockWeights::get(),
153		params.block_weights,
154	);
155}
156
157/// Test that the constants, used in GRANDPA pallet configuration are valid.
158pub fn assert_bridge_grandpa_pallet_constants<R, GI>()
159where
160	R: pallet_bridge_grandpa::Config<GI>,
161	GI: 'static,
162{
163	assert!(
164		R::HeadersToKeep::get() > 0,
165		"HeadersToKeep ({}) must be larger than zero",
166		R::HeadersToKeep::get(),
167	);
168}
169
170/// Test that the constants, used in messages pallet configuration are valid.
171pub fn assert_bridge_messages_pallet_constants<R, MI>()
172where
173	R: pallet_bridge_messages::Config<MI>,
174	MI: 'static,
175{
176	assert!(
177		pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX
178			<= pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
179		"MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX ({}) of {:?} is larger than \
180			its MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX ({}). This makes \
181			no sense",
182		pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
183		pallet_bridge_messages::BridgedChainOf::<R, MI>::ID,
184		pallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
185	);
186}
187
188/// Parameters for asserting bridge GRANDPA pallet names.
189#[derive(Debug)]
190struct AssertBridgeGrandpaPalletNames<'a> {
191	/// Name of the GRANDPA pallet, deployed at this chain and used to bridge with the bridged
192	/// chain.
193	pub with_bridged_chain_grandpa_pallet_name: &'a str,
194}
195
196/// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants
197/// from chain primitives crates.
198fn assert_bridge_grandpa_pallet_names<R, GI>(params: AssertBridgeGrandpaPalletNames)
199where
200	R: pallet_bridge_grandpa::Config<GI>,
201	GI: 'static,
202{
203	// check that the bridge GRANDPA pallet has required name
204	assert_eq!(
205			pallet_bridge_grandpa::PalletOwner::<R, GI>::storage_value_final_key().to_vec(),
206			bp_runtime::storage_value_key(
207				params.with_bridged_chain_grandpa_pallet_name,
208				"PalletOwner",
209			)
210			.0,
211		);
212	assert_eq!(
213		pallet_bridge_grandpa::PalletOperatingMode::<R, GI>::storage_value_final_key().to_vec(),
214		bp_runtime::storage_value_key(
215			params.with_bridged_chain_grandpa_pallet_name,
216			"PalletOperatingMode",
217		)
218		.0,
219	);
220}
221
222/// Parameters for asserting bridge messages pallet names.
223#[derive(Debug)]
224struct AssertBridgeMessagesPalletNames<'a> {
225	/// Name of the messages pallet, deployed at this chain and used to bridge with the bridged
226	/// chain.
227	pub with_bridged_chain_messages_pallet_name: &'a str,
228}
229
230/// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants
231/// from chain primitives crates.
232fn assert_bridge_messages_pallet_names<R, MI>(params: AssertBridgeMessagesPalletNames)
233where
234	R: pallet_bridge_messages::Config<MI>,
235	MI: 'static,
236{
237	// check that the bridge messages pallet has required name
238	assert_eq!(
239		pallet_bridge_messages::PalletOwner::<R, MI>::storage_value_final_key().to_vec(),
240		bp_runtime::storage_value_key(
241			params.with_bridged_chain_messages_pallet_name,
242			"PalletOwner",
243		)
244		.0,
245	);
246	assert_eq!(
247		pallet_bridge_messages::PalletOperatingMode::<R, MI>::storage_value_final_key().to_vec(),
248		bp_runtime::storage_value_key(
249			params.with_bridged_chain_messages_pallet_name,
250			"PalletOperatingMode",
251		)
252		.0,
253	);
254}
255
256/// Parameters for asserting complete standard messages bridge.
257#[derive(Debug)]
258pub struct AssertCompleteBridgeConstants {
259	/// Parameters to assert this chain constants.
260	pub this_chain_constants: AssertChainConstants,
261}
262
263/// All bridge-related constants tests for the complete standard relay-chain messages bridge
264/// (i.e. with bridge GRANDPA and messages pallets deployed).
265pub fn assert_complete_with_relay_chain_bridge_constants<R, GI, MI>(
266	params: AssertCompleteBridgeConstants,
267) where
268	R: frame_system::Config
269		+ pallet_bridge_grandpa::Config<GI>
270		+ pallet_bridge_messages::Config<MI>,
271	GI: 'static,
272	MI: 'static,
273{
274	assert_chain_constants::<R>(params.this_chain_constants);
275	assert_bridge_grandpa_pallet_constants::<R, GI>();
276	assert_bridge_messages_pallet_constants::<R, MI>();
277	assert_bridge_grandpa_pallet_names::<R, GI>(AssertBridgeGrandpaPalletNames {
278		with_bridged_chain_grandpa_pallet_name:
279			<R as pallet_bridge_grandpa::Config<GI>>::BridgedChain::WITH_CHAIN_GRANDPA_PALLET_NAME,
280	});
281	assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
282		with_bridged_chain_messages_pallet_name:
283			<R as pallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
284	});
285}
286
287/// All bridge-related constants tests for the complete standard parachain messages bridge
288/// (i.e. with bridge GRANDPA, parachains and messages pallets deployed).
289pub fn assert_complete_with_parachain_bridge_constants<R, PI, MI>(
290	params: AssertCompleteBridgeConstants,
291) where
292	R: frame_system::Config
293		+ pallet_bridge_parachains::Config<PI>
294		+ pallet_bridge_messages::Config<MI>,
295	<R as pallet_bridge_parachains::BoundedBridgeGrandpaConfig<R::BridgesGrandpaPalletInstance>>::BridgedRelayChain: ChainWithGrandpa,
296	PI: 'static,
297	MI: 'static,
298{
299	assert_chain_constants::<R>(params.this_chain_constants);
300	assert_bridge_grandpa_pallet_constants::<R, R::BridgesGrandpaPalletInstance>();
301	assert_bridge_messages_pallet_constants::<R, MI>();
302	assert_bridge_grandpa_pallet_names::<R, R::BridgesGrandpaPalletInstance>(
303		AssertBridgeGrandpaPalletNames {
304			with_bridged_chain_grandpa_pallet_name:
305				<<R as pallet_bridge_parachains::BoundedBridgeGrandpaConfig<
306					R::BridgesGrandpaPalletInstance,
307				>>::BridgedRelayChain>::WITH_CHAIN_GRANDPA_PALLET_NAME,
308		},
309	);
310	assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
311		with_bridged_chain_messages_pallet_name:
312			<R as pallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
313	});
314}
315
316/// All bridge-related constants tests for the standalone messages bridge deployment (only with
317/// messages pallets deployed).
318pub fn assert_standalone_messages_bridge_constants<R, MI>(params: AssertCompleteBridgeConstants)
319where
320	R: frame_system::Config + pallet_bridge_messages::Config<MI>,
321	MI: 'static,
322{
323	assert_chain_constants::<R>(params.this_chain_constants);
324	assert_bridge_messages_pallet_constants::<R, MI>();
325	assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
326		with_bridged_chain_messages_pallet_name:
327			<R as pallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
328	});
329}
330
331/// Check that the message lane weights are correct.
332pub fn check_message_lane_weights<
333	C: ChainWithMessages,
334	T: frame_system::Config + pallet_bridge_messages::Config<MessagesPalletInstance>,
335	MessagesPalletInstance: 'static,
336>(
337	bridged_chain_extra_storage_proof_size: u32,
338	this_chain_max_unrewarded_relayers: MessageNonce,
339	this_chain_max_unconfirmed_messages: MessageNonce,
340	// whether `RefundBridgedParachainMessages` extension is deployed at runtime and is used for
341	// refunding this bridge transactions?
342	//
343	// in other words: pass true for all known production chains
344	runtime_includes_refund_extension: bool,
345) {
346	type Weights<T, MI> = <T as pallet_bridge_messages::Config<MI>>::WeightInfo;
347
348	// check basic weight assumptions
349	pallet_bridge_messages::ensure_weights_are_correct::<Weights<T, MessagesPalletInstance>>();
350
351	// check that the maximal message dispatch weight is below hardcoded limit
352	pallet_bridge_messages::ensure_maximal_message_dispatch::<Weights<T, MessagesPalletInstance>>(
353		C::maximal_incoming_message_size(),
354		C::maximal_incoming_message_dispatch_weight(),
355	);
356
357	// check that weights allow us to receive messages
358	let max_incoming_message_proof_size =
359		bridged_chain_extra_storage_proof_size.saturating_add(C::maximal_incoming_message_size());
360	pallet_bridge_messages::ensure_able_to_receive_message::<Weights<T, MessagesPalletInstance>>(
361		C::max_extrinsic_size(),
362		C::max_extrinsic_weight(),
363		max_incoming_message_proof_size,
364		C::maximal_incoming_message_dispatch_weight(),
365	);
366
367	// check that weights allow us to receive delivery confirmations
368	let max_incoming_inbound_lane_data_proof_size = InboundLaneData::<
369		AccountIdOf<ThisChainOf<T, MessagesPalletInstance>>,
370	>::encoded_size_hint_u32(
371		this_chain_max_unrewarded_relayers as _
372	);
373	pallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights<T, MessagesPalletInstance>>(
374		C::max_extrinsic_size(),
375		C::max_extrinsic_weight(),
376		max_incoming_inbound_lane_data_proof_size,
377		this_chain_max_unrewarded_relayers,
378		this_chain_max_unconfirmed_messages,
379	);
380
381	// check that extra weights of delivery/confirmation transactions include the weight
382	// of `RefundBridgedParachainMessages` operations. This signed extension assumes the worst case
383	// (i.e. slashing if delivery transaction was invalid) and refunds some weight if
384	// assumption was wrong (i.e. if we did refund instead of slashing). This check
385	// ensures the extension will not refund weight when it doesn't need to (i.e. if pallet
386	// weights do not account weights of refund extension).
387	if runtime_includes_refund_extension {
388		assert_ne!(
389			Weights::<T, MessagesPalletInstance>::receive_messages_proof_overhead_from_runtime(),
390			Weight::zero()
391		);
392		assert_ne!(
393			Weights::<T, MessagesPalletInstance>::receive_messages_delivery_proof_overhead_from_runtime(),
394			Weight::zero()
395		);
396	}
397}