bridge_hub_rococo_runtime/
bridge_to_westend_config.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3
4// Cumulus 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// Cumulus 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 Cumulus.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Bridge definitions used on BridgeHubRococo for bridging to BridgeHubWestend.
18
19use crate::{
20	bridge_common_config::{
21		BridgeParachainWestendInstance, DeliveryRewardInBalance,
22		RelayersForLegacyLaneIdsMessagesInstance,
23	},
24	weights,
25	xcm_config::UniversalLocation,
26	AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent,
27	RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, XcmpQueue,
28};
29use bp_messages::{
30	source_chain::FromBridgedChainMessagesDeliveryProof,
31	target_chain::FromBridgedChainMessagesProof, LegacyLaneId,
32};
33use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge;
34use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload};
35
36use frame_support::{parameter_types, traits::PalletInfoAccess};
37use frame_system::{EnsureNever, EnsureRoot};
38use pallet_bridge_messages::LaneIdOf;
39use pallet_bridge_relayers::extension::{
40	BridgeRelayersTransactionExtension, WithMessagesExtensionConfig,
41};
42use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains};
43use polkadot_parachain_primitives::primitives::Sibling;
44use testnet_parachains_constants::rococo::currency::UNITS as ROC;
45use xcm::{
46	latest::{prelude::*, WESTEND_GENESIS_HASH},
47	prelude::{InteriorLocation, NetworkId},
48};
49use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia};
50
51parameter_types! {
52	pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(<BridgeWestendMessages as PalletInfoAccess>::index() as u8)].into();
53	pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH);
54	pub WestendGlobalConsensusNetworkLocation: Location = Location::new(
55		2,
56		[GlobalConsensus(WestendGlobalConsensusNetwork::get())]
57	);
58	// see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value
59	pub PriorityBoostPerRelayHeader: u64 = 32_007_814_407_814;
60	// see the `FEE_BOOST_PER_PARACHAIN_HEADER` constant get the meaning of this value
61	pub PriorityBoostPerParachainHeader: u64 = 1_396_340_903_540_903;
62	// see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value
63	pub PriorityBoostPerMessage: u64 = 182_044_444_444_444;
64
65	pub BridgeHubWestendLocation: Location = Location::new(
66		2,
67		[
68			GlobalConsensus(WestendGlobalConsensusNetwork::get()),
69			Parachain(<bp_bridge_hub_westend::BridgeHubWestend as bp_runtime::Parachain>::PARACHAIN_ID)
70		]
71	);
72
73	pub storage BridgeDeposit: Balance = 5 * ROC;
74}
75
76/// Proof of messages, coming from Westend.
77pub type FromWestendBridgeHubMessagesProof<MI> =
78	FromBridgedChainMessagesProof<bp_bridge_hub_westend::Hash, LaneIdOf<Runtime, MI>>;
79/// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages.
80pub type ToWestendBridgeHubMessagesDeliveryProof<MI> =
81	FromBridgedChainMessagesDeliveryProof<bp_bridge_hub_westend::Hash, LaneIdOf<Runtime, MI>>;
82
83/// Dispatches received XCM messages from other bridge
84type FromWestendMessageBlobDispatcher =
85	BridgeBlobDispatcher<XcmRouter, UniversalLocation, BridgeRococoToWestendMessagesPalletInstance>;
86
87/// Transaction extension that refunds relayers that are delivering messages from the Westend
88/// parachain.
89pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersTransactionExtension<
90	Runtime,
91	WithMessagesExtensionConfig<
92		StrOnBridgeHubRococoRefundBridgeHubWestendMessages,
93		Runtime,
94		WithBridgeHubWestendMessagesInstance,
95		RelayersForLegacyLaneIdsMessagesInstance,
96		PriorityBoostPerMessage,
97	>,
98	LaneIdOf<Runtime, WithBridgeHubWestendMessagesInstance>,
99>;
100bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWestendMessages);
101
102/// Add XCM messages support for BridgeHubRococo to support Rococo->Westend XCM messages
103pub type WithBridgeHubWestendMessagesInstance = pallet_bridge_messages::Instance3;
104impl pallet_bridge_messages::Config<WithBridgeHubWestendMessagesInstance> for Runtime {
105	type RuntimeEvent = RuntimeEvent;
106	type WeightInfo = weights::pallet_bridge_messages_rococo_to_westend::WeightInfo<Runtime>;
107
108	type ThisChain = bp_bridge_hub_rococo::BridgeHubRococo;
109	type BridgedChain = bp_bridge_hub_westend::BridgeHubWestend;
110	type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders<
111		Runtime,
112		BridgeParachainWestendInstance,
113		bp_bridge_hub_westend::BridgeHubWestend,
114	>;
115
116	type OutboundPayload = XcmAsPlainPayload;
117	type InboundPayload = XcmAsPlainPayload;
118	type LaneId = LegacyLaneId;
119
120	type DeliveryPayments = ();
121	type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter<
122		Runtime,
123		WithBridgeHubWestendMessagesInstance,
124		RelayersForLegacyLaneIdsMessagesInstance,
125		DeliveryRewardInBalance,
126	>;
127
128	type MessageDispatch = XcmOverBridgeHubWestend;
129	type OnMessagesDelivered = XcmOverBridgeHubWestend;
130}
131
132/// Add support for the export and dispatch of XCM programs withing
133/// `WithBridgeHubWestendMessagesInstance`.
134pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1;
135impl pallet_xcm_bridge_hub::Config<XcmOverBridgeHubWestendInstance> for Runtime {
136	type RuntimeEvent = RuntimeEvent;
137
138	type UniversalLocation = UniversalLocation;
139	type BridgedNetwork = WestendGlobalConsensusNetworkLocation;
140	type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance;
141
142	type MessageExportPrice = ();
143	type DestinationVersion =
144		XcmVersionOfDestAndRemoteBridge<PolkadotXcm, BridgeHubWestendLocation>;
145
146	type ForceOrigin = EnsureRoot<AccountId>;
147	// We don't want to allow creating bridges for this instance with `LegacyLaneId`.
148	type OpenBridgeOrigin = EnsureNever<Location>;
149	// Converter aligned with `OpenBridgeOrigin`.
150	type BridgeOriginAccountIdConverter =
151		(ParentIsPreset<AccountId>, SiblingParachainConvertsVia<Sibling, AccountId>);
152
153	type BridgeDeposit = BridgeDeposit;
154	type Currency = Balances;
155	type RuntimeHoldReason = RuntimeHoldReason;
156	// Do not require deposit from system parachains or relay chain
157	type AllowWithoutBridgeDeposit =
158		RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>;
159
160	type LocalXcmChannelManager = CongestionManager;
161	type BlobDispatcher = FromWestendMessageBlobDispatcher;
162}
163
164/// Implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager` for congestion management.
165pub struct CongestionManager;
166impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager {
167	type Error = SendError;
168
169	fn is_congested(with: &Location) -> bool {
170		// This is used to check the inbound bridge queue/messages to determine if they can be
171		// dispatched and sent to the sibling parachain. Therefore, checking outbound `XcmpQueue`
172		// is sufficient here.
173		use bp_xcm_bridge_hub_router::XcmChannelStatusProvider;
174		cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::<Runtime>::is_congested(
175			with,
176		)
177	}
178
179	fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> {
180		// This bridge is intended for AH<>AH communication with a hard-coded/static lane,
181		// so `local_origin` is expected to represent only the local AH.
182		send_xcm::<XcmpQueue>(
183			local_origin.clone(),
184			bp_asset_hub_rococo::build_congestion_message(bridge.inner(), true).into(),
185		)
186		.map(|_| ())
187	}
188
189	fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> {
190		// This bridge is intended for AH<>AH communication with a hard-coded/static lane,
191		// so `local_origin` is expected to represent only the local AH.
192		send_xcm::<XcmpQueue>(
193			local_origin.clone(),
194			bp_asset_hub_rococo::build_congestion_message(bridge.inner(), false).into(),
195		)
196		.map(|_| ())
197	}
198}
199
200#[cfg(feature = "runtime-benchmarks")]
201pub(crate) fn open_bridge_for_benchmarks<R, XBHI, C>(
202	with: pallet_xcm_bridge_hub::LaneIdOf<R, XBHI>,
203	sibling_para_id: u32,
204) -> InteriorLocation
205where
206	R: pallet_xcm_bridge_hub::Config<XBHI>,
207	XBHI: 'static,
208	C: xcm_executor::traits::ConvertLocation<
209		bp_runtime::AccountIdOf<pallet_xcm_bridge_hub::ThisChainOf<R, XBHI>>,
210	>,
211{
212	use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState};
213	use sp_runtime::traits::Zero;
214	use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation};
215
216	// insert bridge metadata
217	let lane_id = with;
218	let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]);
219	let universal_source =
220		[GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into();
221	let universal_destination =
222		[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2075)].into();
223	let bridge_id = BridgeId::new(&universal_source, &universal_destination);
224
225	// insert only bridge metadata, because the benchmarks create lanes
226	pallet_xcm_bridge_hub::Bridges::<R, XBHI>::insert(
227		bridge_id,
228		Bridge {
229			bridge_origin_relative_location: alloc::boxed::Box::new(
230				sibling_parachain.clone().into(),
231			),
232			bridge_origin_universal_location: alloc::boxed::Box::new(
233				VersionedInteriorLocation::from(universal_source.clone()),
234			),
235			bridge_destination_universal_location: alloc::boxed::Box::new(
236				VersionedInteriorLocation::from(universal_destination),
237			),
238			state: BridgeState::Opened,
239			bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"),
240			deposit: Zero::zero(),
241			lane_id,
242		},
243	);
244	pallet_xcm_bridge_hub::LaneToBridge::<R, XBHI>::insert(lane_id, bridge_id);
245
246	universal_source
247}
248
249#[cfg(test)]
250mod tests {
251	use super::*;
252	use crate::bridge_common_config::BridgeGrandpaWestendInstance;
253	use bridge_runtime_common::{
254		assert_complete_bridge_types,
255		integrity::{
256			assert_complete_with_parachain_bridge_constants, check_message_lane_weights,
257			AssertChainConstants, AssertCompleteBridgeConstants,
258		},
259	};
260
261	/// Every additional message in the message delivery transaction boosts its priority.
262	/// So the priority of transaction with `N+1` messages is larger than priority of
263	/// transaction with `N` messages by the `PriorityBoostPerMessage`.
264	///
265	/// Economically, it is an equivalent of adding tip to the transaction with `N` messages.
266	/// The `FEE_BOOST_PER_MESSAGE` constant is the value of this tip.
267	///
268	/// We want this tip to be large enough (delivery transactions with more messages = less
269	/// operational costs and a faster bridge), so this value should be significant.
270	const FEE_BOOST_PER_MESSAGE: Balance = 2 * ROC;
271
272	// see `FEE_BOOST_PER_MESSAGE` comment
273	const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * ROC;
274	// see `FEE_BOOST_PER_MESSAGE` comment
275	const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * ROC;
276
277	#[test]
278	fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() {
279		check_message_lane_weights::<
280			bp_bridge_hub_rococo::BridgeHubRococo,
281			Runtime,
282			WithBridgeHubWestendMessagesInstance,
283		>(
284			bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE,
285			bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
286			bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
287			true,
288		);
289	}
290
291	#[test]
292	fn ensure_bridge_integrity() {
293		assert_complete_bridge_types!(
294			runtime: Runtime,
295			with_bridged_chain_messages_instance: WithBridgeHubWestendMessagesInstance,
296			this_chain: bp_bridge_hub_rococo::BridgeHubRococo,
297			bridged_chain: bp_bridge_hub_westend::BridgeHubWestend,
298			expected_payload_type: XcmAsPlainPayload,
299		);
300
301		assert_complete_with_parachain_bridge_constants::<
302			Runtime,
303			BridgeGrandpaWestendInstance,
304			WithBridgeHubWestendMessagesInstance,
305		>(AssertCompleteBridgeConstants {
306			this_chain_constants: AssertChainConstants {
307				block_length: bp_bridge_hub_rococo::BlockLength::get(),
308				block_weights: bp_bridge_hub_rococo::BlockWeightsForAsyncBacking::get(),
309			},
310		});
311
312		pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::<
313			Runtime,
314			BridgeGrandpaWestendInstance,
315			PriorityBoostPerRelayHeader,
316		>(FEE_BOOST_PER_RELAY_HEADER);
317
318		pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::<
319			Runtime,
320			WithBridgeHubWestendMessagesInstance,
321			bp_bridge_hub_westend::BridgeHubWestend,
322			PriorityBoostPerParachainHeader,
323		>(FEE_BOOST_PER_PARACHAIN_HEADER);
324
325		pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::<
326			Runtime,
327			WithBridgeHubWestendMessagesInstance,
328			PriorityBoostPerMessage,
329		>(FEE_BOOST_PER_MESSAGE);
330
331		let expected: InteriorLocation = [PalletInstance(
332			bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX,
333		)]
334		.into();
335
336		assert_eq!(BridgeRococoToWestendMessagesPalletInstance::get(), expected,);
337	}
338}
339
340/// Contains the migration for the AssetHubRococo<>AssetHubWestend bridge.
341pub mod migration {
342	use super::*;
343	use frame_support::traits::ConstBool;
344
345	parameter_types! {
346		pub AssetHubRococoToAssetHubWestendMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]);
347		pub AssetHubRococoLocation: Location = Location::new(1, [Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)]);
348		pub AssetHubWestendUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)].into();
349	}
350
351	/// Ensure that the existing lanes for the AHR<>AHW bridge are correctly configured.
352	pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane<
353		Runtime,
354		XcmOverBridgeHubWestendInstance,
355		AssetHubRococoToAssetHubWestendMessagesLane,
356		// the lanes are already created for AHR<>AHW, but we need to link them to the bridge
357		// structs
358		ConstBool<false>,
359		AssetHubRococoLocation,
360		AssetHubWestendUniversalLocation,
361	>;
362
363	mod v1_wrong {
364		use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer};
365		use bp_runtime::AccountIdOf;
366		use codec::{Decode, Encode};
367		use pallet_bridge_messages::BridgedChainOf;
368		use sp_std::collections::vec_deque::VecDeque;
369
370		#[derive(Encode, Decode, Clone, PartialEq, Eq)]
371		pub(crate) struct StoredInboundLaneData<T: pallet_bridge_messages::Config<I>, I: 'static>(
372			pub(crate) InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>,
373		);
374		#[derive(Encode, Decode, Clone, PartialEq, Eq)]
375		pub(crate) struct InboundLaneData<RelayerId> {
376			pub state: LaneState,
377			pub(crate) relayers: VecDeque<UnrewardedRelayer<RelayerId>>,
378			pub(crate) last_confirmed_nonce: MessageNonce,
379		}
380		#[derive(Encode, Decode, Clone, PartialEq, Eq)]
381		pub(crate) struct OutboundLaneData {
382			pub state: LaneState,
383			pub(crate) oldest_unpruned_nonce: MessageNonce,
384			pub(crate) latest_received_nonce: MessageNonce,
385			pub(crate) latest_generated_nonce: MessageNonce,
386		}
387	}
388
389	mod v1 {
390		pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData};
391		pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData};
392	}
393
394	/// Fix for v1 migration - corrects data for OutboundLaneData/InboundLaneData (it is needed only
395	/// for Rococo/Westend).
396	pub struct FixMessagesV1Migration<T, I>(sp_std::marker::PhantomData<(T, I)>);
397
398	impl<T: pallet_bridge_messages::Config<I>, I: 'static> frame_support::traits::OnRuntimeUpgrade
399		for FixMessagesV1Migration<T, I>
400	{
401		fn on_runtime_upgrade() -> Weight {
402			use sp_core::Get;
403			let mut weight = T::DbWeight::get().reads(1);
404
405			// `InboundLanes` - add state to the old structs
406			let translate_inbound =
407				|pre: v1_wrong::StoredInboundLaneData<T, I>| -> Option<v1::StoredInboundLaneData<T, I>> {
408					weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
409					Some(v1::StoredInboundLaneData(v1::InboundLaneData {
410						state: v1::LaneState::Opened,
411						relayers: pre.0.relayers,
412						last_confirmed_nonce: pre.0.last_confirmed_nonce,
413					}))
414				};
415			v1::InboundLanes::<T, I>::translate_values(translate_inbound);
416
417			// `OutboundLanes` - add state to the old structs
418			let translate_outbound =
419				|pre: v1_wrong::OutboundLaneData| -> Option<v1::OutboundLaneData> {
420					weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
421					Some(v1::OutboundLaneData {
422						state: v1::LaneState::Opened,
423						oldest_unpruned_nonce: pre.oldest_unpruned_nonce,
424						latest_received_nonce: pre.latest_received_nonce,
425						latest_generated_nonce: pre.latest_generated_nonce,
426					})
427				};
428			v1::OutboundLanes::<T, I>::translate_values(translate_outbound);
429
430			weight
431		}
432	}
433}