1use crate::{
20 bridge_common_config::BridgeRelayersInstance, weights, xcm_config::UniversalLocation,
21 AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent,
22 RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, XcmpQueue,
23};
24use bp_messages::{
25 source_chain::FromBridgedChainMessagesDeliveryProof,
26 target_chain::FromBridgedChainMessagesProof, LegacyLaneId,
27};
28use bp_parachains::SingleParaStoredHeaderDataBuilder;
29use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge;
30use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload};
31
32use frame_support::{
33 parameter_types,
34 traits::{ConstU32, PalletInfoAccess},
35};
36use frame_system::{EnsureNever, EnsureRoot};
37use pallet_bridge_messages::LaneIdOf;
38use pallet_bridge_relayers::extension::{
39 BridgeRelayersTransactionExtension, WithMessagesExtensionConfig,
40};
41use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains};
42use polkadot_parachain_primitives::primitives::Sibling;
43use testnet_parachains_constants::westend::currency::UNITS as WND;
44use xcm::{
45 latest::{prelude::*, ROCOCO_GENESIS_HASH},
46 prelude::{InteriorLocation, NetworkId},
47};
48use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia};
49
50parameter_types! {
51 pub const RelayChainHeadersToKeep: u32 = 1024;
52 pub const ParachainHeadsToKeep: u32 = 64;
53
54 pub const RococoBridgeParachainPalletName: &'static str = "Paras";
55 pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE;
56
57 pub BridgeWestendToRococoMessagesPalletInstance: InteriorLocation = [PalletInstance(<BridgeRococoMessages as PalletInfoAccess>::index() as u8)].into();
58 pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
59 pub RococoGlobalConsensusNetworkLocation: Location = Location::new(
60 2,
61 [GlobalConsensus(RococoGlobalConsensusNetwork::get())]
62 );
63 pub PriorityBoostPerRelayHeader: u64 = 32_007_814_407_814;
65 pub PriorityBoostPerParachainHeader: u64 = 1_396_340_903_540_903;
67 pub PriorityBoostPerMessage: u64 = 364_088_888_888_888;
69
70 pub BridgeHubRococoLocation: Location = Location::new(
71 2,
72 [
73 GlobalConsensus(RococoGlobalConsensusNetwork::get()),
74 Parachain(<bp_bridge_hub_rococo::BridgeHubRococo as bp_runtime::Parachain>::PARACHAIN_ID)
75 ]
76 );
77
78 pub storage BridgeDeposit: Balance = 10 * WND;
79 pub storage DeliveryRewardInBalance: u64 = 1_000_000;
80}
81
82pub type FromRococoBridgeHubMessagesProof<MI> =
84 FromBridgedChainMessagesProof<bp_bridge_hub_rococo::Hash, LaneIdOf<Runtime, MI>>;
85pub type ToRococoBridgeHubMessagesDeliveryProof<MI> =
87 FromBridgedChainMessagesDeliveryProof<bp_bridge_hub_rococo::Hash, LaneIdOf<Runtime, MI>>;
88
89type FromRococoMessageBlobDispatcher =
91 BridgeBlobDispatcher<XcmRouter, UniversalLocation, BridgeWestendToRococoMessagesPalletInstance>;
92
93pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersTransactionExtension<
96 Runtime,
97 WithMessagesExtensionConfig<
98 StrOnBridgeHubWestendRefundBridgeHubRococoMessages,
99 Runtime,
100 WithBridgeHubRococoMessagesInstance,
101 BridgeRelayersInstance,
102 PriorityBoostPerMessage,
103 >,
104>;
105bp_runtime::generate_static_str_provider!(OnBridgeHubWestendRefundBridgeHubRococoMessages);
106
107pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance1;
109impl pallet_bridge_grandpa::Config<BridgeGrandpaRococoInstance> for Runtime {
110 type RuntimeEvent = RuntimeEvent;
111 type BridgedChain = bp_rococo::Rococo;
112 type MaxFreeHeadersPerBlock = ConstU32<4>;
113 type FreeHeadersInterval = ConstU32<5>;
114 type HeadersToKeep = RelayChainHeadersToKeep;
115 type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo<Runtime>;
116}
117
118pub type BridgeParachainRococoInstance = pallet_bridge_parachains::Instance1;
120impl pallet_bridge_parachains::Config<BridgeParachainRococoInstance> for Runtime {
121 type RuntimeEvent = RuntimeEvent;
122 type WeightInfo = weights::pallet_bridge_parachains::WeightInfo<Runtime>;
123 type BridgesGrandpaPalletInstance = BridgeGrandpaRococoInstance;
124 type ParasPalletName = RococoBridgeParachainPalletName;
125 type ParaStoredHeaderDataBuilder =
126 SingleParaStoredHeaderDataBuilder<bp_bridge_hub_rococo::BridgeHubRococo>;
127 type HeadsToKeep = ParachainHeadsToKeep;
128 type MaxParaHeadDataSize = MaxRococoParaHeadDataSize;
129 type OnNewHead = ();
130}
131
132pub type WithBridgeHubRococoMessagesInstance = pallet_bridge_messages::Instance1;
134impl pallet_bridge_messages::Config<WithBridgeHubRococoMessagesInstance> for Runtime {
135 type RuntimeEvent = RuntimeEvent;
136 type WeightInfo = weights::pallet_bridge_messages::WeightInfo<Runtime>;
137
138 type ThisChain = bp_bridge_hub_westend::BridgeHubWestend;
139 type BridgedChain = bp_bridge_hub_rococo::BridgeHubRococo;
140 type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders<
141 Runtime,
142 BridgeParachainRococoInstance,
143 bp_bridge_hub_rococo::BridgeHubRococo,
144 >;
145
146 type OutboundPayload = XcmAsPlainPayload;
147 type InboundPayload = XcmAsPlainPayload;
148 type LaneId = LegacyLaneId;
149
150 type DeliveryPayments = ();
151 type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter<
152 Runtime,
153 WithBridgeHubRococoMessagesInstance,
154 BridgeRelayersInstance,
155 DeliveryRewardInBalance,
156 >;
157
158 type MessageDispatch = XcmOverBridgeHubRococo;
159 type OnMessagesDelivered = XcmOverBridgeHubRococo;
160}
161
162pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1;
164impl pallet_xcm_bridge_hub::Config<XcmOverBridgeHubRococoInstance> for Runtime {
165 type RuntimeEvent = RuntimeEvent;
166
167 type UniversalLocation = UniversalLocation;
168 type BridgedNetwork = RococoGlobalConsensusNetworkLocation;
169 type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance;
170
171 type MessageExportPrice = ();
172 type DestinationVersion = XcmVersionOfDestAndRemoteBridge<PolkadotXcm, BridgeHubRococoLocation>;
173
174 type ForceOrigin = EnsureRoot<AccountId>;
175 type OpenBridgeOrigin = EnsureNever<Location>;
177 type BridgeOriginAccountIdConverter =
179 (ParentIsPreset<AccountId>, SiblingParachainConvertsVia<Sibling, AccountId>);
180
181 type BridgeDeposit = BridgeDeposit;
182 type Currency = Balances;
183 type RuntimeHoldReason = RuntimeHoldReason;
184 type AllowWithoutBridgeDeposit =
186 RelayOrOtherSystemParachains<AllSiblingSystemParachains, Runtime>;
187
188 type LocalXcmChannelManager = CongestionManager;
189 type BlobDispatcher = FromRococoMessageBlobDispatcher;
190}
191
192pub struct CongestionManager;
194impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager {
195 type Error = SendError;
196
197 fn is_congested(with: &Location) -> bool {
198 use bp_xcm_bridge_hub_router::XcmChannelStatusProvider;
202 cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::<Runtime>::is_congested(
203 with,
204 )
205 }
206
207 fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> {
208 send_xcm::<XcmpQueue>(
211 local_origin.clone(),
212 bp_asset_hub_westend::build_congestion_message(bridge.inner(), true).into(),
213 )
214 .map(|_| ())
215 }
216
217 fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> {
218 send_xcm::<XcmpQueue>(
221 local_origin.clone(),
222 bp_asset_hub_westend::build_congestion_message(bridge.inner(), false).into(),
223 )
224 .map(|_| ())
225 }
226}
227
228#[cfg(feature = "runtime-benchmarks")]
229pub(crate) fn open_bridge_for_benchmarks<R, XBHI, C>(
230 with: pallet_xcm_bridge_hub::LaneIdOf<R, XBHI>,
231 sibling_para_id: u32,
232) -> InteriorLocation
233where
234 R: pallet_xcm_bridge_hub::Config<XBHI>,
235 XBHI: 'static,
236 C: xcm_executor::traits::ConvertLocation<
237 bp_runtime::AccountIdOf<pallet_xcm_bridge_hub::ThisChainOf<R, XBHI>>,
238 >,
239{
240 use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState};
241 use sp_runtime::traits::Zero;
242 use xcm::{latest::WESTEND_GENESIS_HASH, VersionedInteriorLocation};
243
244 let lane_id = with;
246 let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]);
247 let universal_source =
248 [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(sibling_para_id)].into();
249 let universal_destination =
250 [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(2075)].into();
251 let bridge_id = BridgeId::new(&universal_source, &universal_destination);
252
253 pallet_xcm_bridge_hub::Bridges::<R, XBHI>::insert(
255 bridge_id,
256 Bridge {
257 bridge_origin_relative_location: alloc::boxed::Box::new(
258 sibling_parachain.clone().into(),
259 ),
260 bridge_origin_universal_location: alloc::boxed::Box::new(
261 VersionedInteriorLocation::from(universal_source.clone()),
262 ),
263 bridge_destination_universal_location: alloc::boxed::Box::new(
264 VersionedInteriorLocation::from(universal_destination),
265 ),
266 state: BridgeState::Opened,
267 bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"),
268 deposit: Zero::zero(),
269 lane_id,
270 },
271 );
272 pallet_xcm_bridge_hub::LaneToBridge::<R, XBHI>::insert(lane_id, bridge_id);
273
274 universal_source
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280 use bridge_runtime_common::{
281 assert_complete_bridge_types,
282 integrity::{
283 assert_complete_with_parachain_bridge_constants, check_message_lane_weights,
284 AssertChainConstants, AssertCompleteBridgeConstants,
285 },
286 };
287
288 const FEE_BOOST_PER_MESSAGE: Balance = 2 * WND;
298
299 const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * WND;
301 const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * WND;
303
304 #[test]
305 fn ensure_bridge_hub_westend_message_lane_weights_are_correct() {
306 check_message_lane_weights::<
307 bp_bridge_hub_westend::BridgeHubWestend,
308 Runtime,
309 WithBridgeHubRococoMessagesInstance,
310 >(
311 bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE,
312 bp_bridge_hub_westend::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
313 bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
314 true,
315 );
316 }
317
318 #[test]
319 fn ensure_bridge_integrity() {
320 assert_complete_bridge_types!(
321 runtime: Runtime,
322 with_bridged_chain_messages_instance: WithBridgeHubRococoMessagesInstance,
323 this_chain: bp_bridge_hub_westend::BridgeHubWestend,
324 bridged_chain: bp_bridge_hub_rococo::BridgeHubRococo,
325 expected_payload_type: XcmAsPlainPayload,
326 );
327
328 assert_complete_with_parachain_bridge_constants::<
329 Runtime,
330 BridgeGrandpaRococoInstance,
331 WithBridgeHubRococoMessagesInstance,
332 >(AssertCompleteBridgeConstants {
333 this_chain_constants: AssertChainConstants {
334 block_length: bp_bridge_hub_westend::BlockLength::get(),
335 block_weights: bp_bridge_hub_westend::BlockWeightsForAsyncBacking::get(),
336 },
337 });
338
339 pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::<
340 Runtime,
341 BridgeGrandpaRococoInstance,
342 PriorityBoostPerRelayHeader,
343 >(FEE_BOOST_PER_RELAY_HEADER);
344
345 pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::<
346 Runtime,
347 WithBridgeHubRococoMessagesInstance,
348 bp_bridge_hub_rococo::BridgeHubRococo,
349 PriorityBoostPerParachainHeader,
350 >(FEE_BOOST_PER_PARACHAIN_HEADER);
351
352 pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::<
353 Runtime,
354 WithBridgeHubRococoMessagesInstance,
355 PriorityBoostPerMessage,
356 >(FEE_BOOST_PER_MESSAGE);
357
358 assert_eq!(
359 BridgeWestendToRococoMessagesPalletInstance::get(),
360 [PalletInstance(
361 bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX
362 )]
363 );
364 }
365}
366
367pub mod migration {
369 use super::*;
370 use bp_messages::LegacyLaneId;
371
372 parameter_types! {
373 pub AssetHubWestendToAssetHubRococoMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]);
374 pub AssetHubWestendLocation: Location = Location::new(1, [Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)]);
375 pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into();
376 }
377
378 mod v1_wrong {
379 use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer};
380 use bp_runtime::AccountIdOf;
381 use codec::{Decode, Encode};
382 use pallet_bridge_messages::BridgedChainOf;
383 use sp_std::collections::vec_deque::VecDeque;
384
385 #[derive(Encode, Decode, Clone, PartialEq, Eq)]
386 pub(crate) struct StoredInboundLaneData<T: pallet_bridge_messages::Config<I>, I: 'static>(
387 pub(crate) InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>,
388 );
389 #[derive(Encode, Decode, Clone, PartialEq, Eq)]
390 pub(crate) struct InboundLaneData<RelayerId> {
391 pub state: LaneState,
392 pub(crate) relayers: VecDeque<UnrewardedRelayer<RelayerId>>,
393 pub(crate) last_confirmed_nonce: MessageNonce,
394 }
395 #[derive(Encode, Decode, Clone, PartialEq, Eq)]
396 pub(crate) struct OutboundLaneData {
397 pub state: LaneState,
398 pub(crate) oldest_unpruned_nonce: MessageNonce,
399 pub(crate) latest_received_nonce: MessageNonce,
400 pub(crate) latest_generated_nonce: MessageNonce,
401 }
402 }
403
404 mod v1 {
405 pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData};
406 pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData};
407 }
408
409 pub struct FixMessagesV1Migration<T, I>(sp_std::marker::PhantomData<(T, I)>);
412
413 impl<T: pallet_bridge_messages::Config<I>, I: 'static> frame_support::traits::OnRuntimeUpgrade
414 for FixMessagesV1Migration<T, I>
415 {
416 fn on_runtime_upgrade() -> Weight {
417 use sp_core::Get;
418 let mut weight = T::DbWeight::get().reads(1);
419
420 let translate_inbound =
422 |pre: v1_wrong::StoredInboundLaneData<T, I>| -> Option<v1::StoredInboundLaneData<T, I>> {
423 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
424 Some(v1::StoredInboundLaneData(v1::InboundLaneData {
425 state: v1::LaneState::Opened,
426 relayers: pre.0.relayers,
427 last_confirmed_nonce: pre.0.last_confirmed_nonce,
428 }))
429 };
430 v1::InboundLanes::<T, I>::translate_values(translate_inbound);
431
432 let translate_outbound =
434 |pre: v1_wrong::OutboundLaneData| -> Option<v1::OutboundLaneData> {
435 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
436 Some(v1::OutboundLaneData {
437 state: v1::LaneState::Opened,
438 oldest_unpruned_nonce: pre.oldest_unpruned_nonce,
439 latest_received_nonce: pre.latest_received_nonce,
440 latest_generated_nonce: pre.latest_generated_nonce,
441 })
442 };
443 v1::OutboundLanes::<T, I>::translate_values(translate_outbound);
444
445 weight
446 }
447 }
448}