From 1a76f1c6aeea84e543cf1dc7b318af1639d73c4d Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 3 Jul 2024 15:16:00 +0200 Subject: [PATCH 01/95] CI fixes --- bridges/primitives/runtime/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 117409b37b94..034e6c12610d 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -26,7 +26,7 @@ frame-system = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } -sp-state-machine = { workspace = true } +sp-state-machine = { optional = true, workspace = true } sp-std = { workspace = true } sp-trie = { workspace = true } trie-db = { workspace = true } @@ -48,9 +48,9 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-state-machine/std", + "sp-state-machine?/std", "sp-std/std", "sp-trie/std", "trie-db/std", ] -test-helpers = [] +test-helpers = ["sp-state-machine"] From 712a6900431f8c2b50d19dc4b7afc074668a6880 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 4 Jul 2024 15:36:29 +0200 Subject: [PATCH 02/95] prune messages from confirmation tx, not from the on_idle (#2211) Original PR with more context: https://github.com/paritytech/parity-bridges-common/pull/2211 Signed-off-by: Branislav Kontur Co-authored-by: Svyatoslav Nikolsky --- bridges/modules/messages/src/lib.rs | 35 ----- bridges/modules/messages/src/outbound_lane.rs | 106 ++------------- .../messages/src/tests/pallet_tests.rs | 124 ------------------ 3 files changed, 13 insertions(+), 252 deletions(-) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index bf105b140401..4b113dbc60c1 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -70,7 +70,6 @@ use bp_runtime::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound}; -use sp_runtime::traits::UniqueSaturatedFrom; use sp_std::{marker::PhantomData, prelude::*}; mod inbound_lane; @@ -153,40 +152,6 @@ pub mod pallet { type OperatingModeStorage = PalletOperatingMode; } - #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet - where - u32: TryFrom>, - { - fn on_idle(_block: BlockNumberFor, remaining_weight: Weight) -> Weight { - // we'll need at least to read outbound lane state, kill a message and update lane state - let db_weight = T::DbWeight::get(); - if !remaining_weight.all_gte(db_weight.reads_writes(1, 2)) { - return Weight::zero() - } - - // messages from lane with index `i` in `ActiveOutboundLanes` are pruned when - // `System::block_number() % lanes.len() == i`. Otherwise we need to read lane states on - // every block, wasting the whole `remaining_weight` for nothing and causing starvation - // of the last lane pruning - let active_lanes = T::ActiveOutboundLanes::get(); - let active_lanes_len = (active_lanes.len() as u32).into(); - let active_lane_index = u32::unique_saturated_from( - frame_system::Pallet::::block_number() % active_lanes_len, - ); - let active_lane_id = active_lanes[active_lane_index as usize]; - - // first db read - outbound lane state - let mut active_lane = outbound_lane::(active_lane_id); - let mut used_weight = db_weight.reads(1); - // and here we'll have writes - used_weight += active_lane.prune_messages(db_weight, remaining_weight - used_weight); - - // we already checked we have enough `remaining_weight` to cover this `used_weight` - used_weight - } - } - #[pallet::call] impl, I: 'static> Pallet { /// Change `PalletOwner`. diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index fcdddf199dc6..788a13e82b1b 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -22,13 +22,9 @@ use bp_messages::{ ChainWithMessages, DeliveredMessages, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; use codec::{Decode, Encode}; -use frame_support::{ - traits::Get, - weights::{RuntimeDbWeight, Weight}, - BoundedVec, PalletError, -}; +use frame_support::{traits::Get, BoundedVec, PalletError}; use scale_info::TypeInfo; -use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_runtime::RuntimeDebug; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; /// Outbound lane storage. @@ -143,41 +139,17 @@ impl OutboundLane { ensure_unrewarded_relayers_are_correct(confirmed_messages.end, relayers)?; + // prune all confirmed messages + for nonce in confirmed_messages.begin..=confirmed_messages.end { + self.storage.remove_message(&nonce); + } + data.latest_received_nonce = confirmed_messages.end; + data.oldest_unpruned_nonce = data.latest_received_nonce.saturating_add(1); self.storage.set_data(data); Ok(Some(confirmed_messages)) } - - /// Prune at most `max_messages_to_prune` already received messages. - /// - /// Returns weight, consumed by messages pruning and lane state update. - pub fn prune_messages( - &mut self, - db_weight: RuntimeDbWeight, - mut remaining_weight: Weight, - ) -> Weight { - let write_weight = db_weight.writes(1); - let two_writes_weight = write_weight + write_weight; - let mut spent_weight = Weight::zero(); - let mut data = self.storage.data(); - while remaining_weight.all_gte(two_writes_weight) && - data.oldest_unpruned_nonce <= data.latest_received_nonce - { - self.storage.remove_message(&data.oldest_unpruned_nonce); - - spent_weight += write_weight; - remaining_weight -= write_weight; - data.oldest_unpruned_nonce += 1; - } - - if !spent_weight.is_zero() { - spent_weight += write_weight; - self.storage.set_data(data); - } - - spent_weight - } } /// Verifies unrewarded relayers vec. @@ -221,7 +193,6 @@ mod tests { REGULAR_PAYLOAD, TEST_LANE_ID, }, }; - use frame_support::weights::constants::RocksDbWeight; use sp_std::ops::RangeInclusive; fn unrewarded_relayers( @@ -281,7 +252,7 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } @@ -302,7 +273,7 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 2); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); assert_eq!( lane.confirm_delivery(3, 3, &unrewarded_relayers(3..=3)), @@ -310,7 +281,7 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } @@ -331,12 +302,12 @@ mod tests { assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); assert_eq!(lane.confirm_delivery(1, 2, &unrewarded_relayers(1..=1)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } @@ -394,57 +365,6 @@ mod tests { ); } - #[test] - fn prune_messages_works() { - run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); - // when lane is empty, nothing is pruned - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - Weight::zero() - ); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - // when nothing is confirmed, nothing is pruned - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - assert!(lane.storage.message(&1).is_some()); - assert!(lane.storage.message(&2).is_some()); - assert!(lane.storage.message(&3).is_some()); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - Weight::zero() - ); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - // after confirmation, some messages are received - assert_eq!( - lane.confirm_delivery(2, 2, &unrewarded_relayers(1..=2)), - Ok(Some(delivered_messages(1..=2))), - ); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - RocksDbWeight::get().writes(3), - ); - assert!(lane.storage.message(&1).is_none()); - assert!(lane.storage.message(&2).is_none()); - assert!(lane.storage.message(&3).is_some()); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); - // after last message is confirmed, everything is pruned - assert_eq!( - lane.confirm_delivery(1, 3, &unrewarded_relayers(3..=3)), - Ok(Some(delivered_messages(3..=3))), - ); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - RocksDbWeight::get().writes(2), - ); - assert!(lane.storage.message(&1).is_none()); - assert!(lane.storage.message(&2).is_none()); - assert!(lane.storage.message(&3).is_none()); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); - }); - } - #[test] fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { run_test(|| { diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 42e1042717de..037baa714af9 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -41,7 +41,6 @@ use frame_support::{ assert_noop, assert_ok, dispatch::Pays, storage::generator::{StorageMap, StorageValue}, - traits::Hooks, weights::Weight, }; use frame_system::{EventRecord, Pallet as System, Phase}; @@ -852,129 +851,6 @@ fn inbound_message_details_works() { }); } -#[test] -fn on_idle_callback_respects_remaining_weight() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - prepare_messages_delivery_proof( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 4, - relayers: vec![unrewarded_relayer(1, 4, TEST_RELAYER_A)].into(), - }, - ), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 4, - total_messages: 4, - last_delivered_nonce: 4, - }, - )); - - // all 4 messages may be pruned now - assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 4); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - System::::set_block_number(2); - - // if passed wight is too low to do anything - let dbw = DbWeight::get(); - assert_eq!(Pallet::::on_idle(0, dbw.reads_writes(1, 1)), Weight::zero(),); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - - // if passed wight is enough to prune single message - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 2)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - - // if passed wight is enough to prune two more messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 3)), - dbw.reads_writes(1, 3), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 4); - - // if passed wight is enough to prune many messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 5); - }); -} - -#[test] -fn on_idle_callback_is_rotating_lanes_to_prune() { - run_test(|| { - // send + receive confirmation for lane 1 - send_regular_message(TEST_LANE_ID); - receive_messages_delivery_proof(); - // send + receive confirmation for lane 2 - send_regular_message(TEST_LANE_ID_2); - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - prepare_messages_delivery_proof( - TEST_LANE_ID_2, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), - }, - ), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - )); - - // nothing is pruned yet - assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 1); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().latest_received_nonce, - 1 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#2.on_idle lane messages of lane 1 are pruned - let dbw = DbWeight::get(); - System::::set_block_number(2); - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#3.on_idle lane messages of lane 2 are pruned - System::::set_block_number(3); - - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 2 - ); - }); -} - #[test] fn outbound_message_from_unconfigured_lane_is_rejected() { run_test(|| { From 1251505e3a232678de573552cc7dd60c8eb5417b Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 4 Jul 2024 23:02:40 +0200 Subject: [PATCH 03/95] Added `do_try_state_for_outbound_lanes` which checks unpruned messages --- bridges/modules/messages/src/lib.rs | 62 +++++++++++++++++++ .../messages/src/tests/pallet_tests.rs | 11 +++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 4b113dbc60c1..f664f9931308 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -575,6 +575,14 @@ pub mod pallet { } } + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } + impl, I: 'static> Pallet { /// Get stored data of the outbound message with given nonce. pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option { @@ -609,6 +617,60 @@ pub mod pallet { } } + #[cfg(any(feature = "try-runtime", test))] + impl, I: 'static> Pallet { + /// Ensure the correctness of the state of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state_for_outbound_lanes() + } + + /// Ensure the correctness of the state of outbound lanes. + pub fn do_try_state_for_outbound_lanes() -> Result<(), sp_runtime::TryRuntimeError> { + use sp_runtime::traits::One; + use sp_std::vec::Vec; + + // collect unpruned lanes + let mut unpruned_lanes = Vec::new(); + for (lane_id, lane_data) in OutboundLanes::::iter() { + let Some(expected_last_prunned_nonce) = + lane_data.oldest_unpruned_nonce.checked_sub(One::one()) + else { + continue; + }; + + // collect message_nonces that were supposed to be pruned + let mut unpruned_message_nonces = Vec::new(); + let mut nonce_to_check = expected_last_prunned_nonce; + loop { + if OutboundMessages::::contains_key(MessageKey { + lane_id, + nonce: nonce_to_check, + }) { + unpruned_message_nonces.push(nonce_to_check); + } + if let Some(new_nonce_to_check) = nonce_to_check.checked_sub(One::one()) { + nonce_to_check = new_nonce_to_check; + } else { + break; + } + } + + if !unpruned_message_nonces.is_empty() { + log::warn!( + target: LOG_TARGET, + "do_try_state_for_outbound_lanes for lane_id: {lane_id:?} with lane_data: {lane_data:?} found unpruned_message_nonces: {unpruned_message_nonces:?}", + ); + unpruned_lanes.push((lane_id, lane_data, unpruned_message_nonces)); + } + } + + // ensure messages before `oldest_unpruned_nonce` are really pruned. + ensure!(unpruned_lanes.is_empty(), "Found unpruned lanes!"); + + Ok(()) + } + } + /// Get-parameter that returns number of active outbound lanes that the pallet maintains. pub struct MaybeOutboundLanesCount(PhantomData<(T, I)>); diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 037baa714af9..cc43125d0c35 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -98,6 +98,7 @@ fn receive_messages_delivery_proof() { last_delivered_nonce: 1, }, )); + assert_ok!(Pallet::::do_try_state()); assert_eq!( System::::events(), @@ -159,6 +160,7 @@ fn pallet_rejects_transactions_if_halted() { ), Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), ); + assert_ok!(Pallet::::do_try_state()); }); } @@ -219,6 +221,7 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { last_delivered_nonce: 1, }, )); + assert_ok!(Pallet::::do_try_state()); }); } @@ -394,10 +397,14 @@ fn receive_messages_proof_rejects_proof_with_too_many_messages() { #[test] fn receive_messages_delivery_proof_works() { run_test(|| { + assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 0); + assert_eq!(OutboundLanes::::get(TEST_LANE_ID).oldest_unpruned_nonce, 1); + send_regular_message(TEST_LANE_ID); receive_messages_delivery_proof(); - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1,); + assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1); + assert_eq!(OutboundLanes::::get(TEST_LANE_ID).oldest_unpruned_nonce, 2); }); } @@ -427,6 +434,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ); assert_ok!(result); + assert_ok!(Pallet::::do_try_state()); assert_eq!( result.unwrap().actual_weight.unwrap(), TestWeightInfo::receive_messages_delivery_proof_weight( @@ -466,6 +474,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ); assert_ok!(result); + assert_ok!(Pallet::::do_try_state()); // even though the pre-dispatch weight was for two messages, the actual weight is // for single message only assert_eq!( From 0feaa40139fd6cfc6b27ffe7962232ee64c8c741 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 4 Jul 2024 15:08:53 +0000 Subject: [PATCH 04/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_messages --- .../src/weights/pallet_bridge_messages.rs | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs index 386342d7ea5d..1033387b527e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 @@ -62,8 +62,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `522` // Estimated: `52645` - // Minimum execution time: 40_748_000 picoseconds. - Weight::from_parts(41_836_000, 0) + // Minimum execution time: 40_289_000 picoseconds. + Weight::from_parts(42_150_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -83,11 +83,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `522` // Estimated: `52645` - // Minimum execution time: 40_923_000 picoseconds. - Weight::from_parts(41_287_000, 0) + // Minimum execution time: 40_572_000 picoseconds. + Weight::from_parts(41_033_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 9_774 - .saturating_add(Weight::from_parts(11_469_207, 0).saturating_mul(n.into())) + // Standard Error: 12_000 + .saturating_add(Weight::from_parts(11_710_588, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -105,8 +105,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `522` // Estimated: `52645` - // Minimum execution time: 45_946_000 picoseconds. - Weight::from_parts(47_547_000, 0) + // Minimum execution time: 46_655_000 picoseconds. + Weight::from_parts(49_576_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -126,11 +126,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `522` // Estimated: `52645` - // Minimum execution time: 39_668_000 picoseconds. - Weight::from_parts(41_908_980, 0) + // Minimum execution time: 40_245_000 picoseconds. + Weight::from_parts(43_461_320, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(2_209, 0).saturating_mul(n.into())) + // Standard Error: 21 + .saturating_add(Weight::from_parts(2_246, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -144,15 +144,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3822` - // Minimum execution time: 30_544_000 picoseconds. - Weight::from_parts(31_171_000, 0) + // Minimum execution time: 32_001_000 picoseconds. + Weight::from_parts(32_842_000, 0) .saturating_add(Weight::from_parts(0, 3822)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -164,15 +166,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3822` - // Minimum execution time: 30_593_000 picoseconds. - Weight::from_parts(31_261_000, 0) + // Minimum execution time: 33_287_000 picoseconds. + Weight::from_parts(33_769_000, 0) .saturating_add(Weight::from_parts(0, 3822)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -184,15 +188,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: // Measured: `357` // Estimated: `6086` - // Minimum execution time: 34_682_000 picoseconds. - Weight::from_parts(35_277_000, 0) + // Minimum execution time: 37_136_000 picoseconds. + Weight::from_parts(38_294_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -221,11 +227,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `653` // Estimated: `52645` - // Minimum execution time: 56_465_000 picoseconds. - Weight::from_parts(61_575_775, 0) + // Minimum execution time: 55_942_000 picoseconds. + Weight::from_parts(60_615_769, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 15 - .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) + // Standard Error: 14 + .saturating_add(Weight::from_parts(7_225, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } From 4cbe6373c33a0b170a2266868185faae902e328d Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 4 Jul 2024 15:14:24 +0000 Subject: [PATCH 05/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_messages --- ...idge_messages_rococo_to_rococo_bulletin.rs | 56 ++++++++++-------- ...allet_bridge_messages_rococo_to_westend.rs | 58 ++++++++++--------- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs index 5522a325f192..d0a7ed25363d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 @@ -60,8 +60,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `654` // Estimated: `52645` - // Minimum execution time: 37_206_000 picoseconds. - Weight::from_parts(38_545_000, 0) + // Minimum execution time: 36_836_000 picoseconds. + Weight::from_parts(37_858_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -80,11 +80,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `654` // Estimated: `52645` - // Minimum execution time: 37_075_000 picoseconds. - Weight::from_parts(37_757_000, 0) + // Minimum execution time: 36_587_000 picoseconds. + Weight::from_parts(37_516_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 5_776 - .saturating_add(Weight::from_parts(11_586_768, 0).saturating_mul(n.into())) + // Standard Error: 8_655 + .saturating_add(Weight::from_parts(11_649_169, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -100,8 +100,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `654` // Estimated: `52645` - // Minimum execution time: 42_087_000 picoseconds. - Weight::from_parts(42_970_000, 0) + // Minimum execution time: 42_157_000 picoseconds. + Weight::from_parts(43_105_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -120,11 +120,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `654` // Estimated: `52645` - // Minimum execution time: 35_055_000 picoseconds. - Weight::from_parts(36_987_740, 0) + // Minimum execution time: 35_536_000 picoseconds. + Weight::from_parts(37_452_828, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_316, 0).saturating_mul(n.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(2_269, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,15 +134,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: // Measured: `621` // Estimated: `2543` - // Minimum execution time: 24_326_000 picoseconds. - Weight::from_parts(25_169_000, 0) + // Minimum execution time: 25_800_000 picoseconds. + Weight::from_parts(26_666_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -150,15 +152,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: // Measured: `621` // Estimated: `2543` - // Minimum execution time: 24_484_000 picoseconds. - Weight::from_parts(25_130_000, 0) + // Minimum execution time: 27_262_000 picoseconds. + Weight::from_parts(27_997_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -166,15 +170,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: // Measured: `621` // Estimated: `2543` - // Minimum execution time: 24_450_000 picoseconds. - Weight::from_parts(25_164_000, 0) + // Minimum execution time: 26_992_000 picoseconds. + Weight::from_parts(27_921_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -204,11 +210,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `813` // Estimated: `52645` - // Minimum execution time: 54_317_000 picoseconds. - Weight::from_parts(59_171_547, 0) + // Minimum execution time: 55_509_000 picoseconds. + Weight::from_parts(59_826_763, 0) .saturating_add(Weight::from_parts(0, 52645)) // Standard Error: 7 - .saturating_add(Weight::from_parts(7_566, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(7_565, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs index 9c05dae979da..dc6c917c6d00 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 @@ -62,8 +62,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `658` // Estimated: `52645` - // Minimum execution time: 41_396_000 picoseconds. - Weight::from_parts(43_141_000, 0) + // Minimum execution time: 40_198_000 picoseconds. + Weight::from_parts(42_079_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -84,11 +84,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `658` // Estimated: `52645` - // Minimum execution time: 41_095_000 picoseconds. - Weight::from_parts(42_030_000, 0) + // Minimum execution time: 39_990_000 picoseconds. + Weight::from_parts(41_381_000, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 5_702 - .saturating_add(Weight::from_parts(11_627_951, 0).saturating_mul(n.into())) + // Standard Error: 8_459 + .saturating_add(Weight::from_parts(11_710_167, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -106,8 +106,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `658` // Estimated: `52645` - // Minimum execution time: 45_912_000 picoseconds. - Weight::from_parts(47_564_000, 0) + // Minimum execution time: 45_940_000 picoseconds. + Weight::from_parts(47_753_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -128,11 +128,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `658` // Estimated: `52645` - // Minimum execution time: 39_175_000 picoseconds. - Weight::from_parts(41_674_095, 0) + // Minimum execution time: 39_067_000 picoseconds. + Weight::from_parts(41_787_019, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_305, 0).saturating_mul(n.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -146,15 +146,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: // Measured: `501` // Estimated: `3966` - // Minimum execution time: 32_033_000 picoseconds. - Weight::from_parts(33_131_000, 0) + // Minimum execution time: 33_107_000 picoseconds. + Weight::from_parts(34_364_000, 0) .saturating_add(Weight::from_parts(0, 3966)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -166,15 +168,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: // Measured: `501` // Estimated: `3966` - // Minimum execution time: 32_153_000 picoseconds. - Weight::from_parts(33_126_000, 0) + // Minimum execution time: 34_826_000 picoseconds. + Weight::from_parts(35_563_000, 0) .saturating_add(Weight::from_parts(0, 3966)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -186,15 +190,17 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: // Measured: `501` // Estimated: `6086` - // Minimum execution time: 36_387_000 picoseconds. - Weight::from_parts(37_396_000, 0) + // Minimum execution time: 38_725_000 picoseconds. + Weight::from_parts(39_727_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -224,11 +230,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `789` // Estimated: `52645` - // Minimum execution time: 56_562_000 picoseconds. - Weight::from_parts(61_452_871, 0) + // Minimum execution time: 56_892_000 picoseconds. + Weight::from_parts(61_941_659, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(7_587, 0).saturating_mul(n.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(7_580, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } From d7f4f43fae942dacd1dc3db8de33e6ce15705e62 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 20 Jun 2023 12:10:18 +0300 Subject: [PATCH 06/95] Add state to message lanes (#2214) * add LaneState enum and a field to lanes data * use OptionQuery in InboundLanes and OutboundLanes * ensure that lanes are opened when accessing them * an option to specify opened lanes in genesis config + fixed tests * added PR reference to TODO * fix failing benchmarks * spelling * get_or_init_data -> data bump Substrate, Polkadot and Cumulus (#2223) --- .../extensions/refund_relayer_extension.rs | 4 +- bridges/bin/runtime-common/src/integrity.rs | 6 - .../runtime-common/src/messages_call_ext.rs | 102 +++++---- .../src/messages_xcm_extension.rs | 3 +- bridges/bin/runtime-common/src/mock.rs | 2 - bridges/modules/messages/README.md | 7 +- bridges/modules/messages/src/benchmarking.rs | 63 ++++-- bridges/modules/messages/src/inbound_lane.rs | 60 +++--- bridges/modules/messages/src/lib.rs | 113 ++++++---- bridges/modules/messages/src/outbound_lane.rs | 13 +- bridges/modules/messages/src/proofs.rs | 8 +- bridges/modules/messages/src/tests/mock.rs | 31 ++- .../messages/src/tests/pallet_tests.rs | 197 ++++++++++++++---- .../modules/xcm-bridge-hub/src/exporter.rs | 20 +- bridges/modules/xcm-bridge-hub/src/mock.rs | 1 - bridges/primitives/messages/src/lib.rs | 51 ++++- .../lib-substrate-relay/src/messages/mod.rs | 1 - 17 files changed, 481 insertions(+), 201 deletions(-) diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 6ba3506377d0..0b74fa898bca 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -943,7 +943,7 @@ pub(crate) mod tests { use bp_header_chain::StoredHeaderDataBuilder; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, + target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState, MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; @@ -1149,6 +1149,7 @@ pub(crate) mod tests { nonces_start: pallet_bridge_messages::InboundLanes::::get( TEST_LANE_ID, ) + .unwrap() .last_delivered_nonce() + 1, nonces_end: best_message, @@ -2884,6 +2885,7 @@ pub(crate) mod tests { // allow empty message delivery transactions let lane_id = TestLaneId::get(); let in_lane_data = InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 0, relayers: vec![UnrewardedRelayer { relayer: relayer_account_at_bridged_chain(), diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index a0a9367dd140..6757191995a6 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -174,12 +174,6 @@ where R: pallet_bridge_messages::Config, MI: 'static, { - assert!( - !R::ActiveOutboundLanes::get().is_empty(), - "ActiveOutboundLanes ({:?}) must not be empty", - R::ActiveOutboundLanes::get(), - ); - assert!( pallet_bridge_messages::BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX <= pallet_bridge_messages::BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index a9ee1969ae0c..5eadb0a32480 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -146,7 +146,10 @@ impl, I: 'static> CallHelper { match info { CallInfo::ReceiveMessagesProof(info) => { let inbound_lane_data = - pallet_bridge_messages::InboundLanes::::get(info.base.lane_id); + match pallet_bridge_messages::InboundLanes::::get(info.base.lane_id) { + Some(inbound_lane_data) => inbound_lane_data, + None => return false, + }; if info.base.bundled_range.is_empty() { let post_occupation = unrewarded_relayers_occupation::(&inbound_lane_data); @@ -162,7 +165,10 @@ impl, I: 'static> CallHelper { }, CallInfo::ReceiveMessagesDeliveryProof(info) => { let outbound_lane_data = - pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id); + match pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id) { + Some(outbound_lane_data) => outbound_lane_data, + None => return false, + }; outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end() }, } @@ -219,7 +225,7 @@ impl< .. }) = self.is_sub_type() { - let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane); + let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -243,7 +249,8 @@ impl< .. }) = self.is_sub_type() { - let outbound_lane_data = pallet_bridge_messages::OutboundLanes::::get(proof.lane); + let outbound_lane_data = + pallet_bridge_messages::OutboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: proof.lane, @@ -349,14 +356,16 @@ mod tests { }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, DeliveredMessages, UnrewardedRelayer, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState, + OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use sp_std::ops::RangeInclusive; + const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); + fn fill_unrewarded_relayers() { let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + pallet_bridge_messages::InboundLanes::::get(TEST_LANE_ID).unwrap(); for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), @@ -364,14 +373,14 @@ mod tests { }); } pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), + TEST_LANE_ID, inbound_lane_state, ); } fn fill_unrewarded_messages() { let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + pallet_bridge_messages::InboundLanes::::get(TEST_LANE_ID).unwrap(); inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { @@ -380,15 +389,19 @@ mod tests { }, }); pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), + TEST_LANE_ID, inbound_lane_state, ); } fn deliver_message_10() { pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), - bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 }, + TEST_LANE_ID, + bp_messages::InboundLaneData { + state: LaneState::Opened, + relayers: Default::default(), + last_confirmed_nonce: 10, + }, ); } @@ -405,7 +418,7 @@ mod tests { proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: TEST_LANE_ID, nonces_start, nonces_end, }), @@ -415,9 +428,23 @@ mod tests { .is_ok() } + fn run_test(test: impl Fn() -> T) -> T { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + pallet_bridge_messages::InboundLanes::::insert( + TEST_LANE_ID, + InboundLaneData::opened(), + ); + pallet_bridge_messages::OutboundLanes::::insert( + TEST_LANE_ID, + OutboundLaneData::opened(), + ); + test() + }) + } + #[test] fn extension_rejects_obsolete_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages 8..=9 // => tx is rejected deliver_message_10(); @@ -427,7 +454,7 @@ mod tests { #[test] fn extension_rejects_same_message() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to import messages 10..=10 // => tx is rejected deliver_message_10(); @@ -437,7 +464,7 @@ mod tests { #[test] fn extension_rejects_call_with_some_obsolete_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages // 10..=15 => tx is rejected deliver_message_10(); @@ -447,7 +474,7 @@ mod tests { #[test] fn extension_rejects_call_with_future_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages // 13..=15 => tx is rejected deliver_message_10(); @@ -470,7 +497,7 @@ mod tests { #[test] fn extension_rejects_empty_delivery_with_rewards_confirmations_if_there_are_free_relayer_and_message_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!validate_message_delivery(10, 9)); }); @@ -479,7 +506,7 @@ mod tests { #[test] fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_relayer_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); fill_unrewarded_relayers(); assert!(validate_message_delivery(10, 9)); @@ -489,7 +516,7 @@ mod tests { #[test] fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_message_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { fill_unrewarded_messages(); assert!(validate_message_delivery( BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, @@ -500,7 +527,7 @@ mod tests { #[test] fn extension_accepts_new_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver message 11..=15 // => tx is accepted deliver_message_10(); @@ -510,8 +537,9 @@ mod tests { fn confirm_message_10() { pallet_bridge_messages::OutboundLanes::::insert( - LaneId([0, 0, 0, 0]), + TEST_LANE_ID, bp_messages::OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 0, latest_received_nonce: 10, latest_generated_nonce: 10, @@ -525,7 +553,7 @@ mod tests { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: TEST_LANE_ID, }, relayers_state: UnrewardedRelayersState { last_delivered_nonce, @@ -539,7 +567,7 @@ mod tests { #[test] fn extension_rejects_obsolete_confirmations() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#5 => tx // is rejected confirm_message_10(); @@ -549,7 +577,7 @@ mod tests { #[test] fn extension_rejects_same_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#10 => // tx is rejected confirm_message_10(); @@ -559,7 +587,7 @@ mod tests { #[test] fn extension_rejects_empty_confirmation_even_if_there_are_no_free_unrewarded_entries() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); fill_unrewarded_relayers(); assert!(!validate_message_confirmation(10)); @@ -568,7 +596,7 @@ mod tests { #[test] fn extension_accepts_new_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#15 => // tx is accepted confirm_message_10(); @@ -583,7 +611,7 @@ mod tests { CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: LaneId([0, 0, 0, 0]), + lane_id: TEST_LANE_ID, bundled_range, best_stored_nonce: 0, // doesn't matter for `was_successful` }, @@ -602,7 +630,7 @@ mod tests { #[test] #[allow(clippy::reversed_empty_ranges)] fn was_successful_returns_false_for_failed_reward_confirmation_transaction() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { fill_unrewarded_messages(); assert!(!was_message_delivery_successful(10..=9, true)); }); @@ -611,14 +639,14 @@ mod tests { #[test] #[allow(clippy::reversed_empty_ranges)] fn was_successful_returns_true_for_successful_reward_confirmation_transaction() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { assert!(was_message_delivery_successful(10..=9, true)); }); } #[test] fn was_successful_returns_false_for_failed_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!was_message_delivery_successful(10..=12, false)); }); @@ -626,7 +654,7 @@ mod tests { #[test] fn was_successful_returns_false_for_partially_successful_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!was_message_delivery_successful(9..=12, false)); }); @@ -634,7 +662,7 @@ mod tests { #[test] fn was_successful_returns_true_for_successful_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(was_message_delivery_successful(9..=10, false)); }); @@ -643,7 +671,7 @@ mod tests { fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: LaneId([0, 0, 0, 0]), + lane_id: TEST_LANE_ID, bundled_range, best_stored_nonce: 0, // doesn't matter for `was_successful` }), @@ -652,7 +680,7 @@ mod tests { #[test] fn was_successful_returns_false_for_failed_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(!was_message_confirmation_successful(10..=12)); }); @@ -660,7 +688,7 @@ mod tests { #[test] fn was_successful_returns_false_for_partially_successful_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(!was_message_confirmation_successful(9..=12)); }); @@ -668,7 +696,7 @@ mod tests { #[test] fn was_successful_returns_true_for_successful_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(was_message_confirmation_successful(9..=10)); }); diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 46ed4da0d854..0ea2f8b9619a 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -339,7 +339,7 @@ mod tests { use super::*; use crate::mock::*; - use bp_messages::OutboundLaneData; + use bp_messages::{LaneState, OutboundLaneData}; use frame_support::parameter_types; use pallet_bridge_messages::OutboundLanes; @@ -397,6 +397,7 @@ mod tests { OutboundLanes::::insert( TEST_LANE_ID, OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 0, latest_received_nonce: 0, latest_generated_nonce, diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 2f248a7162a6..decbf5c687d1 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -111,7 +111,6 @@ crate::generate_bridge_reject_obsolete_headers_and_messages! { } parameter_types! { - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; pub const BridgedParasPalletName: &'static str = "Paras"; pub const ExistentialDeposit: ThisChainBalance = 500; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; @@ -185,7 +184,6 @@ impl pallet_bridge_parachains::Config for TestRuntime { impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; - type ActiveOutboundLanes = ActiveOutboundLanes; type OutboundPayload = XcmAsPlainPayload; diff --git a/bridges/modules/messages/README.md b/bridges/modules/messages/README.md index 80fd92eb0e5a..bf5cced43854 100644 --- a/bridges/modules/messages/README.md +++ b/bridges/modules/messages/README.md @@ -142,10 +142,9 @@ and will simply reject all transactions, related to inbound messages. ### What about other Constants in the Messages Module Configuration Trait? -Two settings that are used to check messages in the `send_message()` function. The -`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that -may be used to send messages. All messages sent using other lanes are rejected. All messages that have -size above `pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. +`pallet_bridge_messages::Config::MaximalOutboundPayloadSize` constant defines the maximal size +of outbound message that may be sent. If the message size is above this limit, the message is +rejected. To be able to reward the relayer for delivering messages, we store a map of message nonces range => identifier of the relayer that has delivered this range at the target chain runtime storage. If a diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index d38aaf32dc94..f73c5ba1442a 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -19,14 +19,14 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{ - inbound_lane::InboundLaneStorage, outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, - BridgedChainOf, Call, OutboundLanes, RuntimeInboundLaneStorage, + outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, BridgedChainOf, Call, + InboundLanes, OutboundLanes, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, ChainWithMessages, DeliveredMessages, - InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, + InboundLaneData, LaneId, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, HashOf, UnverifiedStorageProofParams}; @@ -113,22 +113,32 @@ pub trait Config: crate::Config { } fn send_regular_message, I: 'static>() { - let mut outbound_lane = outbound_lane::(T::bench_lane_id()); + OutboundLanes::::insert( + T::bench_lane_id(), + OutboundLaneData { + state: LaneState::Opened, + latest_generated_nonce: 1, + ..Default::default() + }, + ); + + let mut outbound_lane = outbound_lane::(T::bench_lane_id()).unwrap(); outbound_lane.send_message(BoundedVec::try_from(vec![]).expect("We craft valid messages")); } fn receive_messages, I: 'static>(nonce: MessageNonce) { - let mut inbound_lane_storage = - RuntimeInboundLaneStorage::::from_lane_id(T::bench_lane_id()); - inbound_lane_storage.set_data(InboundLaneData { - relayers: vec![UnrewardedRelayer { - relayer: T::bridged_relayer_id(), - messages: DeliveredMessages::new(nonce), - }] - .into_iter() - .collect(), - last_confirmed_nonce: 0, - }); + InboundLanes::::insert( + T::bench_lane_id(), + InboundLaneData { + state: LaneState::Opened, + relayers: vec![UnrewardedRelayer { + relayer: T::bridged_relayer_id(), + messages: DeliveredMessages::new(nonce), + }] + .into(), + last_confirmed_nonce: 0, + }, + ); } struct ReceiveMessagesProofSetup, I: 'static> { @@ -173,8 +183,8 @@ impl, I: 'static> ReceiveMessagesProofSetup { fn check_last_nonce(&self) { assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - self.last_nonce(), + crate::InboundLanes::::get(&T::bench_lane_id()).map(|d| d.last_delivered_nonce()), + Some(self.last_nonce()), ); } } @@ -277,6 +287,7 @@ mod benchmarks { lane: T::bench_lane_id(), message_nonces: setup.nonces(), outbound_lane_data: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: setup.last_nonce(), latest_received_nonce: ReceiveMessagesProofSetup::::LATEST_RECEIVED_NONCE, latest_generated_nonce: setup.last_nonce(), @@ -356,6 +367,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: DeliveredMessages::new(1), @@ -374,7 +386,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 1); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(1) + ); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -404,6 +419,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: delivered_messages, @@ -422,7 +438,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(2) + ); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -451,6 +470,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer1_id.clone(), @@ -475,7 +495,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(2) + ); assert!(T::is_relayer_rewarded(&relayer1_id)); assert!(T::is_relayer_rewarded(&relayer2_id)); } diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 7ef4599a93c4..5061d63bd30e 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -41,7 +41,7 @@ pub trait InboundLaneStorage { /// Return maximal number of unconfirmed messages in inbound lane. fn max_unconfirmed_messages(&self) -> MessageNonce; /// Get lane data from the storage. - fn get_or_init_data(&mut self) -> InboundLaneData; + fn data(&self) -> InboundLaneData; /// Update lane data in the storage. fn set_data(&mut self, data: InboundLaneData); } @@ -130,7 +130,7 @@ impl InboundLane { &mut self, outbound_lane_data: OutboundLaneData, ) -> Option { - let mut data = self.storage.get_or_init_data(); + let mut data = self.storage.data(); let last_delivered_nonce = data.last_delivered_nonce(); if outbound_lane_data.latest_received_nonce > last_delivered_nonce { @@ -173,7 +173,7 @@ impl InboundLane { nonce: MessageNonce, message_data: DispatchMessageData, ) -> ReceptionResult { - let mut data = self.storage.get_or_init_data(); + let mut data = self.storage.data(); if Some(nonce) != data.last_delivered_nonce().checked_add(1) { return ReceptionResult::InvalidNonce } @@ -244,7 +244,7 @@ mod tests { #[test] fn receive_status_update_ignores_status_from_the_future() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -254,14 +254,14 @@ mod tests { None, ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 0); + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); }); } #[test] fn receive_status_update_ignores_obsolete_status() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -272,7 +272,7 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -281,20 +281,20 @@ mod tests { }), None, ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); }); } #[test] fn receive_status_update_works() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 0); + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![unrewarded_relayer(1, 3, TEST_RELAYER_A)] ); @@ -305,9 +305,9 @@ mod tests { }), Some(2), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 2); + assert_eq!(lane.storage.data().last_confirmed_nonce, 2); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![unrewarded_relayer(3, 3, TEST_RELAYER_A)] ); @@ -318,16 +318,16 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); - assert_eq!(lane.storage.get_or_init_data().relayers, vec![]); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().relayers, vec![]); }); } #[test] fn receive_status_update_works_with_batches_from_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); - let mut seed_storage_data = lane.storage.get_or_init_data(); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut seed_storage_data = lane.storage.data(); // Prepare data seed_storage_data.last_confirmed_nonce = 0; seed_storage_data.relayers.push_back(unrewarded_relayer(1, 1, TEST_RELAYER_A)); @@ -343,9 +343,9 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![ unrewarded_relayer(4, 4, TEST_RELAYER_B), unrewarded_relayer(5, 5, TEST_RELAYER_C) @@ -357,7 +357,7 @@ mod tests { #[test] fn fails_to_receive_message_with_incorrect_nonce() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -366,14 +366,14 @@ mod tests { ), ReceptionResult::InvalidNonce ); - assert_eq!(lane.storage.get_or_init_data().last_delivered_nonce(), 0); + assert_eq!(lane.storage.data().last_delivered_nonce(), 0); }); } #[test] fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); let max_nonce = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; for current_nonce in 1..max_nonce + 1 { assert_eq!( @@ -409,7 +409,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); let max_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; for current_nonce in 1..=max_nonce { assert_eq!( @@ -445,7 +445,7 @@ mod tests { #[test] fn correctly_receives_following_messages_from_two_relayers_alternately() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -471,7 +471,7 @@ mod tests { ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), unrewarded_relayer(2, 2, TEST_RELAYER_B), @@ -484,7 +484,7 @@ mod tests { #[test] fn rejects_same_message_from_two_different_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -507,16 +507,16 @@ mod tests { #[test] fn correct_message_is_processed_instantly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); receive_regular_message(&mut lane, 1); - assert_eq!(lane.storage.get_or_init_data().last_delivered_nonce(), 1); + assert_eq!(lane.storage.data().last_delivered_nonce(), 1); }); } #[test] fn unspent_weight_is_returned_by_receive_message() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); let mut payload = REGULAR_PAYLOAD; *payload.dispatch_result.unspent_weight.ref_time_mut() = 1; assert_eq!( @@ -533,7 +533,7 @@ mod tests { #[test] fn first_message_is_confirmed_correctly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); assert_eq!( diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index f664f9931308..b8a7fba6c1e8 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -61,7 +61,7 @@ use bp_messages::{ ProvedLaneMessages, ProvedMessages, }, ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, + LaneState, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ @@ -115,9 +115,6 @@ pub mod pallet { /// Bridged chain headers provider. type BridgedHeaderChain: HeaderChain; - /// Get all active outbound lanes that the message pallet is serving. - type ActiveOutboundLanes: Get<&'static [LaneId]>; - /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter + Size; /// Payload type of inbound messages. This payload is dispatched on this chain. @@ -249,7 +246,7 @@ pub mod pallet { let mut messages_received_status = Vec::with_capacity(messages.len()); let mut dispatch_weight_left = dispatch_weight; for (lane_id, lane_data) in messages { - let mut lane = inbound_lane::(lane_id); + let mut lane = inbound_lane::(lane_id)?; // subtract extra storage proof bytes from the actual PoV size - there may be // less unrewarded relayers than the maximal configured value @@ -266,7 +263,7 @@ pub mod pallet { "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", lane_id, updated_latest_confirmed_nonce, - UnrewardedRelayersState::from(&lane.storage_mut().get_or_init_data()), + UnrewardedRelayersState::from(&lane.storage_mut().data()), ); } } @@ -377,7 +374,7 @@ pub mod pallet { ); // mark messages as delivered - let mut lane = outbound_lane::(lane_id); + let mut lane = outbound_lane::(lane_id)?; let last_delivered_nonce = lane_data.last_delivered_nonce(); let confirmed_messages = lane .confirm_delivery( @@ -468,10 +465,17 @@ pub mod pallet { pub enum Error { /// Pallet is not in Normal operating mode. NotOperatingNormally, - /// The outbound lane is inactive. - InactiveOutboundLane, /// The inbound message dispatcher is inactive. MessageDispatchInactive, + /// The outbound lane is unknown. + UnknownOutboundLane, + /// The outbound lane exists, but it is currently closed. + ClosedOutboundLane, + /// The inbound lane is unknown. + UnknownInboundLane, + /// The inbound lane exists, but it is currently closed. + ClosedInboundLane, + /// Message has been treated as invalid by chain verifier. /// Message has been treated as invalid by the pallet logic. MessageRejectedByPallet(VerificationError), /// Submitter has failed to pay fee for delivering and dispatching messages. @@ -514,10 +518,13 @@ pub mod pallet { pub type PalletOperatingMode, I: 'static = ()> = StorageValue<_, MessagesOperatingMode, ValueQuery>; + // TODO: https://github.com/paritytech/parity-bridges-common/pull/2213: let's limit number of + // possible opened lanes && use it to constraint maps below + /// Map of lane id => inbound lane data. #[pallet::storage] pub type InboundLanes, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, ValueQuery>; + StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, OptionQuery>; /// Map of lane id => outbound lane data. #[pallet::storage] @@ -525,11 +532,10 @@ pub mod pallet { Hasher = Blake2_128Concat, Key = LaneId, Value = OutboundLaneData, - QueryKind = ValueQuery, - OnEmpty = GetDefault, - MaxValues = MaybeOutboundLanesCount, + QueryKind = OptionQuery, >; + // TODO:(bridges-v2) - do we still need this? /// Map of lane id => is congested signal sent. It is managed by the /// `bridge_runtime_common::LocalXcmQueueManager`. /// @@ -561,6 +567,8 @@ pub mod pallet { pub operating_mode: MessagesOperatingMode, /// Initial pallet owner. pub owner: Option, + /// Opened lanes. + pub opened_lanes: Vec, /// Dummy marker. pub phantom: sp_std::marker::PhantomData, } @@ -572,6 +580,11 @@ pub mod pallet { if let Some(ref owner) = self.owner { PalletOwner::::put(owner); } + + for lane_id in &self.opened_lanes { + InboundLanes::::insert(lane_id, InboundLaneData::opened()); + OutboundLanes::::insert(lane_id, OutboundLaneData::opened()); + } } } @@ -605,15 +618,15 @@ pub mod pallet { } /// Return outbound lane data. - pub fn outbound_lane_data(lane: LaneId) -> OutboundLaneData { + pub fn outbound_lane_data(lane: LaneId) -> Option { OutboundLanes::::get(lane) } /// Return inbound lane data. pub fn inbound_lane_data( lane: LaneId, - ) -> InboundLaneData>> { - InboundLanes::::get(lane).0 + ) -> Option>>> { + InboundLanes::::get(lane).map(|lane| lane.0) } } @@ -676,7 +689,7 @@ pub mod pallet { impl, I: 'static> Get> for MaybeOutboundLanesCount { fn get() -> Option { - Some(T::ActiveOutboundLanes::get().len() as u32) + Some(OutboundLanes::::iter().count() as u32) } } } @@ -686,6 +699,7 @@ pub mod pallet { #[derive(Debug, PartialEq, Eq)] pub struct SendMessageArgs, I: 'static> { lane_id: LaneId, + lane: OutboundLane>, payload: StoredMessagePayload, } @@ -698,16 +712,17 @@ where type SendMessageArgs = SendMessageArgs; fn validate_message( - lane: LaneId, + lane_id: LaneId, message: &T::OutboundPayload, ) -> Result, Self::Error> { ensure_normal_operating_mode::()?; - // let's check if outbound lane is active - ensure!(T::ActiveOutboundLanes::get().contains(&lane), Error::::InactiveOutboundLane); + // check lane + let lane = outbound_lane::(lane_id)?; Ok(SendMessageArgs { - lane_id: lane, + lane_id, + lane, payload: StoredMessagePayload::::try_from(message.encode()).map_err(|_| { Error::::MessageRejectedByPallet(VerificationError::MessageTooLarge) })?, @@ -716,7 +731,7 @@ where fn send_message(args: SendMessageArgs) -> SendMessageArtifacts { // save message in outbound storage and emit event - let mut lane = outbound_lane::(args.lane_id); + let mut lane = args.lane; let message_len = args.payload.len(); let nonce = lane.send_message(args.payload); @@ -751,28 +766,35 @@ fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error< /// Creates new inbound lane object, backed by runtime storage. fn inbound_lane, I: 'static>( lane_id: LaneId, -) -> InboundLane> { - InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id)) +) -> Result>, Error> { + Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id)?)) } /// Creates new outbound lane object, backed by runtime storage. fn outbound_lane, I: 'static>( lane_id: LaneId, -) -> OutboundLane> { - OutboundLane::new(RuntimeOutboundLaneStorage { lane_id, _phantom: Default::default() }) +) -> Result>, Error> { + Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id)?)) } /// Runtime inbound lane storage. struct RuntimeInboundLaneStorage, I: 'static = ()> { lane_id: LaneId, - cached_data: Option>>>, + cached_data: InboundLaneData>>, _phantom: PhantomData, } impl, I: 'static> RuntimeInboundLaneStorage { - /// Creates new runtime inbound lane storage. - fn from_lane_id(lane_id: LaneId) -> RuntimeInboundLaneStorage { - RuntimeInboundLaneStorage { lane_id, cached_data: None, _phantom: Default::default() } + /// Creates new runtime inbound lane storage for given **existing** lane. + fn from_lane_id(lane_id: LaneId) -> Result, Error> { + let cached_data = + InboundLanes::::get(lane_id).ok_or(Error::::UnknownInboundLane)?; + ensure!(cached_data.state == LaneState::Opened, Error::::ClosedInboundLane); + Ok(RuntimeInboundLaneStorage { + lane_id, + cached_data: cached_data.into(), + _phantom: Default::default(), + }) } } @@ -787,7 +809,7 @@ impl, I: 'static> RuntimeInboundLaneStorage { /// we may subtract extra bytes from this component. pub fn extra_proof_size_bytes(&mut self) -> u64 { let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); - let relayers_count = self.get_or_init_data().relayers.len(); + let relayers_count = self.data().relayers.len(); let actual_encoded_len = InboundLaneData::>>::encoded_size_hint(relayers_count) .unwrap_or(usize::MAX); @@ -810,30 +832,34 @@ impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX } - fn get_or_init_data(&mut self) -> InboundLaneData>> { - match self.cached_data { - Some(ref data) => data.clone(), - None => { - let data: InboundLaneData>> = - InboundLanes::::get(self.lane_id).into(); - self.cached_data = Some(data.clone()); - data - }, - } + fn data(&self) -> InboundLaneData>> { + self.cached_data.clone() } fn set_data(&mut self, data: InboundLaneData>>) { - self.cached_data = Some(data.clone()); + self.cached_data = data.clone(); InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) } } /// Runtime outbound lane storage. +#[derive(Debug, PartialEq, Eq)] struct RuntimeOutboundLaneStorage { lane_id: LaneId, + cached_data: OutboundLaneData, _phantom: PhantomData<(T, I)>, } +impl, I: 'static> RuntimeOutboundLaneStorage { + /// Creates new runtime outbound lane storage for given **existing** lane. + fn from_lane_id(lane_id: LaneId) -> Result> { + let cached_data = + OutboundLanes::::get(lane_id).ok_or(Error::::UnknownOutboundLane)?; + ensure!(cached_data.state == LaneState::Opened, Error::::ClosedOutboundLane); + Ok(Self { lane_id, cached_data, _phantom: PhantomData }) + } +} + impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { type StoredMessagePayload = StoredMessagePayload; @@ -842,10 +868,11 @@ impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag } fn data(&self) -> OutboundLaneData { - OutboundLanes::::get(self.lane_id) + self.cached_data.clone() } fn set_data(&mut self, data: OutboundLaneData) { + self.cached_data = data.clone(); OutboundLanes::::insert(self.lane_id, data) } diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index 788a13e82b1b..b1cd453286ba 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -75,6 +75,7 @@ pub enum ReceptionConfirmationError { } /// Outbound messages lane. +#[derive(Debug, PartialEq, Eq)] pub struct OutboundLane { storage: S, } @@ -212,7 +213,7 @@ mod tests { relayers: &VecDeque>, ) -> Result, ReceptionConfirmationError> { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -228,7 +229,7 @@ mod tests { #[test] fn send_message_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!(lane.storage.data().latest_generated_nonce, 0); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert!(lane.storage.message(&1).is_some()); @@ -239,7 +240,7 @@ mod tests { #[test] fn confirm_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -259,7 +260,7 @@ mod tests { #[test] fn confirm_partial_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -288,7 +289,7 @@ mod tests { #[test] fn confirm_delivery_rejects_nonce_lesser_than_latest_received() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -368,7 +369,7 @@ mod tests { #[test] fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index a3318833fa61..0dd5726493fb 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -220,7 +220,8 @@ mod tests { mock::*, }; - use bp_header_chain::StoredHeaderDataBuilder; + use bp_header_chain::{HeaderChainError, StoredHeaderDataBuilder}; + use bp_messages::LaneState; use bp_runtime::{HeaderId, StorageProofError}; use codec::Encode; use sp_runtime::traits::Header; @@ -440,6 +441,7 @@ mod tests { using_messages_proof( 10, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -480,6 +482,7 @@ mod tests { using_messages_proof( 0, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -494,6 +497,7 @@ mod tests { TEST_LANE_ID, ProvedLaneMessages { lane_state: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -512,6 +516,7 @@ mod tests { using_messages_proof( 1, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -526,6 +531,7 @@ mod tests { TEST_LANE_ID, ProvedLaneMessages { lane_state: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index 99da019dc084..cc4ffa6be497 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -35,7 +35,7 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, DispatchMessageData, FromBridgedChainMessagesProof, MessageDispatch, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, Message, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use bp_runtime::{ @@ -186,7 +186,6 @@ impl pallet_bridge_grandpa::Config for TestRuntime { parameter_types! { pub const MaxMessagesToPruneAtOnce: u64 = 10; pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID, TEST_LANE_ID_2]; } /// weights of messages pallet calls we use in tests. @@ -200,8 +199,6 @@ impl Config for TestRuntime { type BridgedChain = BridgedChain; type BridgedHeaderChain = BridgedChainGrandpa; - type ActiveOutboundLanes = ActiveOutboundLanes; - type OutboundPayload = TestPayload; type InboundPayload = TestPayload; @@ -269,11 +266,11 @@ pub const TEST_RELAYER_C: AccountId = 102; /// Lane that we're using in tests. pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); -/// Secondary lane that we're using in tests. -pub const TEST_LANE_ID_2: LaneId = LaneId([0, 0, 0, 2]); +/// Lane that is completely unknown to our runtime. +pub const UNKNOWN_LANE_ID: LaneId = LaneId([0, 0, 0, 2]); -/// Inactive outbound lane. -pub const TEST_LANE_ID_3: LaneId = LaneId([0, 0, 0, 3]); +/// Lane that is registered, but it is closed. +pub const CLOSED_LANE_ID: LaneId = LaneId([0, 0, 0, 3]); /// Regular message payload. pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50); @@ -439,7 +436,7 @@ pub fn unrewarded_relayer( /// Returns unrewarded relayers state at given lane. pub fn inbound_unrewarded_relayers_state(lane: bp_messages::LaneId) -> UnrewardedRelayersState { - let inbound_lane_data = crate::InboundLanes::::get(lane).0; + let inbound_lane_data = crate::InboundLanes::::get(lane).unwrap().0; UnrewardedRelayersState::from(&inbound_lane_data) } @@ -454,7 +451,19 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - new_test_ext().execute_with(test) + new_test_ext().execute_with(|| { + crate::InboundLanes::::insert(TEST_LANE_ID, InboundLaneData::opened()); + crate::OutboundLanes::::insert(TEST_LANE_ID, OutboundLaneData::opened()); + crate::InboundLanes::::insert( + CLOSED_LANE_ID, + InboundLaneData { state: LaneState::Closed, ..Default::default() }, + ); + crate::OutboundLanes::::insert( + CLOSED_LANE_ID, + OutboundLaneData { state: LaneState::Closed, ..Default::default() }, + ); + test() + }) } /// Prepare valid storage proof for given messages and insert appropriate header to the @@ -471,7 +480,7 @@ pub fn prepare_messages_proof( let nonces_start = messages.first().unwrap().key.nonce; let nonces_end = messages.last().unwrap().key.nonce; let (storage_root, storage_proof) = prepare_messages_storage_proof::( - TEST_LANE_ID, + lane, nonces_start..=nonces_end, outbound_lane_data, UnverifiedStorageProofParams::default(), diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index cc43125d0c35..0eb4edbe249b 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -19,18 +19,17 @@ use crate::{ outbound_lane, outbound_lane::ReceptionConfirmationError, - tests::mock::{self, RuntimeEvent as TestEvent, *}, + tests::mock::{RuntimeEvent as TestEvent, *}, weights_ext::WeightInfoExt, - Call, Config, Error, Event, InboundLanes, MaybeOutboundLanesCount, OutboundLanes, - OutboundMessages, Pallet, PalletOperatingMode, PalletOwner, RuntimeInboundLaneStorage, - StoredInboundLaneData, + Call, Config, Error, Event, InboundLanes, OutboundLanes, OutboundMessages, Pallet, + PalletOperatingMode, PalletOwner, RuntimeInboundLaneStorage, StoredInboundLaneData, }; use bp_messages::{ source_chain::{FromBridgedChainMessagesDeliveryProof, MessagesBridge}, target_chain::FromBridgedChainMessagesProof, BridgeMessagesCall, ChainWithMessages, DeliveredMessages, InboundLaneData, - InboundMessageDetails, LaneId, MessageKey, MessageNonce, MessagesOperatingMode, + InboundMessageDetails, LaneId, LaneState, MessageKey, MessageNonce, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState, VerificationError, }; @@ -44,7 +43,6 @@ use frame_support::{ weights::Weight, }; use frame_system::{EventRecord, Pallet as System, Phase}; -use sp_core::Get; use sp_runtime::DispatchError; fn get_ready_for_events() { @@ -55,7 +53,7 @@ fn get_ready_for_events() { fn send_regular_message(lane_id: LaneId) { get_ready_for_events(); - let outbound_lane = outbound_lane::(lane_id); + let outbound_lane = outbound_lane::(lane_id).unwrap(); let message_nonce = outbound_lane.data().latest_generated_nonce + 1; let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) @@ -83,6 +81,7 @@ fn receive_messages_delivery_proof() { prepare_messages_delivery_proof( TEST_LANE_ID, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, @@ -143,6 +142,7 @@ fn pallet_rejects_transactions_if_halted() { let delivery_proof = prepare_messages_delivery_proof( TEST_LANE_ID, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), }, @@ -210,6 +210,7 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { prepare_messages_delivery_proof( TEST_LANE_ID, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), }, @@ -271,7 +272,10 @@ fn receive_messages_proof_works() { REGULAR_PAYLOAD.declared_weight, )); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).unwrap().0.last_delivered_nonce(), + 1 + ); assert!(TestDeliveryPayments::is_reward_paid(1)); }); @@ -284,6 +288,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { InboundLanes::::insert( TEST_LANE_ID, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 8, relayers: vec![ unrewarded_relayer(9, 9, TEST_RELAYER_A), @@ -315,8 +320,9 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { )); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).0, + InboundLanes::::get(TEST_LANE_ID).unwrap().0, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 9, relayers: vec![ unrewarded_relayer(10, 10, TEST_RELAYER_B), @@ -354,7 +360,10 @@ fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enou ), Error::::InsufficientDispatchWeight ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + 0 + ); }); } @@ -397,14 +406,34 @@ fn receive_messages_proof_rejects_proof_with_too_many_messages() { #[test] fn receive_messages_delivery_proof_works() { run_test(|| { - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 0); - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).oldest_unpruned_nonce, 1); + assert_eq!( + OutboundLanes::::get(TEST_LANE_ID) + .unwrap() + .latest_received_nonce, + 0, + ); + assert_eq!( + OutboundLanes::::get(TEST_LANE_ID) + .unwrap() + .oldest_unpruned_nonce, + 1, + ); send_regular_message(TEST_LANE_ID); receive_messages_delivery_proof(); - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1); - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).oldest_unpruned_nonce, 2); + assert_eq!( + OutboundLanes::::get(TEST_LANE_ID) + .unwrap() + .latest_received_nonce, + 1, + ); + assert_eq!( + OutboundLanes::::get(TEST_LANE_ID) + .unwrap() + .oldest_unpruned_nonce, + 2, + ); }); } @@ -609,7 +638,10 @@ fn receive_messages_accepts_single_message_with_invalid_payload() { * improperly encoded) */ ),); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + 1, + ); }); } @@ -630,7 +662,10 @@ fn receive_messages_accepts_batch_with_message_with_invalid_payload() { REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, ),); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + 3, + ); }); } @@ -653,7 +688,10 @@ fn actual_dispatch_weight_does_not_overflow() { ), Error::::InsufficientDispatchWeight ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + 0 + ); }); } @@ -732,6 +770,7 @@ fn proof_size_refund_from_receive_messages_proof_works() { InboundLanes::::insert( TEST_LANE_ID, StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 42, @@ -760,6 +799,7 @@ fn proof_size_refund_from_receive_messages_proof_works() { InboundLanes::::insert( TEST_LANE_ID, StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 42, @@ -805,7 +845,11 @@ fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messa // actually confirmed messages is `1`. let proof = prepare_messages_delivery_proof( TEST_LANE_ID, - InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: 1, + relayers: Default::default(), + }, ); assert_noop!( Pallet::::receive_messages_delivery_proof( @@ -860,16 +904,6 @@ fn inbound_message_details_works() { }); } -#[test] -fn outbound_message_from_unconfigured_lane_is_rejected() { - run_test(|| { - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID_3, ®ULAR_PAYLOAD,), - Error::::InactiveOutboundLane, - ); - }); -} - #[test] fn test_bridge_messages_call_is_correctly_defined() { run_test(|| { @@ -878,6 +912,7 @@ fn test_bridge_messages_call_is_correctly_defined() { let message_delivery_proof = prepare_messages_delivery_proof( TEST_LANE_ID, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, @@ -948,10 +983,11 @@ fn inbound_storage_extra_proof_size_bytes_works() { fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { RuntimeInboundLaneStorage { lane_id: Default::default(), - cached_data: Some(InboundLaneData { + cached_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![relayer_entry(); relayer_entries].into(), last_confirmed_nonce: 0, - }), + }, _phantom: Default::default(), } } @@ -977,9 +1013,100 @@ fn inbound_storage_extra_proof_size_bytes_works() { } #[test] -fn maybe_outbound_lanes_count_returns_correct_value() { - assert_eq!( - MaybeOutboundLanesCount::::get(), - Some(mock::ActiveOutboundLanes::get().len() as u32) - ); +fn send_messages_fails_if_outbound_lane_is_not_opened() { + run_test(|| { + assert_noop!( + Pallet::::validate_message(UNKNOWN_LANE_ID, ®ULAR_PAYLOAD), + Error::::UnknownOutboundLane, + ); + + assert_noop!( + Pallet::::validate_message(CLOSED_LANE_ID, ®ULAR_PAYLOAD), + Error::::ClosedOutboundLane, + ); + }); +} + +#[test] +fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { + run_test(|| { + let mut message = message(1, REGULAR_PAYLOAD); + message.key.lane_id = UNKNOWN_LANE_ID; + let proof = prepare_messages_proof(vec![message.clone()], None); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::UnknownInboundLane, + ); + + message.key.lane_id = CLOSED_LANE_ID; + let proof = prepare_messages_proof(vec![message], None); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::ClosedInboundLane, + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { + run_test(|| { + let make_proof = |lane: LaneId| { + prepare_messages_delivery_proof( + lane, + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into(), + }, + ) + }; + + let proof = make_proof(UNKNOWN_LANE_ID); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ), + Error::::UnknownOutboundLane, + ); + + let proof = make_proof(CLOSED_LANE_ID); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ), + Error::::ClosedOutboundLane, + ); + }); } diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 5bca3ad8e277..c1229e839ed3 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -77,7 +77,7 @@ where let bridge_message = MessagesPallet::::validate_message(sender_and_lane.lane, &blob) .map_err(|e| { - log::debug!( + log::error!( target: LOG_TARGET, "XCM message {:?} cannot be exported because of bridge error {:?} on bridge {:?}", id, @@ -131,6 +131,7 @@ impl HaulBlob for DummyHaulBlob { mod tests { use super::*; use crate::mock::*; + use bp_messages::{LaneState, OutboundLaneData}; use bp_runtime::RangeInclusiveExt; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; @@ -146,6 +147,10 @@ mod tests { #[test] fn export_works() { run_test(|| { + pallet_bridge_messages::OutboundLanes::::insert( + TEST_LANE_ID, + OutboundLaneData { state: LaneState::Opened, ..Default::default() }, + ); assert_ok!(export_xcm::( BridgedRelayNetwork::get(), 0, @@ -188,6 +193,11 @@ mod tests { run_test(|| { let expected_lane_id = TEST_LANE_ID; + pallet_bridge_messages::OutboundLanes::::insert( + expected_lane_id, + OutboundLaneData { state: LaneState::Opened, ..Default::default() }, + ); + assert_eq!( XcmOverBridge::validate( BridgedRelayNetwork::get(), @@ -212,11 +222,18 @@ mod tests { let dest = Location::new(2, BridgedUniversalDestination::get()); let expected_lane_id = TEST_LANE_ID; + // open bridge + pallet_bridge_messages::OutboundLanes::::insert( + expected_lane_id, + OutboundLaneData { state: LaneState::Opened, ..Default::default() }, + ); + // check before - no messages assert_eq!( pallet_bridge_messages::Pallet::::outbound_lane_data( expected_lane_id ) + .unwrap() .queued_messages() .saturating_len(), 0 @@ -231,6 +248,7 @@ mod tests { pallet_bridge_messages::Pallet::::outbound_lane_data( expected_lane_id ) + .unwrap() .queued_messages() .saturating_len(), 1 diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 0cca32ba9e5f..5cd19afc545f 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -90,7 +90,6 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestMessagesWeights; - type ActiveOutboundLanes = ActiveOutboundLanes; type OutboundPayload = Vec; type InboundPayload = Vec; type DeliveryPayments = (); diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 9984f8ac3222..6a5a16866fc4 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -199,6 +199,21 @@ impl TypeId for LaneId { const TYPE_ID: [u8; 4] = *b"blan"; } +/// Lane state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum LaneState { + /// Lane is closed and all attempts to send/receive messages to/from this lane + /// will fail. + /// + /// Keep in mind that the lane has two ends and the state of the same lane at + /// its ends may be different. Those who are controlling/serving the lane + /// and/or sending messages over the lane, have to coordinate their actions on + /// both ends to make sure that lane is operating smoothly on both ends. + Closed, + /// Lane is opened and messages may be sent/received over it. + Opened, +} + /// Message nonce. Valid messages will never have 0 nonce. pub type MessageNonce = u64; @@ -229,6 +244,11 @@ pub struct Message { /// Inbound lane data. #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct InboundLaneData { + /// Inbound lane state. + /// + /// If state is `Closed`, then all attempts to deliver messages to this end will fail. + pub state: LaneState, + /// Identifiers of relayers and messages that they have delivered to this lane (ordered by /// message nonce). /// @@ -261,11 +281,20 @@ pub struct InboundLaneData { impl Default for InboundLaneData { fn default() -> Self { - InboundLaneData { relayers: VecDeque::new(), last_confirmed_nonce: 0 } + InboundLaneData { + state: LaneState::Closed, + relayers: VecDeque::new(), + last_confirmed_nonce: 0, + } } } impl InboundLaneData { + /// Returns default inbound lane data with opened state. + pub fn opened() -> Self { + InboundLaneData { state: LaneState::Opened, ..Default::default() } + } + /// Returns approximate size of the struct, given a number of entries in the `relayers` set and /// size of each entry. /// @@ -464,6 +493,10 @@ impl From<&InboundLaneData> for UnrewardedRelayersState { /// Outbound lane data. #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct OutboundLaneData { + /// Lane state. + /// + /// If state is `Closed`, then all attempts to send messages messages at this end will fail. + pub state: LaneState, /// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated /// message if all sent messages are already pruned. pub oldest_unpruned_nonce: MessageNonce, @@ -473,9 +506,17 @@ pub struct OutboundLaneData { pub latest_generated_nonce: MessageNonce, } +impl OutboundLaneData { + /// Returns default outbound lane data with opened state. + pub fn opened() -> Self { + OutboundLaneData { state: LaneState::Opened, ..Default::default() } + } +} + impl Default for OutboundLaneData { fn default() -> Self { OutboundLaneData { + state: LaneState::Closed, // it is 1 because we're pruning everything in [oldest_unpruned_nonce; // latest_received_nonce] oldest_unpruned_nonce: 1, @@ -569,9 +610,16 @@ pub enum VerificationError { mod tests { use super::*; + #[test] + fn lane_is_closed_by_default() { + assert_eq!(InboundLaneData::<()>::default().state, LaneState::Closed); + assert_eq!(OutboundLaneData::default().state, LaneState::Closed); + } + #[test] fn total_unrewarded_messages_does_not_overflow() { let lane_data = InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) }, UnrewardedRelayer { @@ -599,6 +647,7 @@ mod tests { for (relayer_entries, messages_count) in test_cases { let expected_size = InboundLaneData::::encoded_size_hint(relayer_entries as _); let actual_size = InboundLaneData { + state: LaneState::Opened, relayers: (1u8..=relayer_entries) .map(|i| UnrewardedRelayer { relayer: i, diff --git a/bridges/relays/lib-substrate-relay/src/messages/mod.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs index e52b70206669..19036a8804c9 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -838,7 +838,6 @@ mod tests { type ThisChain = ThisUnderlyingChain; type BridgedChain = BridgedUnderlyingChain; type BridgedHeaderChain = BridgedHeaderChain; - type ActiveOutboundLanes = (); type OutboundPayload = Vec; type InboundPayload = Vec; type DeliveryPayments = (); From 7a50472850e62820c7b814414f5dd4b54b899f2b Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 22 Jun 2023 13:13:53 +0300 Subject: [PATCH 07/95] Change LaneId underlying type from [u8; 4] to H256 (#2221) * change LaneId underlying type from [u8; 4] to H256 * fixed typo * added some tests * spelling * started fixing testnets * uncommented call size test * changed RewardsAccountParams encoding + added values separator when computing LaneId * review suggestions --- Cargo.lock | 3 + bridges/bin/runtime-common/Cargo.toml | 1 + .../extensions/refund_relayer_extension.rs | 53 +++++---- .../runtime-common/src/messages_call_ext.rs | 28 +++-- .../src/messages_xcm_extension.rs | 37 ++++-- bridges/bin/runtime-common/src/mock.rs | 6 +- bridges/modules/messages/src/benchmarking.rs | 4 +- bridges/modules/messages/src/inbound_lane.rs | 36 +++--- bridges/modules/messages/src/outbound_lane.rs | 16 +-- bridges/modules/messages/src/proofs.rs | 10 +- bridges/modules/messages/src/tests/mock.rs | 24 ++-- .../messages/src/tests/pallet_tests.rs | 111 +++++++++--------- bridges/modules/relayers/src/benchmarking.rs | 6 +- bridges/modules/relayers/src/lib.rs | 24 ++-- bridges/modules/relayers/src/mock.rs | 9 +- .../modules/relayers/src/payment_adapter.rs | 14 +-- bridges/modules/relayers/src/stake_adapter.rs | 4 +- .../modules/xcm-bridge-hub/src/exporter.rs | 6 +- bridges/modules/xcm-bridge-hub/src/mock.rs | 14 +-- bridges/primitives/messages/Cargo.toml | 6 +- bridges/primitives/messages/src/lib.rs | 109 +++++++++++++++-- .../primitives/messages/src/storage_keys.rs | 12 +- bridges/primitives/relayers/src/lib.rs | 23 ++-- bridges/relays/lib-substrate-relay/Cargo.toml | 1 + .../relays/lib-substrate-relay/src/cli/mod.rs | 11 +- .../src/cli/relay_headers_and_messages/mod.rs | 7 +- .../src/cli/relay_messages.rs | 8 +- .../lib-substrate-relay/src/messages/mod.rs | 6 +- .../src/messages/source.rs | 2 +- .../relays/messages/src/message_lane_loop.rs | 12 +- 30 files changed, 371 insertions(+), 232 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7466975fa428..f775a1cd48d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1855,6 +1855,7 @@ dependencies = [ "scale-info", "serde", "sp-core", + "sp-io", "sp-std 14.0.0", ] @@ -2360,6 +2361,7 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", @@ -21369,6 +21371,7 @@ dependencies = [ "rbtag", "relay-substrate-client", "relay-utils", + "rustc-hex", "scale-info", "sp-consensus-grandpa", "sp-core", diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 36f27b6aa035..c454ad9b5b1b 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -49,6 +49,7 @@ xcm-builder = { workspace = true } bp-test-utils = { workspace = true } pallet-balances = { workspace = true } pallet-bridge-messages = { features = ["std", "test-helpers"], workspace = true } +sp-core = { workspace = true } [features] default = ["std"] diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 0b74fa898bca..668ca94dd7ce 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -19,8 +19,11 @@ //! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). -use crate::messages_call_ext::{ - CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, +use crate::{ + messages_call_ext::{ + CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, + }, + messages_xcm_extension::LaneIdFromChainId, }; use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; @@ -92,15 +95,15 @@ pub trait RefundableMessagesLaneId { } /// Default implementation of `RefundableMessagesLaneId`. -pub struct RefundableMessagesLane(PhantomData<(Instance, Id)>); +pub struct RefundableMessagesLane(PhantomData<(Runtime, Instance)>); -impl RefundableMessagesLaneId for RefundableMessagesLane +impl RefundableMessagesLaneId for RefundableMessagesLane where + Runtime: MessagesConfig, Instance: 'static, - Id: Get, { type Instance = Instance; - type Id = Id; + type Id = LaneIdFromChainId; } /// Refund calculator. @@ -968,14 +971,14 @@ pub(crate) mod tests { }; parameter_types! { - pub TestLaneId: LaneId = TEST_LANE_ID; + TestParachain: u32 = 1000; pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( - TEST_LANE_ID, + test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain, ); pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( - TEST_LANE_ID, + test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain, ); @@ -985,7 +988,7 @@ pub(crate) mod tests { type TestMessagesExtensionProvider = RefundBridgedMessages< TestRuntime, - RefundableMessagesLane<(), TestLaneId>, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, @@ -994,7 +997,7 @@ pub(crate) mod tests { type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< TestRuntime, (), - RefundableMessagesLane<(), TestLaneId>, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, @@ -1003,7 +1006,7 @@ pub(crate) mod tests { type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, RefundableParachain<(), BridgedUnderlyingParachain>, - RefundableMessagesLane<(), TestLaneId>, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, @@ -1060,7 +1063,7 @@ pub(crate) mod tests { }; pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); - let lane_id = TestLaneId::get(); + let lane_id = test_lane_id(); let in_lane_data = InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); @@ -1145,9 +1148,9 @@ pub(crate) mod tests { proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TestLaneId::get(), + lane: test_lane_id(), nonces_start: pallet_bridge_messages::InboundLanes::::get( - TEST_LANE_ID, + test_lane_id(), ) .unwrap() .last_delivered_nonce() + @@ -1164,7 +1167,7 @@ pub(crate) mod tests { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TestLaneId::get(), + lane: test_lane_id(), }, relayers_state: UnrewardedRelayersState { last_delivered_nonce: best_message, @@ -1321,7 +1324,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1363,7 +1366,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1393,7 +1396,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1429,7 +1432,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1457,7 +1460,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1484,7 +1487,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1499,7 +1502,7 @@ pub(crate) mod tests { call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1519,7 +1522,7 @@ pub(crate) mod tests { relayer: relayer_account_at_this_chain(), call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }), @@ -2883,7 +2886,7 @@ pub(crate) mod tests { .unwrap(); // allow empty message delivery transactions - let lane_id = TestLaneId::get(); + let lane_id = test_lane_id(); let in_lane_data = InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 0, diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index 5eadb0a32480..c4e5a5e25829 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -361,11 +361,13 @@ mod tests { }; use sp_std::ops::RangeInclusive; - const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); + fn test_lane_id() -> LaneId { + LaneId::new(1, 2) + } fn fill_unrewarded_relayers() { let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(TEST_LANE_ID).unwrap(); + pallet_bridge_messages::InboundLanes::::get(test_lane_id()).unwrap(); for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), @@ -373,14 +375,14 @@ mod tests { }); } pallet_bridge_messages::InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), inbound_lane_state, ); } fn fill_unrewarded_messages() { let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(TEST_LANE_ID).unwrap(); + pallet_bridge_messages::InboundLanes::::get(test_lane_id()).unwrap(); inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { @@ -389,14 +391,14 @@ mod tests { }, }); pallet_bridge_messages::InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), inbound_lane_state, ); } fn deliver_message_10() { pallet_bridge_messages::InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), bp_messages::InboundLaneData { state: LaneState::Opened, relayers: Default::default(), @@ -418,7 +420,7 @@ mod tests { proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TEST_LANE_ID, + lane: test_lane_id(), nonces_start, nonces_end, }), @@ -431,11 +433,11 @@ mod tests { fn run_test(test: impl Fn() -> T) -> T { sp_io::TestExternalities::new(Default::default()).execute_with(|| { pallet_bridge_messages::InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), InboundLaneData::opened(), ); pallet_bridge_messages::OutboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), OutboundLaneData::opened(), ); test() @@ -537,7 +539,7 @@ mod tests { fn confirm_message_10() { pallet_bridge_messages::OutboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), bp_messages::OutboundLaneData { state: LaneState::Opened, oldest_unpruned_nonce: 0, @@ -553,7 +555,7 @@ mod tests { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TEST_LANE_ID, + lane: test_lane_id(), }, relayers_state: UnrewardedRelayersState { last_delivered_nonce, @@ -611,7 +613,7 @@ mod tests { CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range, best_stored_nonce: 0, // doesn't matter for `was_successful` }, @@ -671,7 +673,7 @@ mod tests { fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range, best_stored_nonce: 0, // doesn't matter for `was_successful` }), diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 0ea2f8b9619a..5ce906bef61d 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -26,7 +26,7 @@ use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, LaneId, MessageNonce, }; -use bp_runtime::messages::MessageDispatchResult; +use bp_runtime::{messages::MessageDispatchResult, Chain}; pub use bp_xcm_bridge_hub::XcmAsPlainPayload; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::{Decode, Encode}; @@ -38,8 +38,27 @@ use scale_info::TypeInfo; use sp_runtime::SaturatedConversion; use sp_std::{fmt::Debug, marker::PhantomData}; use xcm::prelude::*; + use xcm_builder::{DispatchBlob, DispatchBlobError}; +/// Make LaneId from chain identifiers of two bridge endpoints. +// TODO: https://github.com/paritytech/parity-bridges-common/issues/1666: this function +// is a temporary solution, because `ChainId` and will be removed soon. +pub struct LaneIdFromChainId(PhantomData<(R, I)>); + +impl Get for LaneIdFromChainId +where + R: pallet_bridge_messages::Config, + I: 'static, +{ + fn get() -> LaneId { + LaneId::new( + pallet_bridge_messages::ThisChainOf::::ID, + pallet_bridge_messages::BridgedChainOf::::ID, + ) + } +} + /// Message dispatch result type for single message. #[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] pub enum XcmBlobMessageDispatchResult { @@ -346,7 +365,7 @@ mod tests { parameter_types! { pub TestSenderAndLane: SenderAndLane = SenderAndLane { location: Location::new(1, [Parachain(1000)]), - lane: TEST_LANE_ID, + lane: test_lane_id(), }; pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ (TestSenderAndLane::get(), (NetworkId::ByGenesis([0; 32]), InteriorLocation::Here)) @@ -395,7 +414,7 @@ mod tests { fn fill_up_lane_to_congestion() -> MessageNonce { let latest_generated_nonce = OUTBOUND_LANE_CONGESTED_THRESHOLD; OutboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), OutboundLaneData { state: LaneState::Opened, oldest_unpruned_nonce: 0, @@ -449,7 +468,9 @@ mod tests { enqueued + 1, ); assert_eq!(DummySendXcm::messages_sent(), 1); - assert!(LocalXcmQueueManager::::is_congested_signal_sent(TEST_LANE_ID)); + assert!(LocalXcmQueueManager::::is_congested_signal_sent( + test_lane_id() + )); }); } @@ -460,7 +481,7 @@ mod tests { assert_eq!(DummySendXcm::messages_sent(), 1); // when we receive a delivery report for other lane, we don't send an uncongested signal - TestBlobHaulerAdapter::on_messages_delivered(LaneId([42, 42, 42, 42]), 0); + TestBlobHaulerAdapter::on_messages_delivered(LaneId::new(1, 3), 0); assert_eq!(DummySendXcm::messages_sent(), 1); }); } @@ -468,7 +489,7 @@ mod tests { #[test] fn uncongested_signal_is_not_sent_when_we_havent_send_congested_signal_before() { run_test(|| { - TestBlobHaulerAdapter::on_messages_delivered(TEST_LANE_ID, 0); + TestBlobHaulerAdapter::on_messages_delivered(test_lane_id(), 0); assert_eq!(DummySendXcm::messages_sent(), 0); }); } @@ -480,7 +501,7 @@ mod tests { assert_eq!(DummySendXcm::messages_sent(), 1); TestBlobHaulerAdapter::on_messages_delivered( - TEST_LANE_ID, + test_lane_id(), OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, ); assert_eq!(DummySendXcm::messages_sent(), 1); @@ -494,7 +515,7 @@ mod tests { assert_eq!(DummySendXcm::messages_sent(), 1); TestBlobHaulerAdapter::on_messages_delivered( - TEST_LANE_ID, + test_lane_id(), OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); assert_eq!(DummySendXcm::messages_sent(), 2); diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index decbf5c687d1..83ee83f517f8 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -33,6 +33,7 @@ use frame_support::{ weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, }; use pallet_transaction_payment::Multiplier; +use sp_core::Get; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8}, @@ -85,7 +86,10 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< >; /// Message lane used in tests. -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); +pub fn test_lane_id() -> LaneId { + crate::messages_xcm_extension::LaneIdFromChainId::::get() +} + /// Bridged chain id used in tests. pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; /// Maximal extrinsic size at the `BridgedChain`. diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index f73c5ba1442a..e12b6c923ef8 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -74,10 +74,8 @@ pub struct MessageDeliveryProofParams { /// Trait that must be implemented by runtime. pub trait Config: crate::Config { /// Lane id to use in benchmarks. - /// - /// By default, lane 00000000 is used. fn bench_lane_id() -> LaneId { - LaneId([0, 0, 0, 0]) + LaneId::new(1, 2) } /// Return id of relayer account at the bridged chain. diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 5061d63bd30e..3f397d025d27 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -216,15 +216,7 @@ impl InboundLane { #[cfg(test)] mod tests { use super::*; - use crate::{ - inbound_lane, - tests::mock::{ - dispatch_result, inbound_message_data, inbound_unrewarded_relayers_state, run_test, - unrewarded_relayer, BridgedChain, TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, - TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, TEST_RELAYER_C, - }, - RuntimeInboundLaneStorage, - }; + use crate::{inbound_lane, tests::mock::*, RuntimeInboundLaneStorage}; use bp_messages::UnrewardedRelayersState; fn receive_regular_message( @@ -244,7 +236,7 @@ mod tests { #[test] fn receive_status_update_ignores_status_from_the_future() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -261,7 +253,7 @@ mod tests { #[test] fn receive_status_update_ignores_obsolete_status() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -288,7 +280,7 @@ mod tests { #[test] fn receive_status_update_works() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -326,7 +318,7 @@ mod tests { #[test] fn receive_status_update_works_with_batches_from_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); let mut seed_storage_data = lane.storage.data(); // Prepare data seed_storage_data.last_confirmed_nonce = 0; @@ -357,7 +349,7 @@ mod tests { #[test] fn fails_to_receive_message_with_incorrect_nonce() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -373,7 +365,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; for current_nonce in 1..max_nonce + 1 { assert_eq!( @@ -409,7 +401,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; for current_nonce in 1..=max_nonce { assert_eq!( @@ -445,7 +437,7 @@ mod tests { #[test] fn correctly_receives_following_messages_from_two_relayers_alternately() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -484,7 +476,7 @@ mod tests { #[test] fn rejects_same_message_from_two_different_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -507,7 +499,7 @@ mod tests { #[test] fn correct_message_is_processed_instantly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!(lane.storage.data().last_delivered_nonce(), 1); }); @@ -516,7 +508,7 @@ mod tests { #[test] fn unspent_weight_is_returned_by_receive_message() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); let mut payload = REGULAR_PAYLOAD; *payload.dispatch_result.unspent_weight.ref_time_mut() = 1; assert_eq!( @@ -533,7 +525,7 @@ mod tests { #[test] fn first_message_is_confirmed_correctly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); assert_eq!( @@ -544,7 +536,7 @@ mod tests { Some(1), ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index b1cd453286ba..647618b66f16 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -190,8 +190,8 @@ mod tests { use crate::{ outbound_lane, tests::mock::{ - outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, - REGULAR_PAYLOAD, TEST_LANE_ID, + outbound_message_data, run_test, test_lane_id, unrewarded_relayer, TestRelayer, + TestRuntime, REGULAR_PAYLOAD, }, }; use sp_std::ops::RangeInclusive; @@ -213,7 +213,7 @@ mod tests { relayers: &VecDeque>, ) -> Result, ReceptionConfirmationError> { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -229,7 +229,7 @@ mod tests { #[test] fn send_message_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.storage.data().latest_generated_nonce, 0); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert!(lane.storage.message(&1).is_some()); @@ -240,7 +240,7 @@ mod tests { #[test] fn confirm_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -260,7 +260,7 @@ mod tests { #[test] fn confirm_partial_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -289,7 +289,7 @@ mod tests { #[test] fn confirm_delivery_rejects_nonce_lesser_than_latest_received() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -369,7 +369,7 @@ mod tests { #[test] fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID).unwrap(); + let mut lane = outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index 0dd5726493fb..0016d67b87aa 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -236,7 +236,7 @@ mod tests { test: impl Fn(FromBridgedChainMessagesProof) -> R, ) -> R { let (state_root, storage_proof) = prepare_messages_storage_proof::( - TEST_LANE_ID, + test_lane_id(), 1..=nonces_end, outbound_lane_data, bp_runtime::UnverifiedStorageProofParams::default(), @@ -268,7 +268,7 @@ mod tests { test(FromBridgedChainMessagesProof { bridged_header_hash, storage_proof, - lane: TEST_LANE_ID, + lane: test_lane_id(), nonces_start: 1, nonces_end, }) @@ -494,7 +494,7 @@ mod tests { |proof| verify_messages_proof::(proof, 0), ), Ok(vec![( - TEST_LANE_ID, + test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { state: LaneState::Opened, @@ -528,7 +528,7 @@ mod tests { |proof| verify_messages_proof::(proof, 1), ), Ok(vec![( - TEST_LANE_ID, + test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { state: LaneState::Opened, @@ -537,7 +537,7 @@ mod tests { latest_generated_nonce: 1, }), messages: vec![Message { - key: MessageKey { lane_id: TEST_LANE_ID, nonce: 1 }, + key: MessageKey { lane_id: test_lane_id(), nonce: 1 }, payload: vec![42], }], }, diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index cc4ffa6be497..9d24233929bf 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -213,7 +213,7 @@ impl Config for TestRuntime { #[cfg(feature = "runtime-benchmarks")] impl crate::benchmarking::Config<()> for TestRuntime { fn bench_lane_id() -> LaneId { - TEST_LANE_ID + test_lane_id() } fn prepare_message_proof( @@ -264,13 +264,19 @@ pub const TEST_RELAYER_B: AccountId = 101; pub const TEST_RELAYER_C: AccountId = 102; /// Lane that we're using in tests. -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); +pub fn test_lane_id() -> LaneId { + LaneId::new(1, 2) +} /// Lane that is completely unknown to our runtime. -pub const UNKNOWN_LANE_ID: LaneId = LaneId([0, 0, 0, 2]); +pub fn unknown_lane_id() -> LaneId { + LaneId::new(1, 3) +} /// Lane that is registered, but it is closed. -pub const CLOSED_LANE_ID: LaneId = LaneId([0, 0, 0, 3]); +pub fn closed_lane_id() -> LaneId { + LaneId::new(1, 4) +} /// Regular message payload. pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50); @@ -392,7 +398,7 @@ impl OnMessagesDelivered for TestOnMessagesDelivered { /// Return test lane message with given nonce and payload. pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { - Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() } + Message { key: MessageKey { lane_id: test_lane_id(), nonce }, payload: payload.encode() } } /// Return valid outbound message data, constructed from given payload. @@ -452,14 +458,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { new_test_ext().execute_with(|| { - crate::InboundLanes::::insert(TEST_LANE_ID, InboundLaneData::opened()); - crate::OutboundLanes::::insert(TEST_LANE_ID, OutboundLaneData::opened()); + crate::InboundLanes::::insert(test_lane_id(), InboundLaneData::opened()); + crate::OutboundLanes::::insert(test_lane_id(), OutboundLaneData::opened()); crate::InboundLanes::::insert( - CLOSED_LANE_ID, + closed_lane_id(), InboundLaneData { state: LaneState::Closed, ..Default::default() }, ); crate::OutboundLanes::::insert( - CLOSED_LANE_ID, + closed_lane_id(), OutboundLaneData { state: LaneState::Closed, ..Default::default() }, ); test() diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 0eb4edbe249b..1df17112c699 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -79,7 +79,7 @@ fn receive_messages_delivery_proof() { assert_ok!(Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 1, @@ -104,7 +104,7 @@ fn receive_messages_delivery_proof() { vec![EventRecord { phase: Phase::Initialization, event: TestEvent::Messages(Event::MessagesDelivered { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), messages: DeliveredMessages::new(1), }), topics: vec![], @@ -116,14 +116,14 @@ fn receive_messages_delivery_proof() { fn pallet_rejects_transactions_if_halted() { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); PalletOperatingMode::::put(MessagesOperatingMode::Basic( BasicOperatingMode::Halted, )); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(test_lane_id(), ®ULAR_PAYLOAD), Error::::NotOperatingNormally, ); @@ -140,7 +140,7 @@ fn pallet_rejects_transactions_if_halted() { ); let delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 1, @@ -186,14 +186,14 @@ fn receive_messages_fails_if_dispatcher_is_inactive() { fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); PalletOperatingMode::::put( MessagesOperatingMode::RejectingOutboundMessages, ); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(test_lane_id(), ®ULAR_PAYLOAD), Error::::NotOperatingNormally, ); @@ -208,7 +208,7 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { assert_ok!(Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 1, @@ -229,7 +229,7 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { #[test] fn send_message_works() { run_test(|| { - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); }); } @@ -244,7 +244,7 @@ fn send_message_rejects_too_large_message() { .extra .extend_from_slice(&vec![0u8; max_outbound_payload_size as usize]); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, &message_payload.clone(),), + Pallet::::validate_message(test_lane_id(), &message_payload.clone(),), Error::::MessageRejectedByPallet(VerificationError::MessageTooLarge), ); @@ -255,7 +255,7 @@ fn send_message_rejects_too_large_message() { assert_eq!(message_payload.encoded_size() as u32, max_outbound_payload_size); let valid_message = - Pallet::::validate_message(TEST_LANE_ID, &message_payload) + Pallet::::validate_message(test_lane_id(), &message_payload) .expect("validate_message has failed"); Pallet::::send_message(valid_message); }) @@ -273,7 +273,10 @@ fn receive_messages_proof_works() { )); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().0.last_delivered_nonce(), + InboundLanes::::get(test_lane_id()) + .unwrap() + .0 + .last_delivered_nonce(), 1 ); @@ -286,7 +289,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { run_test(|| { // say we have received 10 messages && last confirmed message is 8 InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 8, @@ -298,7 +301,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }, ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, @@ -320,7 +323,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { )); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().0, + InboundLanes::::get(test_lane_id()).unwrap().0, InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 9, @@ -332,7 +335,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }, ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, @@ -361,7 +364,7 @@ fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enou Error::::InsufficientDispatchWeight ); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), 0 ); }); @@ -407,29 +410,29 @@ fn receive_messages_proof_rejects_proof_with_too_many_messages() { fn receive_messages_delivery_proof_works() { run_test(|| { assert_eq!( - OutboundLanes::::get(TEST_LANE_ID) + OutboundLanes::::get(test_lane_id()) .unwrap() .latest_received_nonce, 0, ); assert_eq!( - OutboundLanes::::get(TEST_LANE_ID) + OutboundLanes::::get(test_lane_id()) .unwrap() .oldest_unpruned_nonce, 1, ); - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); receive_messages_delivery_proof(); assert_eq!( - OutboundLanes::::get(TEST_LANE_ID) + OutboundLanes::::get(test_lane_id()) .unwrap() .latest_received_nonce, 1, ); assert_eq!( - OutboundLanes::::get(TEST_LANE_ID) + OutboundLanes::::get(test_lane_id()) .unwrap() .oldest_unpruned_nonce, 2, @@ -440,12 +443,12 @@ fn receive_messages_delivery_proof_works() { #[test] fn receive_messages_delivery_proof_rewards_relayers() { run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); + send_regular_message(test_lane_id()); // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A let single_message_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), ..Default::default() @@ -481,7 +484,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { // this reports delivery of both message 1 and message 2 => reward is paid only to // TEST_RELAYER_B let two_messages_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -519,15 +522,15 @@ fn receive_messages_delivery_proof_rewards_relayers() { ); assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); - assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 0))); + assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((test_lane_id(), 0))); }); } #[test] fn receive_messages_delivery_proof_rejects_invalid_proof() { run_test(|| { - let mut proof = prepare_messages_delivery_proof(TEST_LANE_ID, Default::default()); - proof.lane = bp_messages::LaneId([42, 42, 42, 42]); + let mut proof = prepare_messages_delivery_proof(test_lane_id(), Default::default()); + proof.lane = bp_messages::LaneId::new(42, 84); assert_noop!( Pallet::::receive_messages_delivery_proof( @@ -545,7 +548,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i run_test(|| { // when number of relayers entries is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -571,7 +574,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i // when number of messages is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -597,7 +600,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i // when last delivered nonce is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -639,7 +642,7 @@ fn receive_messages_accepts_single_message_with_invalid_payload() { ),); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), 1, ); }); @@ -663,7 +666,7 @@ fn receive_messages_accepts_batch_with_message_with_invalid_payload() { ),); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), 3, ); }); @@ -689,7 +692,7 @@ fn actual_dispatch_weight_does_not_overflow() { Error::::InsufficientDispatchWeight ); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).unwrap().last_delivered_nonce(), + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), 0 ); }); @@ -768,7 +771,7 @@ fn proof_size_refund_from_receive_messages_proof_works() { REGULAR_PAYLOAD.declared_weight, ); InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), StoredInboundLaneData(InboundLaneData { state: LaneState::Opened, relayers: vec![ @@ -797,7 +800,7 @@ fn proof_size_refund_from_receive_messages_proof_works() { // if count of unrewarded relayer entries is less than maximal, then some `proof_size` // must be refunded InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), StoredInboundLaneData(InboundLaneData { state: LaneState::Opened, relayers: vec![ @@ -835,7 +838,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messa { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); // 1) InboundLaneData declares that the `last_confirmed_nonce` is 1; // 2) InboundLaneData has no entries => `InboundLaneData::last_delivered_nonce()` returns @@ -844,7 +847,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messa // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and numer of // actually confirmed messages is `1`. let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 1, @@ -873,20 +876,20 @@ fn storage_keys_computed_properly() { assert_eq!( OutboundMessages::::storage_map_final_key(MessageKey { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), nonce: 42 }), - bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, + bp_messages::storage_keys::message_key("Messages", &test_lane_id(), 42).0, ); assert_eq!( - OutboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, + OutboundLanes::::storage_map_final_key(test_lane_id()), + bp_messages::storage_keys::outbound_lane_data_key("Messages", &test_lane_id()).0, ); assert_eq!( - InboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, + InboundLanes::::storage_map_final_key(test_lane_id()), + bp_messages::storage_keys::inbound_lane_data_key("Messages", &test_lane_id()).0, ); } @@ -895,7 +898,7 @@ fn inbound_message_details_works() { run_test(|| { assert_eq!( Pallet::::inbound_message_data( - TEST_LANE_ID, + test_lane_id(), REGULAR_PAYLOAD.encode(), OutboundMessageDetails { nonce: 0, dispatch_weight: Weight::zero(), size: 0 }, ), @@ -910,7 +913,7 @@ fn test_bridge_messages_call_is_correctly_defined() { let account_id = 1; let message_proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); let message_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { state: LaneState::Opened, last_confirmed_nonce: 1, @@ -982,7 +985,7 @@ fn inbound_storage_extra_proof_size_bytes_works() { fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { RuntimeInboundLaneStorage { - lane_id: Default::default(), + lane_id: LaneId::new(1, 2), cached_data: InboundLaneData { state: LaneState::Opened, relayers: vec![relayer_entry(); relayer_entries].into(), @@ -1016,12 +1019,12 @@ fn inbound_storage_extra_proof_size_bytes_works() { fn send_messages_fails_if_outbound_lane_is_not_opened() { run_test(|| { assert_noop!( - Pallet::::validate_message(UNKNOWN_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(unknown_lane_id(), ®ULAR_PAYLOAD), Error::::UnknownOutboundLane, ); assert_noop!( - Pallet::::validate_message(CLOSED_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(closed_lane_id(), ®ULAR_PAYLOAD), Error::::ClosedOutboundLane, ); }); @@ -1031,7 +1034,7 @@ fn send_messages_fails_if_outbound_lane_is_not_opened() { fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { run_test(|| { let mut message = message(1, REGULAR_PAYLOAD); - message.key.lane_id = UNKNOWN_LANE_ID; + message.key.lane_id = unknown_lane_id(); let proof = prepare_messages_proof(vec![message.clone()], None); assert_noop!( @@ -1045,7 +1048,7 @@ fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { Error::::UnknownInboundLane, ); - message.key.lane_id = CLOSED_LANE_ID; + message.key.lane_id = closed_lane_id(); let proof = prepare_messages_proof(vec![message], None); assert_noop!( @@ -1079,7 +1082,7 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { ) }; - let proof = make_proof(UNKNOWN_LANE_ID); + let proof = make_proof(unknown_lane_id()); assert_noop!( Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), @@ -1094,7 +1097,7 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { Error::::UnknownOutboundLane, ); - let proof = make_proof(CLOSED_LANE_ID); + let proof = make_proof(closed_lane_id()); assert_noop!( Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), diff --git a/bridges/modules/relayers/src/benchmarking.rs b/bridges/modules/relayers/src/benchmarking.rs index ca312d44edfd..8a3f905a8f29 100644 --- a/bridges/modules/relayers/src/benchmarking.rs +++ b/bridges/modules/relayers/src/benchmarking.rs @@ -43,7 +43,7 @@ pub trait Config: crate::Config { benchmarks! { // Benchmark `claim_rewards` call. claim_rewards { - let lane = LaneId([0, 0, 0, 0]); + let lane = LaneId::new(1, 2); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); let relayer: T::AccountId = whitelisted_caller(); @@ -102,7 +102,7 @@ benchmarks! { crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); // create slash destination account - let lane = LaneId([0, 0, 0, 0]); + let lane = LaneId::new(1, 2); let slash_destination = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); T::prepare_rewards_account(slash_destination, Zero::zero()); }: { @@ -116,7 +116,7 @@ benchmarks! { // the weight of message delivery call if `RefundBridgedParachainMessages` signed extension // is deployed at runtime level. register_relayer_reward { - let lane = LaneId([0, 0, 0, 0]); + let lane = LaneId::new(1, 2); let relayer: T::AccountId = whitelisted_caller(); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index 2c86ec01f5b9..114f8ca3fb1c 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -492,7 +492,7 @@ mod tests { get_ready_for_events(); Pallet::::register_relayer_reward( - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), ®ULAR_RELAYER, 100, ); @@ -504,7 +504,7 @@ mod tests { phase: Phase::Initialization, event: TestEvent::Relayers(RewardRegistered { relayer: REGULAR_RELAYER, - rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + rewards_account_params: test_reward_account_param(), reward: 100 }), topics: vec![], @@ -519,7 +519,7 @@ mod tests { assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::root(), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), DispatchError::BadOrigin, ); @@ -532,7 +532,7 @@ mod tests { assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), Error::::NoRewardForRelayer, ); @@ -544,13 +544,13 @@ mod tests { run_test(|| { RelayerRewards::::insert( FAILING_RELAYER, - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 100, ); assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(FAILING_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), Error::::FailedToPayReward, ); @@ -564,15 +564,15 @@ mod tests { RelayerRewards::::insert( REGULAR_RELAYER, - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 100, ); assert_ok!(Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() )); assert_eq!( - RelayerRewards::::get(REGULAR_RELAYER, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(REGULAR_RELAYER, test_reward_account_param()), None ); @@ -583,7 +583,7 @@ mod tests { phase: Phase::Initialization, event: TestEvent::Relayers(RewardPaid { relayer: REGULAR_RELAYER, - rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + rewards_account_params: test_reward_account_param(), reward: 100 }), topics: vec![], @@ -599,12 +599,12 @@ mod tests { run_test(|| { let in_lane_0 = RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), + LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain, ); let out_lane_1 = RewardsAccountParams::new( - LaneId([0, 0, 0, 1]), + LaneId::new(1, 3), *b"test", RewardsAccountOwner::BridgedChain, ); diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 3124787896c3..81993589de61 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -95,10 +95,6 @@ impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { } } -/// Message lane that we're using in tests. -pub const TEST_REWARDS_ACCOUNT_PARAMS: RewardsAccountParams = - RewardsAccountParams::new(LaneId([0, 0, 0, 0]), *b"test", RewardsAccountOwner::ThisChain); - /// Regular relayer that may receive rewards. pub const REGULAR_RELAYER: AccountId = 1; @@ -132,6 +128,11 @@ impl PaymentProcedure for TestPaymentProcedure { } } +/// Reward account params that we are using in tests. +pub fn test_reward_account_param() -> RewardsAccountParams { + RewardsAccountParams::new(LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain) +} + /// Return test externalities to use in tests. pub fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index f75c409aca4f..beec412c1203 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -117,16 +117,16 @@ mod tests { register_relayers_rewards::( &RELAYER_2, relayers_rewards(), - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 50, ); assert_eq!( - RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_1, test_reward_account_param()), Some(100) ); assert_eq!( - RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_2, test_reward_account_param()), Some(150) ); }); @@ -138,20 +138,20 @@ mod tests { register_relayers_rewards::( &RELAYER_3, relayers_rewards(), - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 50, ); assert_eq!( - RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_1, test_reward_account_param()), Some(100) ); assert_eq!( - RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_2, test_reward_account_param()), Some(150) ); assert_eq!( - RelayerRewards::::get(RELAYER_3, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_3, test_reward_account_param()), None ); }); diff --git a/bridges/modules/relayers/src/stake_adapter.rs b/bridges/modules/relayers/src/stake_adapter.rs index 7ba90d91dfd9..ce097344d56b 100644 --- a/bridges/modules/relayers/src/stake_adapter.rs +++ b/bridges/modules/relayers/src/stake_adapter.rs @@ -130,7 +130,7 @@ mod tests { #[test] fn repatriate_reserved_works() { run_test(|| { - let beneficiary = TEST_REWARDS_ACCOUNT_PARAMS; + let beneficiary = test_reward_account_param(); let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary); let mut expected_balance = ExistentialDeposit::get(); @@ -186,7 +186,7 @@ mod tests { #[test] fn repatriate_reserved_doesnt_work_when_beneficiary_account_is_missing() { run_test(|| { - let beneficiary = TEST_REWARDS_ACCOUNT_PARAMS; + let beneficiary = test_reward_account_param(); let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary); Balances::mint_into(&3, test_stake() * 2).unwrap(); diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index c1229e839ed3..40669d4dfda9 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -148,7 +148,7 @@ mod tests { fn export_works() { run_test(|| { pallet_bridge_messages::OutboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), OutboundLaneData { state: LaneState::Opened, ..Default::default() }, ); assert_ok!(export_xcm::( @@ -191,7 +191,7 @@ mod tests { #[test] fn exporter_computes_correct_lane_id() { run_test(|| { - let expected_lane_id = TEST_LANE_ID; + let expected_lane_id = test_lane_id(); pallet_bridge_messages::OutboundLanes::::insert( expected_lane_id, @@ -220,7 +220,7 @@ mod tests { run_test(|| { // valid routable destination let dest = Location::new(2, BridgedUniversalDestination::get()); - let expected_lane_id = TEST_LANE_ID; + let expected_lane_id = test_lane_id(); // open bridge pallet_bridge_messages::OutboundLanes::::insert( diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 5cd19afc545f..2306174f63fe 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -27,7 +27,7 @@ use bridge_runtime_common::messages_xcm_extension::{SenderAndLane, XcmBlobHauler use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{Everything, NeverEnsureOrigin}, + traits::{Everything, Get, NeverEnsureOrigin}, weights::RuntimeDbWeight, }; use sp_core::H256; @@ -52,7 +52,11 @@ type Block = frame_system::mocking::MockBlock; pub const SIBLING_ASSET_HUB_ID: u32 = 2001; pub const THIS_BRIDGE_HUB_ID: u32 = 2002; pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); + +/// Message lane used in tests. +pub fn test_lane_id() -> LaneId { + bridge_runtime_common::messages_xcm_extension::LaneIdFromChainId::::get() +} frame_support::construct_runtime! { pub enum TestRuntime { @@ -82,10 +86,6 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } -parameter_types! { - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; -} - impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestMessagesWeights; @@ -293,7 +293,7 @@ impl TestExportXcmWithXcmOverBridge { parameter_types! { pub TestSenderAndLane: SenderAndLane = SenderAndLane { location: SiblingLocation::get(), - lane: TEST_LANE_ID, + lane: test_lane_id(), }; pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ (TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedRelativeDestination::get())) diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 4a9037342bce..59e458a402dd 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -16,15 +16,14 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies - bp-runtime = { workspace = true } bp-header-chain = { workspace = true } # Substrate Dependencies - frame-support = { workspace = true } sp-core = { workspace = true } sp-std = { workspace = true } +sp-io = { workspace = true } [dev-dependencies] hex = { workspace = true, default-features = true } @@ -40,5 +39,6 @@ std = [ "scale-info/std", "serde/std", "sp-core/std", - "sp-std/std", + "sp-io/std", + "sp-std/std" ] diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 6a5a16866fc4..6bfb4e79e98e 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -31,7 +31,8 @@ pub use frame_support::weights::Weight; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use source_chain::RelayersRewards; -use sp_core::{RuntimeDebug, TypeId}; +use sp_core::{RuntimeDebug, TypeId, H256}; +use sp_io::hashing::blake2_256; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; pub mod source_chain; @@ -165,7 +166,24 @@ impl OperatingMode for MessagesOperatingMode { } } -/// Lane id which implements `TypeId`. +/// Bridge lane identifier. +/// +/// Lane connects two endpoints at both sides of the bridge. We assume that every endpoint +/// has its own unique identifier. We want lane identifiers to be the same on the both sides +/// of the bridge (and naturally unique across global consensus if endpoints have unique +/// identifiers). So lane id is the hash (`blake2_256`) of **ordered** encoded locations +/// concatenation (separated by some binary data). I.e.: +/// +/// ```nocompile +/// let endpoint1 = X2(GlobalConsensus(NetworkId::Rococo), Parachain(42)); +/// let endpoint2 = X2(GlobalConsensus(NetworkId::Wococo), Parachain(777)); +/// +/// let final_lane_key = if endpoint1 < endpoint2 { +/// (endpoint1, VALUES_SEPARATOR, endpoint2) +/// } else { +/// (endpoint2, VALUES_SEPARATOR, endpoint1) +/// }.using_encoded(blake2_256); +/// ``` #[derive( Clone, Copy, @@ -181,7 +199,39 @@ impl OperatingMode for MessagesOperatingMode { Serialize, Deserialize, )] -pub struct LaneId(pub [u8; 4]); +pub struct LaneId(H256); + +impl LaneId { + /// Create lane identifier from two locations. + pub fn new(endpoint1: T, endpoint2: T) -> Self { + const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; + + LaneId( + if endpoint1 < endpoint2 { + (endpoint1, VALUES_SEPARATOR, endpoint2) + } else { + (endpoint2, VALUES_SEPARATOR, endpoint1) + } + .using_encoded(blake2_256) + .into(), + ) + } + + /// Create lane identifier from given hash. + /// + /// There's no `From` implementation for the `LaneId`, because using this conversion + /// in a wrong way (i.e. computing hash of endpoints manually) may lead to issues. So we + /// want the call to be explicit. + pub const fn from_inner(hash: H256) -> Self { + LaneId(hash) + } +} + +impl core::fmt::Display for LaneId { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmt) + } +} impl core::fmt::Debug for LaneId { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -189,8 +239,8 @@ impl core::fmt::Debug for LaneId { } } -impl AsRef<[u8]> for LaneId { - fn as_ref(&self) -> &[u8] { +impl AsRef for LaneId { + fn as_ref(&self) -> &H256 { &self.0 } } @@ -380,7 +430,7 @@ pub struct UnrewardedRelayer { } /// Received messages with their dispatch result. -#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct ReceivedMessages { /// Id of the lane which is receiving messages. pub lane: LaneId, @@ -677,7 +727,50 @@ mod tests { } #[test] - fn lane_id_debug_format_matches_inner_array_format() { - assert_eq!(format!("{:?}", LaneId([0, 0, 0, 0])), format!("{:?}", [0, 0, 0, 0]),); + fn lane_id_debug_format_matches_inner_hash_format() { + assert_eq!( + format!("{:?}", LaneId(H256::from([1u8; 32]))), + format!("{:?}", H256::from([1u8; 32])), + ); + } + + #[test] + fn lane_id_is_generated_using_ordered_endpoints() { + assert_eq!(LaneId::new(1, 2), LaneId::new(2, 1)); + } + + #[test] + fn lane_id_is_different_for_different_endpoints() { + assert_ne!(LaneId::new(1, 2), LaneId::new(1, 3)); + } + + #[test] + fn lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { + /// Some artificial type that generates the same encoding for different values + /// concatenations. I.e. the encoding for `(Either::Two(1, 2), Either::Two(3, 4))` + /// is the same as encoding of `(Either::Three(1, 2, 3), Either::One(4))`. + /// In practice, this type is not useful, because you can't do a proper decoding. + /// But still there may be some collisions even in proper types. + #[derive(Eq, Ord, PartialEq, PartialOrd)] + enum Either { + Three(u64, u64, u64), + Two(u64, u64), + One(u64), + } + + impl codec::Encode for Either { + fn encode(&self) -> Vec { + match *self { + Self::One(a) => a.encode(), + Self::Two(a, b) => (a, b).encode(), + Self::Three(a, b, c) => (a, b, c).encode(), + } + } + } + + assert_ne!( + LaneId::new(Either::Two(1, 2), Either::Two(3, 4)), + LaneId::new(Either::Three(1, 2, 3), Either::One(4)), + ); } } diff --git a/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs index 8eedf8fcc7ac..3e7b04a50b0c 100644 --- a/bridges/primitives/messages/src/storage_keys.rs +++ b/bridges/primitives/messages/src/storage_keys.rs @@ -91,10 +91,10 @@ mod tests { fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted messages proofs. - let storage_key = message_key("BridgeMessages", &LaneId(*b"test"), 42).0; + let storage_key = message_key("BridgeMessages", &LaneId::new(1, 2), 42).0; assert_eq!( storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), + hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea70e9bdb8f50c68d12f06eabb57759ee5eb1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea02a00000000000000").to_vec(), "Unexpected storage key: {}", hex::encode(&storage_key), ); @@ -104,10 +104,10 @@ mod tests { fn outbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted outbound lane state proofs. - let storage_key = outbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + let storage_key = outbound_lane_data_key("BridgeMessages", &LaneId::new(1, 2)).0; assert_eq!( storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), + hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1fd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), "Unexpected storage key: {}", hex::encode(&storage_key), ); @@ -117,10 +117,10 @@ mod tests { fn inbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted inbound lane state proofs. - let storage_key = inbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + let storage_key = inbound_lane_data_key("BridgeMessages", &LaneId::new(1, 2)).0; assert_eq!( storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), + hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fabd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), "Unexpected storage key: {}", hex::encode(&storage_key), ); diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index 436f33db4008..704fef7c8e6b 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -57,9 +57,12 @@ pub enum RewardsAccountOwner { /// parameters to identify the account that pays a reward to the relayer. #[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] pub struct RewardsAccountParams { - lane_id: LaneId, - bridged_chain_id: ChainId, + // **IMPORTANT NOTE**: the order of fields here matters - we are using + // `into_account_truncating` and lane id is already `32` byte, so if other fields are encoded + // after it, they're simply dropped. So lane id shall be the last field. owner: RewardsAccountOwner, + bridged_chain_id: ChainId, + lane_id: LaneId, } impl RewardsAccountParams { @@ -162,21 +165,21 @@ mod tests { fn different_lanes_are_using_different_accounts() { assert_eq!( PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), + LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain )), - hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 1]), + LaneId::new(1, 3), *b"test", RewardsAccountOwner::ThisChain )), - hex_literal::hex!("62726170000000017465737400726577617264732d6163636f756e7400000000") + hex_literal::hex!("627261700074657374a43e8951aa302c133beb5f85821a21645f07b487270ef3") .into(), ); } @@ -185,21 +188,21 @@ mod tests { fn different_directions_are_using_different_accounts() { assert_eq!( PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), + LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain )), - hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), + LaneId::new(1, 2), *b"test", RewardsAccountOwner::BridgedChain )), - hex_literal::hex!("62726170000000007465737401726577617264732d6163636f756e7400000000") + hex_literal::hex!("627261700174657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); } diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index b0f93e5b5485..89115cfeee92 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -22,6 +22,7 @@ num-traits = { workspace = true, default-features = true } rbtag = { workspace = true } structopt = { workspace = true } strum = { features = ["derive"], workspace = true, default-features = true } +rustc-hex = { workspace = true } thiserror = { workspace = true } # Bridge dependencies diff --git a/bridges/relays/lib-substrate-relay/src/cli/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/mod.rs index ddb3e416dc32..2882d230f6aa 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/mod.rs @@ -18,6 +18,7 @@ use codec::{Decode, Encode}; use rbtag::BuildInfo; +use sp_core::H256; use structopt::StructOpt; use strum::{EnumString, VariantNames}; @@ -42,21 +43,19 @@ pub type DefaultClient = relay_substrate_client::RpcWithCachingClient; /// Lane id. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HexLaneId(pub [u8; 4]); +pub struct HexLaneId(pub H256); impl From for LaneId { fn from(lane_id: HexLaneId) -> LaneId { - LaneId(lane_id.0) + LaneId::from_inner(lane_id.0) } } impl std::str::FromStr for HexLaneId { - type Err = hex::FromHexError; + type Err = rustc_hex::FromHexError; fn from_str(s: &str) -> Result { - let mut lane_id = [0u8; 4]; - hex::decode_to_slice(s, &mut lane_id)?; - Ok(HexLaneId(lane_id)) + Ok(HexLaneId(H256::from_str(s)?)) } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 338dda3c6330..8e524fe22dec 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -55,7 +55,7 @@ use sp_core::Pair; #[derive(Debug, PartialEq, StructOpt)] pub struct HeadersAndMessagesSharedParams { /// Hex-encoded lane identifiers that should be served by the complex relay. - #[structopt(long, default_value = "00000000")] + #[structopt(long)] pub lane: Vec, /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) /// are relayed. @@ -359,6 +359,7 @@ mod tests { use crate::{cli::chain_schema::RuntimeVersionType, declare_chain_cli_schema}; use relay_substrate_client::{ChainRuntimeVersion, Parachain, SimpleRuntimeVersion}; + use sp_core::H256; #[test] // We need `#[allow(dead_code)]` because some of the methods generated by the macros @@ -422,7 +423,7 @@ mod tests { "--polkadot-port", "9944", "--lane", - "00000000", + "0000000000000000000000000000000000000000000000000000000000000000", "--prometheus-host", "0.0.0.0", ]); @@ -432,7 +433,7 @@ mod tests { res, BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages { shared: HeadersAndMessagesSharedParams { - lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], + lane: vec![HexLaneId(H256::from([0x00u8; 32]))], only_mandatory_headers: false, only_free_headers: false, prometheus_params: PrometheusParams { diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index 68bbe71ae599..1771155bbcd3 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -37,8 +37,8 @@ use relay_utils::UniqueSaturatedInto; /// Messages relaying params. #[derive(StructOpt)] pub struct RelayMessagesParams { - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, #[structopt(flatten)] source: SourceConnectionParams, @@ -59,8 +59,8 @@ pub struct RelayMessagesRangeParams { /// This header must be previously proved to the target chain. #[structopt(long)] at_source_block: u128, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, /// Nonce (inclusive) of the first message to relay. #[structopt(long)] diff --git a/bridges/relays/lib-substrate-relay/src/messages/mod.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs index 19036a8804c9..28bc5c7f5e8e 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -644,7 +644,7 @@ where FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: Default::default(), + lane: LaneId::new(1, 2), nonces_start: 1, nonces_end: messages as u64, }, @@ -706,7 +706,7 @@ mod tests { let receive_messages_proof = FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: LaneId::new(1, 2), nonces_start: 0, nonces_end: 0, }; @@ -761,7 +761,7 @@ mod tests { let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: LaneId::new(1, 2), }; let relayers_state = UnrewardedRelayersState { unrewarded_relayer_entries: 0, diff --git a/bridges/relays/lib-substrate-relay/src/messages/source.rs b/bridges/relays/lib-substrate-relay/src/messages/source.rs index b75fc86d5eee..2c49df3452ab 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/source.rs @@ -661,7 +661,7 @@ mod tests { } let maybe_batches = - split_msgs_to_refine::(Default::default(), msgs_to_refine); + split_msgs_to_refine::(LaneId::new(1, 2), msgs_to_refine); match expected_batches { Ok(expected_batches) => { let batches = maybe_batches.unwrap(); diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index b681d86d2ae8..995499092c3e 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -276,7 +276,7 @@ pub struct ClientsState { /// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs /// sync loop. pub fn metrics_prefix(lane: &LaneId) -> String { - format!("{}_to_{}_MessageLane_{}", P::SOURCE_NAME, P::TARGET_NAME, hex::encode(lane)) + format!("{}_to_{}_MessageLane_{:?}", P::SOURCE_NAME, P::TARGET_NAME, lane) } /// Run message lane service loop. @@ -957,7 +957,7 @@ pub(crate) mod tests { }; let _ = run( Params { - lane: LaneId([0, 0, 0, 0]), + lane: LaneId::new(1, 2), source_tick: Duration::from_millis(100), target_tick: Duration::from_millis(100), reconnect_delay: Duration::from_millis(0), @@ -1274,4 +1274,12 @@ pub(crate) mod tests { assert!(!result.target_to_source_header_requirements.is_empty()); assert!(!result.source_to_target_header_requirements.is_empty()); } + + #[test] + fn metrics_prefix_is_valid() { + assert!(MessageLaneLoopMetrics::new(Some(&metrics_prefix::( + &LaneId::new(1, 2) + ))) + .is_ok()); + } } From 4f0dc6a306b4529dfaee7fec08f1a84ea63a9cea Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 3 Jul 2023 16:56:23 +0300 Subject: [PATCH 08/95] Introduce MessagesLaneManager (#2227) * some useful stuff like LanesManager * clippy * more clippy * Error::LanesManager * {in, out}bound_lane -> active_{in, out}bound_lane * merge two impl blocks in one * fmt --- bridges/modules/messages/src/inbound_lane.rs | 31 ++- bridges/modules/messages/src/lanes_manager.rs | 263 ++++++++++++++++++ bridges/modules/messages/src/lib.rs | 162 ++--------- bridges/modules/messages/src/outbound_lane.rs | 39 ++- .../messages/src/tests/pallet_tests.rs | 17 +- bridges/primitives/header-chain/src/lib.rs | 13 + bridges/primitives/messages/src/lib.rs | 15 +- 7 files changed, 380 insertions(+), 160 deletions(-) create mode 100644 bridges/modules/messages/src/lanes_manager.rs diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 3f397d025d27..ccc1b1b60caa 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -20,8 +20,8 @@ use crate::{BridgedChainOf, Config}; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, - OutboundLaneData, ReceptionResult, UnrewardedRelayer, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, MessageKey, + MessageNonce, OutboundLaneData, ReceptionResult, UnrewardedRelayer, }; use bp_runtime::AccountIdOf; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; @@ -44,6 +44,8 @@ pub trait InboundLaneStorage { fn data(&self) -> InboundLaneData; /// Update lane data in the storage. fn set_data(&mut self, data: InboundLaneData); + /// Purge lane data from the storage. + fn purge(self); } /// Inbound lane data wrapper that implements `MaxEncodedLen`. @@ -120,9 +122,21 @@ impl InboundLane { InboundLane { storage } } - /// Returns `mut` storage reference. - pub fn storage_mut(&mut self) -> &mut S { - &mut self.storage + /// Get lane state. + pub fn state(&self) -> LaneState { + self.storage.data().state + } + + /// Returns storage reference. + pub fn storage(&self) -> &S { + &self.storage + } + + /// Set lane state. + pub fn set_state(&mut self, state: LaneState) { + let mut data = self.storage.data(); + data.state = state; + self.storage.set_data(data); } /// Receive state of the corresponding outbound lane. @@ -211,12 +225,17 @@ impl InboundLane { ReceptionResult::Dispatched(dispatch_result) } + + /// Purge lane state from the storage. + pub fn purge(self) { + self.storage.purge() + } } #[cfg(test)] mod tests { use super::*; - use crate::{inbound_lane, tests::mock::*, RuntimeInboundLaneStorage}; + use crate::{inbound_lane, lanes_manager::RuntimeInboundLaneStorage, tests::mock::*}; use bp_messages::UnrewardedRelayersState; fn receive_regular_message( diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs new file mode 100644 index 000000000000..911bed9fcb67 --- /dev/null +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -0,0 +1,263 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +use crate::{ + BridgedChainOf, Config, InboundLane, InboundLaneStorage, InboundLanes, OutboundLane, + OutboundLaneStorage, OutboundLanes, OutboundMessages, StoredInboundLaneData, + StoredMessagePayload, +}; + +use bp_messages::{ + ChainWithMessages, InboundLaneData, LaneId, LaneState, MessageKey, MessageNonce, + OutboundLaneData, +}; +use bp_runtime::AccountIdOf; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ensure, sp_runtime::RuntimeDebug, PalletError}; +use scale_info::TypeInfo; +use sp_std::marker::PhantomData; + +/// Lanes manager errors. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum LanesManagerError { + /// Inbound lane already exists. + InboundLaneAlreadyExists, + /// Outbound lane already exists. + OutboundLaneAlreadyExists, + /// No inbound lane with given id. + UnknownInboundLane, + /// No outbound lane with given id. + UnknownOutboundLane, + /// Inbound lane with given id is closed. + ClosedInboundLane, + /// Outbound lane with given id is closed. + ClosedOutboundLane, +} + +/// Message lanes manager. +pub struct LanesManager(PhantomData<(T, I)>); + +impl, I: 'static> Default for LanesManager { + fn default() -> Self { + Self::new() + } +} + +impl, I: 'static> LanesManager { + /// Create new lanes manager. + pub fn new() -> Self { + Self(PhantomData) + } + + /// Create new inbound lane in `Opened` state. + pub fn create_inbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + InboundLanes::::try_mutate(lane_id, |lane| match lane { + Some(_) => Err(LanesManagerError::InboundLaneAlreadyExists), + None => { + *lane = Some(StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, + ..Default::default() + })); + Ok(()) + }, + })?; + + self.active_inbound_lane(lane_id) + } + + /// Create new outbound lane in `Opened` state. + pub fn create_outbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + OutboundLanes::::try_mutate(lane_id, |lane| match lane { + Some(_) => Err(LanesManagerError::OutboundLaneAlreadyExists), + None => { + *lane = Some(OutboundLaneData { state: LaneState::Opened, ..Default::default() }); + Ok(()) + }, + })?; + + self.active_outbound_lane(lane_id) + } + + /// Get existing inbound lane, checking that it is in usable state. + pub fn active_inbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, true)?)) + } + + /// Get existing outbound lane, checking that it is in usable state. + pub fn active_outbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, true)?)) + } + + /// Get existing inbound lane without any additional state checks. + pub fn any_state_inbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, false)?)) + } + + /// Get existing outbound lane without any additional state checks. + pub fn any_state_outbound_lane( + &self, + lane_id: LaneId, + ) -> Result>, LanesManagerError> { + Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, false)?)) + } +} + +/// Runtime inbound lane storage. +pub struct RuntimeInboundLaneStorage, I: 'static = ()> { + pub(crate) lane_id: LaneId, + pub(crate) cached_data: InboundLaneData>>, + pub(crate) _phantom: PhantomData, +} + +impl, I: 'static> RuntimeInboundLaneStorage { + /// Creates new runtime inbound lane storage for given **existing** lane. + fn from_lane_id( + lane_id: LaneId, + check_active: bool, + ) -> Result, LanesManagerError> { + let cached_data = + InboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownInboundLane)?; + ensure!( + !check_active || cached_data.state.is_active(), + LanesManagerError::ClosedInboundLane + ); + Ok(RuntimeInboundLaneStorage { + lane_id, + cached_data: cached_data.into(), + _phantom: Default::default(), + }) + } + + /// Returns number of bytes that may be subtracted from the PoV component of + /// `receive_messages_proof` call, because the actual inbound lane state is smaller than the + /// maximal configured. + /// + /// Maximal inbound lane state set size is configured by the + /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV + /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, + /// we may subtract extra bytes from this component. + pub fn extra_proof_size_bytes(&self) -> u64 { + let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); + let relayers_count = self.data().relayers.len(); + let actual_encoded_len = + InboundLaneData::>>::encoded_size_hint(relayers_count) + .unwrap_or(usize::MAX); + max_encoded_len.saturating_sub(actual_encoded_len) as _ + } +} + +impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { + type Relayer = AccountIdOf>; + + fn id(&self) -> LaneId { + self.lane_id + } + + fn max_unrewarded_relayer_entries(&self) -> MessageNonce { + BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX + } + + fn max_unconfirmed_messages(&self) -> MessageNonce { + BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + } + + fn data(&self) -> InboundLaneData>> { + self.cached_data.clone() + } + + fn set_data(&mut self, data: InboundLaneData>>) { + self.cached_data = data.clone(); + InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) + } + + fn purge(self) { + InboundLanes::::remove(self.lane_id) + } +} + +/// Runtime outbound lane storage. +#[derive(Debug, PartialEq, Eq)] +pub struct RuntimeOutboundLaneStorage { + pub(crate) lane_id: LaneId, + pub(crate) cached_data: OutboundLaneData, + pub(crate) _phantom: PhantomData<(T, I)>, +} + +impl, I: 'static> RuntimeOutboundLaneStorage { + /// Creates new runtime outbound lane storage for given **existing** lane. + fn from_lane_id(lane_id: LaneId, check_active: bool) -> Result { + let cached_data = + OutboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownOutboundLane)?; + ensure!( + !check_active || cached_data.state.is_active(), + LanesManagerError::ClosedOutboundLane + ); + Ok(Self { lane_id, cached_data, _phantom: PhantomData }) + } +} + +impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { + type StoredMessagePayload = StoredMessagePayload; + + fn id(&self) -> LaneId { + self.lane_id + } + + fn data(&self) -> OutboundLaneData { + self.cached_data.clone() + } + + fn set_data(&mut self, data: OutboundLaneData) { + self.cached_data = data.clone(); + OutboundLanes::::insert(self.lane_id, data) + } + + #[cfg(test)] + fn message(&self, nonce: &MessageNonce) -> Option { + OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) + .map(Into::into) + } + + fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) { + OutboundMessages::::insert( + MessageKey { lane_id: self.lane_id, nonce }, + message_payload, + ); + } + + fn remove_message(&mut self, nonce: &MessageNonce) { + OutboundMessages::::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce }); + } + + fn purge(self) { + OutboundLanes::::remove(self.lane_id) + } +} diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index b8a7fba6c1e8..8bf601100807 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -36,8 +36,13 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -pub use inbound_lane::StoredInboundLaneData; -pub use outbound_lane::StoredMessagePayload; +pub use inbound_lane::{InboundLane, InboundLaneStorage, StoredInboundLaneData}; +pub use lanes_manager::{ + LanesManager, LanesManagerError, RuntimeInboundLaneStorage, RuntimeOutboundLaneStorage, +}; +pub use outbound_lane::{ + OutboundLane, OutboundLaneStorage, ReceptionConfirmationError, StoredMessagePayload, +}; pub use weights::WeightInfo; pub use weights_ext::{ ensure_able_to_receive_confirmation, ensure_able_to_receive_message, @@ -45,11 +50,6 @@ pub use weights_ext::{ EXPECTED_DEFAULT_MESSAGE_LENGTH, EXTRA_STORAGE_PROOF_SIZE, }; -use crate::{ - inbound_lane::{InboundLane, InboundLaneStorage}, - outbound_lane::{OutboundLane, OutboundLaneStorage, ReceptionConfirmationError}, -}; - use bp_header_chain::HeaderChain; use bp_messages::{ source_chain::{ @@ -61,18 +61,19 @@ use bp_messages::{ ProvedLaneMessages, ProvedMessages, }, ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - LaneState, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, + MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ AccountIdOf, BasicOperatingMode, HashOf, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, Size, }; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound}; use sp_std::{marker::PhantomData, prelude::*}; mod inbound_lane; +mod lanes_manager; mod outbound_lane; mod proofs; mod tests; @@ -250,7 +251,7 @@ pub mod pallet { // subtract extra storage proof bytes from the actual PoV size - there may be // less unrewarded relayers than the maximal configured value - let lane_extra_proof_size_bytes = lane.storage_mut().extra_proof_size_bytes(); + let lane_extra_proof_size_bytes = lane.storage().extra_proof_size_bytes(); actual_weight = actual_weight.set_proof_size( actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), ); @@ -263,7 +264,7 @@ pub mod pallet { "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", lane_id, updated_latest_confirmed_nonce, - UnrewardedRelayersState::from(&lane.storage_mut().data()), + UnrewardedRelayersState::from(&lane.storage().data()), ); } } @@ -467,19 +468,10 @@ pub mod pallet { NotOperatingNormally, /// The inbound message dispatcher is inactive. MessageDispatchInactive, - /// The outbound lane is unknown. - UnknownOutboundLane, - /// The outbound lane exists, but it is currently closed. - ClosedOutboundLane, - /// The inbound lane is unknown. - UnknownInboundLane, - /// The inbound lane exists, but it is currently closed. - ClosedInboundLane, - /// Message has been treated as invalid by chain verifier. + /// Error that is reported by the lanes manager. + LanesManager(LanesManagerError), /// Message has been treated as invalid by the pallet logic. MessageRejectedByPallet(VerificationError), - /// Submitter has failed to pay fee for delivering and dispatching messages. - FailedToWithdrawMessageFee, /// The transaction brings too many messages. TooManyMessagesInTheProof, /// Invalid messages has been submitted. @@ -492,8 +484,6 @@ pub mod pallet { /// The cumulative dispatch weight, passed by relayer is not enough to cover dispatch /// of all bundled messages. InsufficientDispatchWeight, - /// The message someone is trying to work with (i.e. increase fee) is not yet sent. - MessageIsNotYetSent, /// Error confirming messages receival. ReceptionConfirmation(ReceptionConfirmationError), /// Error generated by the `OwnedBridgeModule` trait. @@ -767,130 +757,18 @@ fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error< fn inbound_lane, I: 'static>( lane_id: LaneId, ) -> Result>, Error> { - Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id)?)) + LanesManager::::new() + .active_inbound_lane(lane_id) + .map_err(Error::LanesManager) } /// Creates new outbound lane object, backed by runtime storage. fn outbound_lane, I: 'static>( lane_id: LaneId, ) -> Result>, Error> { - Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id)?)) -} - -/// Runtime inbound lane storage. -struct RuntimeInboundLaneStorage, I: 'static = ()> { - lane_id: LaneId, - cached_data: InboundLaneData>>, - _phantom: PhantomData, -} - -impl, I: 'static> RuntimeInboundLaneStorage { - /// Creates new runtime inbound lane storage for given **existing** lane. - fn from_lane_id(lane_id: LaneId) -> Result, Error> { - let cached_data = - InboundLanes::::get(lane_id).ok_or(Error::::UnknownInboundLane)?; - ensure!(cached_data.state == LaneState::Opened, Error::::ClosedInboundLane); - Ok(RuntimeInboundLaneStorage { - lane_id, - cached_data: cached_data.into(), - _phantom: Default::default(), - }) - } -} - -impl, I: 'static> RuntimeInboundLaneStorage { - /// Returns number of bytes that may be subtracted from the PoV component of - /// `receive_messages_proof` call, because the actual inbound lane state is smaller than the - /// maximal configured. - /// - /// Maximal inbound lane state set size is configured by the - /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV - /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, - /// we may subtract extra bytes from this component. - pub fn extra_proof_size_bytes(&mut self) -> u64 { - let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); - let relayers_count = self.data().relayers.len(); - let actual_encoded_len = - InboundLaneData::>>::encoded_size_hint(relayers_count) - .unwrap_or(usize::MAX); - max_encoded_len.saturating_sub(actual_encoded_len) as _ - } -} - -impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { - type Relayer = AccountIdOf>; - - fn id(&self) -> LaneId { - self.lane_id - } - - fn max_unrewarded_relayer_entries(&self) -> MessageNonce { - BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX - } - - fn max_unconfirmed_messages(&self) -> MessageNonce { - BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - } - - fn data(&self) -> InboundLaneData>> { - self.cached_data.clone() - } - - fn set_data(&mut self, data: InboundLaneData>>) { - self.cached_data = data.clone(); - InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) - } -} - -/// Runtime outbound lane storage. -#[derive(Debug, PartialEq, Eq)] -struct RuntimeOutboundLaneStorage { - lane_id: LaneId, - cached_data: OutboundLaneData, - _phantom: PhantomData<(T, I)>, -} - -impl, I: 'static> RuntimeOutboundLaneStorage { - /// Creates new runtime outbound lane storage for given **existing** lane. - fn from_lane_id(lane_id: LaneId) -> Result> { - let cached_data = - OutboundLanes::::get(lane_id).ok_or(Error::::UnknownOutboundLane)?; - ensure!(cached_data.state == LaneState::Opened, Error::::ClosedOutboundLane); - Ok(Self { lane_id, cached_data, _phantom: PhantomData }) - } -} - -impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { - type StoredMessagePayload = StoredMessagePayload; - - fn id(&self) -> LaneId { - self.lane_id - } - - fn data(&self) -> OutboundLaneData { - self.cached_data.clone() - } - - fn set_data(&mut self, data: OutboundLaneData) { - self.cached_data = data.clone(); - OutboundLanes::::insert(self.lane_id, data) - } - - #[cfg(test)] - fn message(&self, nonce: &MessageNonce) -> Option { - OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) - } - - fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) { - OutboundMessages::::insert( - MessageKey { lane_id: self.lane_id, nonce }, - message_payload, - ); - } - - fn remove_message(&mut self, nonce: &MessageNonce) { - OutboundMessages::::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce }); - } + LanesManager::::new() + .active_outbound_lane(lane_id) + .map_err(Error::LanesManager) } /// Verify messages proof and return proved messages with decoded payload. diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index 647618b66f16..9dd8b4be6f83 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -19,16 +19,18 @@ use crate::{Config, LOG_TARGET}; use bp_messages::{ - ChainWithMessages, DeliveredMessages, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, + ChainWithMessages, DeliveredMessages, LaneId, LaneState, MessageNonce, OutboundLaneData, + UnrewardedRelayer, }; use codec::{Decode, Encode}; use frame_support::{traits::Get, BoundedVec, PalletError}; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; /// Outbound lane storage. pub trait OutboundLaneStorage { + /// Stored message payload type. type StoredMessagePayload; /// Lane id. @@ -44,6 +46,8 @@ pub trait OutboundLaneStorage { fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload); /// Remove outbound message from the storage. fn remove_message(&mut self, nonce: &MessageNonce); + /// Purge lane data from the storage. + fn purge(self); } /// Limit for the `StoredMessagePayload` vector. @@ -91,6 +95,24 @@ impl OutboundLane { self.storage.data() } + /// Get lane state. + pub fn state(&self) -> LaneState { + self.storage.data().state + } + + /// Set lane state. + pub fn set_state(&mut self, state: LaneState) { + let mut data = self.storage.data(); + data.state = state; + self.storage.set_data(data); + } + + /// Return nonces of all currently queued messages. + pub fn queued_messages(&self) -> RangeInclusive { + let data = self.storage.data(); + data.oldest_unpruned_nonce..=data.latest_generated_nonce + } + /// Send message over lane. /// /// Returns new message nonce. @@ -151,6 +173,19 @@ impl OutboundLane { Ok(Some(confirmed_messages)) } + + /// Remove message from the storage. Doesn't perform any checks. + pub fn remove_oldest_unpruned_message(&mut self) { + let mut data = self.storage.data(); + self.storage.remove_message(&data.oldest_unpruned_nonce); + data.oldest_unpruned_nonce += 1; + self.storage.set_data(data); + } + + /// Purge lane state from the storage. + pub fn purge(self) { + self.storage.purge() + } } /// Verifies unrewarded relayers vec. diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 1df17112c699..397fdc032973 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -17,12 +17,13 @@ //! Pallet-level tests. use crate::{ + lanes_manager::RuntimeInboundLaneStorage, outbound_lane, outbound_lane::ReceptionConfirmationError, tests::mock::{RuntimeEvent as TestEvent, *}, weights_ext::WeightInfoExt, - Call, Config, Error, Event, InboundLanes, OutboundLanes, OutboundMessages, Pallet, - PalletOperatingMode, PalletOwner, RuntimeInboundLaneStorage, StoredInboundLaneData, + Call, Config, Error, Event, InboundLanes, LanesManagerError, OutboundLanes, OutboundMessages, + Pallet, PalletOperatingMode, PalletOwner, StoredInboundLaneData, }; use bp_messages::{ @@ -1020,12 +1021,12 @@ fn send_messages_fails_if_outbound_lane_is_not_opened() { run_test(|| { assert_noop!( Pallet::::validate_message(unknown_lane_id(), ®ULAR_PAYLOAD), - Error::::UnknownOutboundLane, + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), ); assert_noop!( Pallet::::validate_message(closed_lane_id(), ®ULAR_PAYLOAD), - Error::::ClosedOutboundLane, + Error::::LanesManager(LanesManagerError::ClosedOutboundLane), ); }); } @@ -1045,7 +1046,7 @@ fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { 1, REGULAR_PAYLOAD.declared_weight, ), - Error::::UnknownInboundLane, + Error::::LanesManager(LanesManagerError::UnknownInboundLane), ); message.key.lane_id = closed_lane_id(); @@ -1059,7 +1060,7 @@ fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { 1, REGULAR_PAYLOAD.declared_weight, ), - Error::::ClosedInboundLane, + Error::::LanesManager(LanesManagerError::ClosedInboundLane), ); }); } @@ -1094,7 +1095,7 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { last_delivered_nonce: 1, }, ), - Error::::UnknownOutboundLane, + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), ); let proof = make_proof(closed_lane_id()); @@ -1109,7 +1110,7 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { last_delivered_nonce: 1, }, ), - Error::::ClosedOutboundLane, + Error::::LanesManager(LanesManagerError::ClosedOutboundLane), ); }); } diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 26295dee1801..509e2d062704 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -90,6 +90,19 @@ pub trait HeaderChain { } } +impl HeaderChain for () { + fn finalized_header_state_root(_header_hash: HashOf) -> Option> { + None + } + + fn verify_storage_proof( + _header_hash: HashOf, + _db: UnverifiedStorageProof, + ) -> Result { + Err(HeaderChainError::UnknownHeader) + } +} + /// A type that can be used as a parameter in a dispatchable function. /// /// When using `decl_module` all arguments for call functions must implement this trait. diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 6bfb4e79e98e..540b6a37d794 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -252,6 +252,12 @@ impl TypeId for LaneId { /// Lane state. #[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub enum LaneState { + /// Lane is opened and messages may be sent/received over it. + Opened, + /// Lane is closing. It is equal to the `Opened` state, but it will switch to + /// the `Closed` state and then vanish after some period. This state is here + /// to give bridged chain ability to know that the lane is going to be closed. + Closing, /// Lane is closed and all attempts to send/receive messages to/from this lane /// will fail. /// @@ -260,8 +266,13 @@ pub enum LaneState { /// and/or sending messages over the lane, have to coordinate their actions on /// both ends to make sure that lane is operating smoothly on both ends. Closed, - /// Lane is opened and messages may be sent/received over it. - Opened, +} + +impl LaneState { + /// Returns true if lane state allows sending/receiving messages. + pub fn is_active(&self) -> bool { + matches!(*self, LaneState::Opened | LaneState::Closing) + } } /// Message nonce. Valid messages will never have 0 nonce. From 0ba297eaa224e6658492ca4dd69f44d7a0e42f0b Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 4 Jul 2023 16:23:26 +0200 Subject: [PATCH 09/95] Backport from staging (#2243) * Updated version according to Cumulus * Updated docs --- .../docs/polkadot-kusama-bridge-overview.md | 18 ++++++++++-------- bridges/modules/messages/README.md | 7 ++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/bridges/docs/polkadot-kusama-bridge-overview.md b/bridges/docs/polkadot-kusama-bridge-overview.md index 08036f0b0722..bd8e48285856 100644 --- a/bridges/docs/polkadot-kusama-bridge-overview.md +++ b/bridges/docs/polkadot-kusama-bridge-overview.md @@ -25,8 +25,9 @@ You won't be able to directly use bridge hub transactions to send XCM messages o use other parachains transactions, which will use HRMP to deliver messages to the Bridge Hub. The Bridge Hub will just queue these messages in its outbound lane, which is dedicated to deliver messages between two parachains. -Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two parachains would -allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama accounts to hold wrapped DOT tokens. +Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two +parachains would allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama +accounts to hold wrapped DOT tokens. For that bridge (pair of parachains under different consensus systems) we'll be using the lane 00000000. Later, when other parachains will join the bridge, they will be using other lanes for their messages. @@ -92,13 +93,14 @@ Obviously, there should be someone who is paying relayer rewards. We want bridge can't use fees for rewards. Instead, the parachains using the bridge, use sovereign accounts on both sides of the bridge to cover relayer rewards. -Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will have an account -at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama Bridge Hub. The sovereign accounts -are used as a source of funds when the relayer is calling the `pallet_bridge_relayers::claim_rewards`. +Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will +have an account at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama +Bridge Hub. The sovereign accounts are used as a source of funds when the relayer is calling the +`pallet_bridge_relayers::claim_rewards`. -Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. Kusama -Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign -account is not used to cover rewards of bridging with some other Polkadot Parachain. +Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. +Kusama Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign account +is not used to cover rewards of bridging with some other Polkadot Parachain. ### Multiple Relayers and Rewards diff --git a/bridges/modules/messages/README.md b/bridges/modules/messages/README.md index bf5cced43854..a78c86802498 100644 --- a/bridges/modules/messages/README.md +++ b/bridges/modules/messages/README.md @@ -28,9 +28,10 @@ Single message lane may be seen as a transport channel for single application (o time the module itself never dictates any lane or message rules. In the end, it is the runtime developer who defines what message lane and message mean for this runtime. -In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane as a channel of -communication between two parachains of different relay chains. For example, lane `[0, 0, 0, 0]` is used for Polkadot <> -Kusama Asset Hub communications. Other lanes may be used to bridge other parachains. +In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane +as a channel of communication between two parachains of different relay chains. For example, lane +`[0, 0, 0, 0]` is used for Polkadot <> Kusama Asset Hub communications. Other lanes may be used to +bridge other parachains. ## Message Workflow From 963382e8c58a66c20b098ab11d7824ae563481ad Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 11 Jul 2023 17:03:04 +0300 Subject: [PATCH 10/95] Allow delivery confirmations on closed outbound lanes (#2257) * allow delivery confirmations on closed outbound lanes * fix benchmarks compilation --- bridges/modules/messages/src/benchmarking.rs | 4 +- bridges/modules/messages/src/inbound_lane.rs | 26 ++++++------- bridges/modules/messages/src/lib.rs | 23 ++++++++---- bridges/modules/messages/src/outbound_lane.rs | 14 +++---- .../messages/src/tests/pallet_tests.rs | 37 ++++++++++--------- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index e12b6c923ef8..b3a4447fb021 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -19,7 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{ - outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, BridgedChainOf, Call, + active_outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, BridgedChainOf, Call, InboundLanes, OutboundLanes, }; @@ -120,7 +120,7 @@ fn send_regular_message, I: 'static>() { }, ); - let mut outbound_lane = outbound_lane::(T::bench_lane_id()).unwrap(); + let mut outbound_lane = active_outbound_lane::(T::bench_lane_id()).unwrap(); outbound_lane.send_message(BoundedVec::try_from(vec![]).expect("We craft valid messages")); } diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index ccc1b1b60caa..65240feb7194 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -235,7 +235,7 @@ impl InboundLane { #[cfg(test)] mod tests { use super::*; - use crate::{inbound_lane, lanes_manager::RuntimeInboundLaneStorage, tests::mock::*}; + use crate::{active_inbound_lane, lanes_manager::RuntimeInboundLaneStorage, tests::mock::*}; use bp_messages::UnrewardedRelayersState; fn receive_regular_message( @@ -255,7 +255,7 @@ mod tests { #[test] fn receive_status_update_ignores_status_from_the_future() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -272,7 +272,7 @@ mod tests { #[test] fn receive_status_update_ignores_obsolete_status() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -299,7 +299,7 @@ mod tests { #[test] fn receive_status_update_works() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -337,7 +337,7 @@ mod tests { #[test] fn receive_status_update_works_with_batches_from_relayers() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let mut seed_storage_data = lane.storage.data(); // Prepare data seed_storage_data.last_confirmed_nonce = 0; @@ -368,7 +368,7 @@ mod tests { #[test] fn fails_to_receive_message_with_incorrect_nonce() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -384,7 +384,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; for current_nonce in 1..max_nonce + 1 { assert_eq!( @@ -420,7 +420,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; for current_nonce in 1..=max_nonce { assert_eq!( @@ -456,7 +456,7 @@ mod tests { #[test] fn correctly_receives_following_messages_from_two_relayers_alternately() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -495,7 +495,7 @@ mod tests { #[test] fn rejects_same_message_from_two_different_relayers() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -518,7 +518,7 @@ mod tests { #[test] fn correct_message_is_processed_instantly() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!(lane.storage.data().last_delivered_nonce(), 1); }); @@ -527,7 +527,7 @@ mod tests { #[test] fn unspent_weight_is_returned_by_receive_message() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let mut payload = REGULAR_PAYLOAD; *payload.dispatch_result.unspent_weight.ref_time_mut() = 1; assert_eq!( @@ -544,7 +544,7 @@ mod tests { #[test] fn first_message_is_confirmed_correctly() { run_test(|| { - let mut lane = inbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); assert_eq!( diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 8bf601100807..ea2e6fca517a 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -247,7 +247,7 @@ pub mod pallet { let mut messages_received_status = Vec::with_capacity(messages.len()); let mut dispatch_weight_left = dispatch_weight; for (lane_id, lane_data) in messages { - let mut lane = inbound_lane::(lane_id)?; + let mut lane = active_inbound_lane::(lane_id)?; // subtract extra storage proof bytes from the actual PoV size - there may be // less unrewarded relayers than the maximal configured value @@ -375,7 +375,7 @@ pub mod pallet { ); // mark messages as delivered - let mut lane = outbound_lane::(lane_id)?; + let mut lane = any_state_outbound_lane::(lane_id)?; let last_delivered_nonce = lane_data.last_delivered_nonce(); let confirmed_messages = lane .confirm_delivery( @@ -708,7 +708,7 @@ where ensure_normal_operating_mode::()?; // check lane - let lane = outbound_lane::(lane_id)?; + let lane = active_outbound_lane::(lane_id)?; Ok(SendMessageArgs { lane_id, @@ -753,8 +753,8 @@ fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error< Err(Error::::NotOperatingNormally) } -/// Creates new inbound lane object, backed by runtime storage. -fn inbound_lane, I: 'static>( +/// Creates new inbound lane object, backed by runtime storage. Lane must be active. +fn active_inbound_lane, I: 'static>( lane_id: LaneId, ) -> Result>, Error> { LanesManager::::new() @@ -762,8 +762,8 @@ fn inbound_lane, I: 'static>( .map_err(Error::LanesManager) } -/// Creates new outbound lane object, backed by runtime storage. -fn outbound_lane, I: 'static>( +/// Creates new outbound lane object, backed by runtime storage. Lane must be active. +fn active_outbound_lane, I: 'static>( lane_id: LaneId, ) -> Result>, Error> { LanesManager::::new() @@ -771,6 +771,15 @@ fn outbound_lane, I: 'static>( .map_err(Error::LanesManager) } +/// Creates new outbound lane object, backed by runtime storage. +fn any_state_outbound_lane, I: 'static>( + lane_id: LaneId, +) -> Result>, Error> { + LanesManager::::new() + .any_state_outbound_lane(lane_id) + .map_err(Error::LanesManager) +} + /// Verify messages proof and return proved messages with decoded payload. fn verify_and_decode_messages_proof, I: 'static>( proof: FromBridgedChainMessagesProof>>, diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index 9dd8b4be6f83..f71240ab7c70 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -223,7 +223,7 @@ fn ensure_unrewarded_relayers_are_correct( mod tests { use super::*; use crate::{ - outbound_lane, + active_outbound_lane, tests::mock::{ outbound_message_data, run_test, test_lane_id, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD, @@ -248,7 +248,7 @@ mod tests { relayers: &VecDeque>, ) -> Result, ReceptionConfirmationError> { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -264,7 +264,7 @@ mod tests { #[test] fn send_message_works() { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.storage.data().latest_generated_nonce, 0); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert!(lane.storage.message(&1).is_some()); @@ -275,7 +275,7 @@ mod tests { #[test] fn confirm_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -295,7 +295,7 @@ mod tests { #[test] fn confirm_partial_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -324,7 +324,7 @@ mod tests { #[test] fn confirm_delivery_rejects_nonce_lesser_than_latest_received() { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -404,7 +404,7 @@ mod tests { #[test] fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { run_test(|| { - let mut lane = outbound_lane::(test_lane_id()).unwrap(); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 397fdc032973..13d5af15a3be 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -17,8 +17,8 @@ //! Pallet-level tests. use crate::{ + active_outbound_lane, lanes_manager::RuntimeInboundLaneStorage, - outbound_lane, outbound_lane::ReceptionConfirmationError, tests::mock::{RuntimeEvent as TestEvent, *}, weights_ext::WeightInfoExt, @@ -54,7 +54,7 @@ fn get_ready_for_events() { fn send_regular_message(lane_id: LaneId) { get_ready_for_events(); - let outbound_lane = outbound_lane::(lane_id).unwrap(); + let outbound_lane = active_outbound_lane::(lane_id).unwrap(); let message_nonce = outbound_lane.data().latest_generated_nonce + 1; let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) @@ -441,6 +441,24 @@ fn receive_messages_delivery_proof_works() { }); } +#[test] +fn receive_messages_delivery_proof_works_on_closed_outbound_lanes() { + run_test(|| { + send_regular_message(test_lane_id()); + active_outbound_lane::(test_lane_id()) + .unwrap() + .set_state(LaneState::Closed); + receive_messages_delivery_proof(); + + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .latest_received_nonce, + 1, + ); + }); +} + #[test] fn receive_messages_delivery_proof_rewards_relayers() { run_test(|| { @@ -1097,20 +1115,5 @@ fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { ), Error::::LanesManager(LanesManagerError::UnknownOutboundLane), ); - - let proof = make_proof(closed_lane_id()); - assert_noop!( - Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - proof, - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - ), - Error::::LanesManager(LanesManagerError::ClosedOutboundLane), - ); }); } From 1b372c1bca522611c85c7bf6847000e78540946c Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 13 Jul 2023 10:36:03 +0300 Subject: [PATCH 11/95] remove internal code that pretends to support cross-lane delivery transactions (#2259) --- bridges/modules/messages/src/lib.rs | 166 +++++++++--------- bridges/modules/messages/src/proofs.rs | 18 +- .../primitives/messages/src/target_chain.rs | 4 +- 3 files changed, 86 insertions(+), 102 deletions(-) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index ea2e6fca517a..554db4faa8ec 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -234,92 +234,89 @@ pub mod pallet { let mut actual_weight = declared_weight; // verify messages proof && convert proof into messages - let messages = verify_and_decode_messages_proof::(*proof, messages_count) - .map_err(|err| { - log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); + let (lane_id, lane_data) = + verify_and_decode_messages_proof::(*proof, messages_count).map_err( + |err| { + log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); - Error::::InvalidMessagesProof - })?; + Error::::InvalidMessagesProof + }, + )?; // dispatch messages and (optionally) update lane(s) state(s) let mut total_messages = 0; let mut valid_messages = 0; - let mut messages_received_status = Vec::with_capacity(messages.len()); let mut dispatch_weight_left = dispatch_weight; - for (lane_id, lane_data) in messages { - let mut lane = active_inbound_lane::(lane_id)?; - - // subtract extra storage proof bytes from the actual PoV size - there may be - // less unrewarded relayers than the maximal configured value - let lane_extra_proof_size_bytes = lane.storage().extra_proof_size_bytes(); - actual_weight = actual_weight.set_proof_size( - actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), - ); + let mut lane = active_inbound_lane::(lane_id)?; - if let Some(lane_state) = lane_data.lane_state { - let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); - if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { - log::trace!( - target: LOG_TARGET, - "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", - lane_id, - updated_latest_confirmed_nonce, - UnrewardedRelayersState::from(&lane.storage().data()), - ); - } - } + // subtract extra storage proof bytes from the actual PoV size - there may be + // less unrewarded relayers than the maximal configured value + let lane_extra_proof_size_bytes = lane.storage().extra_proof_size_bytes(); + actual_weight = actual_weight.set_proof_size( + actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), + ); - let mut lane_messages_received_status = - ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); - for mut message in lane_data.messages { - debug_assert_eq!(message.key.lane_id, lane_id); - total_messages += 1; - - // ensure that relayer has declared enough weight for dispatching next message - // on this lane. We can't dispatch lane messages out-of-order, so if declared - // weight is not enough, let's move to next lane - let message_dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); - if message_dispatch_weight.any_gt(dispatch_weight_left) { - log::trace!( - target: LOG_TARGET, - "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", - lane_id, - message_dispatch_weight, - dispatch_weight_left, - ); - - fail!(Error::::InsufficientDispatchWeight); - } + if let Some(lane_state) = lane_data.lane_state { + let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); + if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { + log::trace!( + target: LOG_TARGET, + "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", + lane_id, + updated_latest_confirmed_nonce, + UnrewardedRelayersState::from(&lane.storage().data()), + ); + } + } - let receival_result = lane.receive_message::( - &relayer_id_at_bridged_chain, - message.key.nonce, - message.data, + let mut messages_received_status = + ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); + for mut message in lane_data.messages { + debug_assert_eq!(message.key.lane_id, lane_id); + total_messages += 1; + + // ensure that relayer has declared enough weight for dispatching next message + // on this lane. We can't dispatch lane messages out-of-order, so if declared + // weight is not enough, let's move to next lane + let message_dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); + if message_dispatch_weight.any_gt(dispatch_weight_left) { + log::trace!( + target: LOG_TARGET, + "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", + lane_id, + message_dispatch_weight, + dispatch_weight_left, ); - // note that we're returning unspent weight to relayer even if message has been - // rejected by the lane. This allows relayers to submit spam transactions with - // e.g. the same set of already delivered messages over and over again, without - // losing funds for messages dispatch. But keep in mind that relayer pays base - // delivery transaction cost anyway. And base cost covers everything except - // dispatch, so we have a balance here. - let unspent_weight = match &receival_result { - ReceptionResult::Dispatched(dispatch_result) => { - valid_messages += 1; - dispatch_result.unspent_weight - }, - ReceptionResult::InvalidNonce | - ReceptionResult::TooManyUnrewardedRelayers | - ReceptionResult::TooManyUnconfirmedMessages => message_dispatch_weight, - }; - lane_messages_received_status.push(message.key.nonce, receival_result); - - let unspent_weight = unspent_weight.min(message_dispatch_weight); - dispatch_weight_left -= message_dispatch_weight - unspent_weight; - actual_weight = actual_weight.saturating_sub(unspent_weight); + fail!(Error::::InsufficientDispatchWeight); } - messages_received_status.push(lane_messages_received_status); + let receival_result = lane.receive_message::( + &relayer_id_at_bridged_chain, + message.key.nonce, + message.data, + ); + + // note that we're returning unspent weight to relayer even if message has been + // rejected by the lane. This allows relayers to submit spam transactions with + // e.g. the same set of already delivered messages over and over again, without + // losing funds for messages dispatch. But keep in mind that relayer pays base + // delivery transaction cost anyway. And base cost covers everything except + // dispatch, so we have a balance here. + let unspent_weight = match &receival_result { + ReceptionResult::Dispatched(dispatch_result) => { + valid_messages += 1; + dispatch_result.unspent_weight + }, + ReceptionResult::InvalidNonce | + ReceptionResult::TooManyUnrewardedRelayers | + ReceptionResult::TooManyUnconfirmedMessages => message_dispatch_weight, + }; + messages_received_status.push(message.key.nonce, receival_result); + + let unspent_weight = unspent_weight.min(message_dispatch_weight); + dispatch_weight_left -= message_dispatch_weight - unspent_weight; + actual_weight = actual_weight.saturating_sub(unspent_weight); } // let's now deal with relayer payments @@ -450,7 +447,7 @@ pub mod pallet { /// Messages have been received from the bridged chain. MessagesReceived( /// Result of received messages dispatch. - Vec::DispatchLevelResult>>, + ReceivedMessages<::DispatchLevelResult>, ), /// Messages in the inclusive range have been delivered to the bridged chain. MessagesDelivered { @@ -788,18 +785,13 @@ fn verify_and_decode_messages_proof, I: 'static>( // `receive_messages_proof` weight formula and `MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` // check guarantees that the `message_count` is sane and Vec may be allocated. // (tx with too many messages will either be rejected from the pool, or will fail earlier) - proofs::verify_messages_proof::(proof, messages_count).map(|messages_by_lane| { - messages_by_lane - .into_iter() - .map(|(lane, lane_data)| { - ( - lane, - ProvedLaneMessages { - lane_state: lane_data.lane_state, - messages: lane_data.messages.into_iter().map(Into::into).collect(), - }, - ) - }) - .collect() + proofs::verify_messages_proof::(proof, messages_count).map(|(lane, lane_data)| { + ( + lane, + ProvedLaneMessages { + lane_state: lane_data.lane_state, + messages: lane_data.messages.into_iter().map(Into::into).collect(), + }, + ) }) } diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index 0016d67b87aa..f35eb24d98c5 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -98,11 +98,7 @@ pub fn verify_messages_proof, I: 'static>( // Check that the storage proof doesn't have any untouched keys. parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?; - // We only support single lane messages in this generated_schema - let mut proved_messages = ProvedMessages::new(); - proved_messages.insert(lane, proved_lane_messages); - - Ok(proved_messages) + Ok((lane, proved_lane_messages)) } /// Verify proof of This -> Bridged chain messages delivery. @@ -493,7 +489,7 @@ mod tests { false, |proof| verify_messages_proof::(proof, 0), ), - Ok(vec![( + Ok(( test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { @@ -504,9 +500,7 @@ mod tests { }), messages: Vec::new(), }, - )] - .into_iter() - .collect()), + )), ); } @@ -527,7 +521,7 @@ mod tests { false, |proof| verify_messages_proof::(proof, 1), ), - Ok(vec![( + Ok(( test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { @@ -541,9 +535,7 @@ mod tests { payload: vec![42], }], }, - )] - .into_iter() - .collect()), + )) ); } diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index 74fecb9d9f0d..b351cef42afa 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -23,7 +23,7 @@ use codec::{Decode, Encode, Error as CodecError}; use frame_support::weights::Weight; use scale_info::TypeInfo; use sp_core::RuntimeDebug; -use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, prelude::*}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; /// Messages proof from bridged chain. /// @@ -59,7 +59,7 @@ impl Size for FromBridgedChainMessagesProof = BTreeMap>; +pub type ProvedMessages = (LaneId, ProvedLaneMessages); /// Proved messages from single lane of the source chain. #[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] From 71ee52b08354fe2dfe3f0e1d1c3e0a1f4ed902b8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 13 Jul 2023 17:57:56 +0300 Subject: [PATCH 12/95] introduce partial bp-xcm-bridge-hub - just LocalXcmChannelManager (#2265) --- Cargo.lock | 1 + bridges/primitives/xcm-bridge-hub/Cargo.toml | 8 ++- bridges/primitives/xcm-bridge-hub/src/lib.rs | 57 +++++++++++++++++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f775a1cd48d3..e2cd4d7bf638 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2008,6 +2008,7 @@ name = "bp-xcm-bridge-hub" version = "0.2.0" dependencies = [ "sp-std 14.0.0", + "staging-xcm", ] [[package]] diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 932e9ade0197..b990a232bff1 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -15,6 +15,12 @@ workspace = true # Substrate Dependencies sp-std = { workspace = true } +# Polkadot Dependencies +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } + [features] default = ["std"] -std = ["sp-std/std"] +std = [ + "sp-std/std", + "xcm/std", +] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 9745011c902d..78f913273370 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -16,9 +16,64 @@ //! Primitives of the xcm-bridge-hub pallet. -#![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +use xcm::latest::prelude::*; + /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; + +/// A manager of XCM communication channels between the bridge hub and parent/sibling chains +/// that have opened bridges at this bridge hub. +/// +/// We use this interface to suspend and resume channels programmatically to implement backpressure +/// mechanism for bridge queues. +#[allow(clippy::result_unit_err)] // XCM uses `Result<(), ()>` everywhere +pub trait LocalXcmChannelManager { + // TODO: https://github.com/paritytech/parity-bridges-common/issues/2255 + // check following assumptions. They are important at least for following cases: + // 1) we now close the associated outbound lane when misbehavior is reported. If we'll keep + // handling inbound XCM messages after the `suspend_inbound_channel`, they will be dropped + // 2) the sender will be able to enqueue message to othe lanes if we won't stop handling inbound + // XCM immediately. He even may open additional bridges + + /// Stop handling new incoming XCM messages from given bridge `owner` (parent/sibling chain). + /// + /// We assume that the channel will be suspended immediately, but we don't mind if inbound + /// messages will keep piling up here for some time. Once this is communicated to the + /// `owner` chain (in any form), we expect it to stop sending messages to us and queue + /// messages at that `owner` chain instead. + /// + /// This method will be called if we detect a misbehavior in one of bridges, owned by + /// the `owner`. We expect that: + /// + /// - no more incoming XCM messages from the `owner` will be processed until further + /// `resume_inbound_channel` call; + /// + /// - soon after the call, the channel will switch to the state when incoming messages are + /// piling up at the sending chain, not at the bridge hub. + /// + /// This method shall not fail if the channel is already suspended. + fn suspend_inbound_channel(owner: Location) -> Result<(), ()>; + + /// Start handling incoming messages from from given bridge `owner` (parent/sibling chain) + /// again. + /// + /// This method is called when the `owner` tries to resume bridge operations after + /// resolving "misbehavior" issues. The channel is assumed to be suspended by the previous + /// `suspend_inbound_channel` call, however we don't check it anywhere. + /// + /// This method shall not fail if the channel is already resumed. + fn resume_inbound_channel(owner: Location) -> Result<(), ()>; +} + +impl LocalXcmChannelManager for () { + fn suspend_inbound_channel(_owner: Location) -> Result<(), ()> { + Ok(()) + } + + fn resume_inbound_channel(_owner: Location) -> Result<(), ()> { + Err(()) + } +} From dcbe134b08d14c18294dc398234c178e47469c55 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 17 Jul 2023 12:50:38 +0300 Subject: [PATCH 13/95] XCM bridge hub pallet (will be deployed at bridge hubs) (#2213) * XCM over bridge pallet (won't ever be merged to this repo): initial commit * try both bridge-id and lane-id * flush * flush * flush * flush * first prototype * started working on xcm-over-bridge tests * proper open_bridge_works test * more open_bridge tests * request_bridge_closure tests * tests for close_bridge * report_misbehavior tests * renaming xcm-over-bridge ad xcm-bridge-hub: we'll have two similar pallets for dynamic lanes/fees support. One will be deployed at the bridge hub (xcm-bridge-hub) and another one (xcm-bridge-hub-router) at sibling/parent chains to send messages to remote network over the bridge hub * added couple of TODOs * moved BridgeQueuesState here + TODO for implementing report_bridge_queues_state + fmt * fixing TODOs * fixing TODOs * moved bridge locations to primitives * added a couple of TODOs * ref issue from TODO * clippy and spelling * fix tests * another TODOs * typo * LaneState -> force_close_bridge * start_closing_the_bridge -> start_closing_bridge * removed Closing bridge state, so now we only have the Opened -> optional temporary Closed state -> None * spelling * started prototyping suspend+resume on misbehavior * continue prototyping * more tests for open_bridge * more tests for close_bridge * more tests for report_misbehavior * started tests for resume_misbehaving_bridges * implemented tests for resume_misbehaving_bridges * remove UnsuspendedChannelWithMisbehavingOwner because now, when all bridges are resumed at once + we assume that the inbound XCM channel is suspended immediately it is no longer actual * added TODO * add comment re misbehavior reporter if he's associated with the bridge owner * ignored clippy * fmt * use versioned XCM structs in public interfaces and storage + Box XCM locations where possible * spelling * removed TODO in favor of https://github.com/paritytech/parity-bridges-common/pull/2257 * LocalChannelManager -> LocalXcmChannelManager * removed code specific to #2233, because it isn't the only option now * removemisbehavior mentions * also temporary (?) remove BridgesByLocalOrigin because the storage format will likely change to be able to resume bridges from the on_iniitalize/on_idle * AllowedOpenBridgeOrigin -> OpenBridgeOrigin * - TooManyBridgesForLocalOrigin * use bridge_destination_relative_location in args * better impl of strip_low_level_junctions * get rid of xcm_into_latest * clippy * added #![warn(missing_docs)] to new crates --- Cargo.lock | 6 + bridges/modules/xcm-bridge-hub/Cargo.toml | 7 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 929 ++++++++++++++++++- bridges/modules/xcm-bridge-hub/src/mock.rs | 111 ++- bridges/primitives/header-chain/src/lib.rs | 13 - bridges/primitives/messages/src/lib.rs | 6 +- bridges/primitives/xcm-bridge-hub/Cargo.toml | 14 +- bridges/primitives/xcm-bridge-hub/src/lib.rs | 433 ++++++++- 8 files changed, 1470 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2cd4d7bf638..2495b787e0af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2007,6 +2007,11 @@ dependencies = [ name = "bp-xcm-bridge-hub" version = "0.2.0" dependencies = [ + "bp-messages", + "bp-runtime", + "frame-support", + "parity-scale-codec", + "scale-info", "sp-std 14.0.0", "staging-xcm", ] @@ -12000,6 +12005,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-xcm-bridge-hub-router", "parity-scale-codec", + "polkadot-parachain-primitives", "scale-info", "sp-core", "sp-io", diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 8fbf61a0a535..2cb8d89722e7 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -35,11 +35,12 @@ xcm-builder = { workspace = true } xcm-executor = { workspace = true } [dev-dependencies] -bp-header-chain = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } +bp-header-chain = { workspace = true } +pallet-balances = { workspace = true } +sp-io = { workspace = true } bp-runtime = { features = ["test-helpers"], workspace = true } pallet-xcm-bridge-hub-router = { workspace = true } +polkadot-parachain-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 60b988497fc5..af3709b5a252 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -14,19 +14,61 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Module that adds XCM support to bridge pallets. +//! Module that adds XCM support to bridge pallets. The pallet allows to dynamically +//! open and close bridges between local (to this pallet location) and remote XCM +//! destinations. +//! +//! Every bridge between two XCM locations has a dedicated lane in associated +//! messages pallet. Assuming that this pallet is deployed at the bridge hub +//! parachain and there's a similar pallet at the bridged network, the dynamic +//! bridge lifetime is as follows: +//! +//! 1) the sibling parachain opens a XCMP channel with this bridge hub; +//! +//! 2) the sibling parachain funds its sovereign parachain account at this bridge hub. It shall hold +//! enough funds to pay for the bridge (see `BridgeReserve`); +//! +//! 3) the sibling parachain opens the bridge by sending XCM `Transact` instruction with the +//! `open_bridge` call. The `BridgeReserve` amount is reserved on the sovereign account of +//! sibling parachain; +//! +//! 4) at the other side of the bridge, the same thing (1, 2, 3) happens. Parachains that need to +//! connect over the bridge need to coordinate the moment when they start sending messages over +//! the bridge. Otherwise they may lose messages and/or bundled assets; +//! +//! 5) when either side wants to close the bridge, it sends the XCM `Transact` with the +//! `close_bridge` call. The bridge is closed immediately if there are no queued messages. +//! Otherwise, the owner must repeat the `close_bridge` call to prune all queued messages first. +//! +//! The pallet doesn't provide any mechanism for graceful closure, because it always involves +//! some contract between two connected chains and the bridge hub knows nothing about that. It +//! is the task for the connected chains to make sure that all required actions are completed +//! before the closure. In the end, the bridge hub can't even guarantee that all messages that +//! are delivered to the destination, are processed in the way their sender expects. So if we +//! can't guarantee that, we shall not care about more complex procedures and leave it to the +//! participating parties. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler; -use pallet_bridge_messages::Config as BridgeMessagesConfig; -use xcm::prelude::*; pub use exporter::PalletAsHaulBlobExporter; pub use pallet::*; mod exporter; +use bp_messages::{LaneId, LaneState, MessageNonce}; +use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; +use bp_xcm_bridge_hub::{ + bridge_locations, Bridge, BridgeLocations, BridgeLocationsError, BridgeState, +}; +use frame_support::traits::{Currency, ReservableCurrency}; +use frame_system::Config as SystemConfig; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; +use sp_runtime::traits::Zero; +use xcm::prelude::*; +use xcm_executor::traits::ConvertLocation; + mod mock; /// The target that will be used when publishing logs related to this pallet. @@ -37,13 +79,17 @@ pub mod pallet { use super::*; use bridge_runtime_common::messages_xcm_extension::SenderAndLane; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::BlockNumberFor; + use frame_system::pallet_prelude::{BlockNumberFor, *}; #[pallet::config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: BridgeMessagesConfig { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + /// Runtime's universal location. type UniversalLocation: Get; // TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and @@ -67,8 +113,36 @@ pub mod pallet { /// Support for point-to-point links /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) type LanesSupport: XcmBlobHauler; + + /// A set of XCM locations within local consensus system that are allowed to open + /// bridges with remote destinations. + // TODO: there's only one impl of `EnsureOrigin` - + // `EnsureXcmOrigin`, but it doesn't do what we need. Is there some other way to check + // `Origin` and get matching `Location`??? + type OpenBridgeOrigin: EnsureOrigin< + ::RuntimeOrigin, + Success = Location, + >; + /// A converter between a multi-location and a sovereign account. + type BridgeOriginAccountIdConverter: ConvertLocation; + + /// Amount of this chain native tokens that is reserved on the sibling parachain account + /// when bridge open request is registered. + #[pallet::constant] + type BridgeReserve: Get>>; + /// Currency used to pay for bridge registration. + type NativeCurrency: ReservableCurrency; } + /// An alias for the bridge metadata. + pub type BridgeOf = Bridge>; + /// An alias for the this chain. + pub type ThisChainOf = + pallet_bridge_messages::ThisChainOf>::BridgeMessagesPalletInstance>; + /// An alias for the associated lanes manager. + pub type LanesManagerOf = + pallet_bridge_messages::LanesManager>::BridgeMessagesPalletInstance>; + #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); @@ -76,13 +150,311 @@ pub mod pallet { impl, I: 'static> Hooks> for Pallet { fn integrity_test() { assert!( - Self::bridged_network_id().is_some(), - "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", - T::BridgedNetwork::get() + Self::bridged_network_id().is_ok(), + "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", + T::BridgedNetwork::get() + ) + } + } + + #[pallet::call] + impl, I: 'static> Pallet + where + T: frame_system::Config>>, + T::NativeCurrency: Currency>>, + { + /// Open a bridge between two locations. + /// + /// The caller must be within the `T::OpenBridgeOrigin` filter (presumably: a sibling + /// parachain or a parent relay chain). The `bridge_destination_universal_location` must be + /// a destination within the consensus of the `T::BridgedNetwork` network. + /// + /// The `BridgeReserve` amount is reserved on the caller account. This reserve + /// is unreserved after bridge is closed. + /// + /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane + /// is `Opened`. + #[pallet::call_index(0)] + #[pallet::weight(Weight::zero())] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - weights + pub fn open_bridge( + origin: OriginFor, + bridge_destination_universal_location: Box, + ) -> DispatchResult { + // check and compute required bridge locations + let locations = + Self::bridge_locations(origin, bridge_destination_universal_location.clone())?; + + // reserve balance on the parachain sovereign account + let reserve = T::BridgeReserve::get(); + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + &locations.bridge_origin_relative_location, + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; + T::NativeCurrency::reserve(&bridge_owner_account, reserve) + .map_err(|_| Error::::FailedToReserveBridgeReserve)?; + + // save bridge metadata + Bridges::::try_mutate(locations.lane_id, |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(BridgeOf:: { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location.clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + reserve, + }); + Ok(()) + }, + })?; + + // create new lanes. Under normal circumstances, following calls shall never fail + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .create_inbound_lane(locations.lane_id) + .map_err(Error::::LanesManager)?; + lanes_manager + .create_outbound_lane(locations.lane_id) + .map_err(Error::::LanesManager)?; + + // write something to log + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} has been opened", + locations.lane_id, + locations.bridge_origin_universal_location, + locations.bridge_destination_universal_location, + ); + + // deposit `BridgeOpened` event + Self::deposit_event(Event::::BridgeOpened { + lane_id: locations.lane_id, + local_endpoint: Box::new(locations.bridge_origin_universal_location), + remote_endpoint: Box::new(locations.bridge_destination_universal_location), + }); + + Ok(()) + } + + /// Try to close the bridge. + /// + /// Can only be called by the "owner" of this side of the bridge, meaning that the + /// inbound XCM channel with the local origin chain is working. + /// + /// Closed bridge is a bridge without any traces in the runtime storage. So this method + /// first tries to prune all queued messages at the outbound lane. When there are no + /// outbound messages left, outbound and inbound lanes are purged. After that, funds + /// are returned back to the owner of this side of the bridge. + /// + /// The number of messages that we may prune in a single call is limited by the + /// `may_prune_messages` argument. If there are more messages in the queue, the method + /// prunes exactly `may_prune_messages` and exits early. The caller may call it again + /// until outbound queue is depleted and get his funds back. + /// + /// The states after this call: everything is either `Closed`, or purged from the + /// runtime storage. + #[pallet::call_index(1)] + #[pallet::weight(Weight::zero())] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - weights + pub fn close_bridge( + origin: OriginFor, + bridge_destination_universal_location: Box, + may_prune_messages: MessageNonce, + ) -> DispatchResult { + // compute required bridge locations + let locations = Self::bridge_locations(origin, bridge_destination_universal_location)?; + + // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - may do refund here, if + // bridge/lanes are already closed + for messages that are not pruned + + // update bridge metadata - this also guarantees that the bridge is in the proper state + let bridge = + Bridges::::try_mutate_exists(locations.lane_id, |bridge| match bridge { + Some(bridge) => { + bridge.state = BridgeState::Closed; + Ok(bridge.clone()) + }, + None => Err(Error::::UnknownBridge), + })?; + + // close inbound and outbound lanes + let lanes_manager = LanesManagerOf::::new(); + let mut inbound_lane = lanes_manager + .any_state_inbound_lane(locations.lane_id) + .map_err(Error::::LanesManager)?; + let mut outbound_lane = lanes_manager + .any_state_outbound_lane(locations.lane_id) + .map_err(Error::::LanesManager)?; + + // now prune queued messages + let mut pruned_messages = 0; + for _ in outbound_lane.queued_messages() { + if pruned_messages == may_prune_messages { + break + } + + outbound_lane.remove_oldest_unpruned_message(); + pruned_messages += 1; + } + + // if there are outbound messages in the queue, just update states and early exit + if !outbound_lane.queued_messages().is_empty() { + // update lanes state. Under normal circumstances, following calls shall never fail + inbound_lane.set_state(LaneState::Closed); + outbound_lane.set_state(LaneState::Closed); + + // write something to log + let enqueued_messages = outbound_lane.queued_messages().checked_len().unwrap_or(0); + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} is closing. {} messages remaining", + locations.lane_id, + locations.bridge_origin_universal_location, + locations.bridge_destination_universal_location, + enqueued_messages, + ); + + // deposit the `ClosingBridge` event + Self::deposit_event(Event::::ClosingBridge { + lane_id: locations.lane_id, + pruned_messages, + enqueued_messages, + }); + + return Ok(()) + } + + // else we have pruned all messages, so lanes and the bridge itself may gone + inbound_lane.purge(); + outbound_lane.purge(); + Bridges::::remove(locations.lane_id); + + // unreserve remaining amount + let failed_to_unreserve = + T::NativeCurrency::unreserve(&bridge.bridge_owner_account, bridge.reserve); + if !failed_to_unreserve.is_zero() { + // we can't do anything here - looks like funds have been (partially) unreserved + // before by someone else. Let's not fail, though - it'll be worse for the caller + log::trace!( + target: LOG_TARGET, + "Failed to unreserve {:?} during ridge {:?} closure", + failed_to_unreserve, + locations.lane_id, + ); + } + + // write something to log + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} has been closed", + locations.lane_id, + locations.bridge_origin_universal_location, + locations.bridge_destination_universal_location, + ); + + // deposit the `BridgePruned` event + Self::deposit_event(Event::::BridgePruned { + lane_id: locations.lane_id, + pruned_messages, + }); + + Ok(()) + } + } + + impl, I: 'static> Pallet + where + T: frame_system::Config>>, + T::NativeCurrency: Currency>>, + { + /// Return bridge endpoint locations and dedicated lane identifier. + pub fn bridge_locations( + origin: OriginFor, + bridge_destination_universal_location: Box, + ) -> Result, sp_runtime::DispatchError> { + bridge_locations( + Box::new(T::UniversalLocation::get()), + Box::new(T::OpenBridgeOrigin::ensure_origin(origin)?), + Box::new( + (*bridge_destination_universal_location) + .try_into() + .map_err(|_| Error::::UnsupportedXcmVersion)?, + ), + Self::bridged_network_id()?, ) + .map_err(|e| Error::::BridgeLocations(e).into()) } } + impl, I: 'static> Pallet { + /// Returns some `NetworkId` if contains `GlobalConsensus` junction. + fn bridged_network_id() -> Result { + match T::BridgedNetwork::get().take_first_interior() { + Some(GlobalConsensus(network)) => Ok(network), + _ => Err(Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeDestination, + ) + .into()), + } + } + } + + /// All registered bridges. + #[pallet::storage] + pub type Bridges, I: 'static = ()> = + StorageMap<_, Identity, LaneId, BridgeOf>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// The bridge between two locations has been opened. + BridgeOpened { + /// Universal location of local bridge endpoint. + local_endpoint: Box, + /// Universal location of remote bridge endpoint. + remote_endpoint: Box, + /// Bridge and its lane identifier. + lane_id: LaneId, + }, + /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. + ClosingBridge { + /// Bridge and its lane identifier. + lane_id: LaneId, + /// Number of pruned messages during the close call. + pruned_messages: MessageNonce, + /// Number of enqueued messages that need to be pruned in follow up calls. + enqueued_messages: MessageNonce, + }, + /// Bridge has been closed and pruned from the runtime storage. It now may be reopened + /// again by any participant. + BridgePruned { + /// Bridge and its lane identifier. + lane_id: LaneId, + /// Number of pruned messages during the close call. + pruned_messages: MessageNonce, + }, + } + + #[pallet::error] + pub enum Error { + /// Bridge locations error. + BridgeLocations(BridgeLocationsError), + /// Invalid local bridge origin account. + InvalidBridgeOriginAccount, + /// The bridge is already registered in this pallet. + BridgeAlreadyExists, + /// Trying to close already closed bridge. + BridgeAlreadyClosed, + /// Lanes manager error. + LanesManager(LanesManagerError), + /// Trying to access unknown bridge. + UnknownBridge, + /// The bridge origin can't pay the required amount for opening the bridge. + FailedToReserveBridgeReserve, + /// The version of XCM location argument is unsupported. + UnsupportedXcmVersion, + } + impl, I: 'static> Pallet { /// Returns dedicated/configured lane identifier. pub(crate) fn lane_for( @@ -97,7 +469,7 @@ pub mod pallet { .find_map(|(lane_source, (lane_dest_network, lane_dest))| { if lane_source.location == source && &lane_dest_network == dest.0 && - Self::bridged_network_id().as_ref() == Some(dest.0) && + Self::bridged_network_id().as_ref() == Ok(dest.0) && &lane_dest == dest.1 { Some(lane_source) @@ -106,13 +478,542 @@ pub mod pallet { } }) } + } +} - /// Returns some `NetworkId` if contains `GlobalConsensus` junction. - fn bridged_network_id() -> Option { - match T::BridgedNetwork::get().take_first_interior() { - Some(GlobalConsensus(network)) => Some(network), - _ => None, +#[cfg(test)] +mod tests { + use super::*; + use mock::*; + + use frame_support::{assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; + use frame_system::{EventRecord, Phase}; + + fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId { + let bridge_owner_account = + LocationToAccountId::convert_location(&locations.bridge_origin_relative_location) + .unwrap(); + Balances::mint_into(&bridge_owner_account, balance).unwrap(); + bridge_owner_account + } + + fn mock_open_bridge_from_with( + origin: RuntimeOrigin, + with: InteriorLocation, + ) -> (BridgeOf, BridgeLocations) { + let reserve = BridgeDeposit::get(); + let locations = XcmOverBridge::bridge_locations(origin, Box::new(with.into())).unwrap(); + let bridge_owner_account = + fund_origin_sovereign_account(&locations, reserve + ExistentialDeposit::get()); + Balances::reserve(&bridge_owner_account, reserve).unwrap(); + + let bridge = Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location.clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + reserve, + }; + Bridges::::insert(locations.lane_id, bridge.clone()); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_inbound_lane(locations.lane_id).unwrap(); + lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + + (bridge, *locations) + } + + fn mock_open_bridge_from( + origin: RuntimeOrigin, + ) -> (BridgeOf, BridgeLocations) { + mock_open_bridge_from_with(origin, bridged_asset_hub_location()) + } + + fn enqueue_message(lane: LaneId) { + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .active_outbound_lane(lane) + .unwrap() + .send_message(BoundedVec::try_from(vec![42]).expect("We craft valid messages")); + } + + #[test] + fn open_bridge_fails_if_origin_is_not_allowed() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::disallowed_origin(), + Box::new(bridged_asset_hub_location().into()), + ), + sp_runtime::DispatchError::BadOrigin, + ); + }) + } + + #[test] + fn open_bridge_fails_if_origin_is_not_relative() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_universal_origin(), + Box::new(bridged_asset_hub_location().into()), + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::sibling_parachain_universal_origin(), + Box::new(bridged_asset_hub_location().into()), + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + }) + } + + #[test] + fn open_bridge_fails_if_destination_is_not_remote() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_origin(), + Box::new( + [GlobalConsensus(RelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)] + .into() + ), + ), + Error::::BridgeLocations(BridgeLocationsError::DestinationIsLocal), + ); + }); + } + + #[test] + fn open_bridge_fails_if_outside_of_bridged_consensus() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_origin(), + Box::new( + [ + GlobalConsensus(NonBridgedRelayNetwork::get()), + Parachain(BRIDGED_ASSET_HUB_ID) + ] + .into() + ), + ), + Error::::BridgeLocations( + BridgeLocationsError::UnreachableDestination + ), + ); + }); + } + + #[test] + fn open_bridge_fails_if_origin_has_no_sovereign_account() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::origin_without_sovereign_account(), + Box::new(bridged_asset_hub_location().into()), + ), + Error::::InvalidBridgeOriginAccount, + ); + }); + } + + #[test] + fn open_bridge_fails_if_origin_sovereign_account_has_no_enough_funds() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_origin(), + Box::new(bridged_asset_hub_location().into()), + ), + Error::::FailedToReserveBridgeReserve, + ); + }); + } + + #[test] + fn open_bridge_fails_if_it_already_exists() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let locations = XcmOverBridge::bridge_locations( + origin.clone(), + Box::new(bridged_asset_hub_location().into()), + ) + .unwrap(); + fund_origin_sovereign_account( + &locations, + BridgeDeposit::get() + ExistentialDeposit::get(), + ); + + Bridges::::insert( + locations.lane_id, + Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location.into(), + ), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + reserve: 0, + }, + ); + + assert_noop!( + XcmOverBridge::open_bridge(origin, Box::new(bridged_asset_hub_location().into()),), + Error::::BridgeAlreadyExists, + ); + }) + } + + #[test] + fn open_bridge_fails_if_its_lanes_already_exists() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let locations = XcmOverBridge::bridge_locations( + origin.clone(), + Box::new(bridged_asset_hub_location().into()), + ) + .unwrap(); + fund_origin_sovereign_account( + &locations, + BridgeDeposit::get() + ExistentialDeposit::get(), + ); + + let lanes_manager = LanesManagerOf::::new(); + + lanes_manager.create_inbound_lane(locations.lane_id).unwrap(); + assert_noop!( + XcmOverBridge::open_bridge( + origin.clone(), + Box::new(bridged_asset_hub_location().into()), + ), + Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), + ); + + lanes_manager.active_inbound_lane(locations.lane_id).unwrap().purge(); + lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + assert_noop!( + XcmOverBridge::open_bridge(origin, Box::new(bridged_asset_hub_location().into()),), + Error::::LanesManager( + LanesManagerError::OutboundLaneAlreadyExists + ), + ); + }) + } + + #[test] + fn open_bridge_works() { + run_test(|| { + // in our test runtime, we expect that bridge may be opened by parent relay chain + // and any sibling parachain + let origins = [ + OpenBridgeOrigin::parent_relay_chain_origin(), + OpenBridgeOrigin::sibling_parachain_origin(), + ]; + + // check that every origin may open the bridge + let lanes_manager = LanesManagerOf::::new(); + let expected_reserve = BridgeDeposit::get(); + let existential_deposit = ExistentialDeposit::get(); + for origin in origins { + // reset events + System::set_block_number(1); + System::reset_events(); + + // compute all other locations + let locations = XcmOverBridge::bridge_locations( + origin.clone(), + Box::new(bridged_asset_hub_location().into()), + ) + .unwrap(); + + // ensure that there's no bridge and lanes in the storage + assert_eq!(Bridges::::get(locations.lane_id), None); + assert_eq!( + lanes_manager.active_inbound_lane(locations.lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(locations.lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + + // give enough funds to the sovereign account of the bridge origin + let bridge_owner_account = fund_origin_sovereign_account( + &locations, + expected_reserve + existential_deposit, + ); + assert_eq!( + Balances::free_balance(&bridge_owner_account), + expected_reserve + existential_deposit + ); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); + + // now open the bridge + assert_ok!(XcmOverBridge::open_bridge( + origin, + Box::new(locations.bridge_destination_universal_location.clone().into()), + )); + + // ensure that everything has been set up in the runtime storage + assert_eq!( + Bridges::::get(locations.lane_id), + Some(Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location.into() + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + reserve: expected_reserve, + }), + ); + assert_eq!( + lanes_manager.active_inbound_lane(locations.lane_id).map(|l| l.state()), + Ok(LaneState::Opened) + ); + assert_eq!( + lanes_manager.active_outbound_lane(locations.lane_id).map(|l| l.state()), + Ok(LaneState::Opened) + ); + assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_reserve); + + // ensure that the proper event is deposited + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { + lane_id: locations.lane_id, + local_endpoint: Box::new(locations.bridge_origin_universal_location), + remote_endpoint: Box::new( + locations.bridge_destination_universal_location + ), + }), + topics: vec![], + }), + ); } - } + }); + } + + #[test] + fn close_bridge_fails_if_origin_is_not_allowed() { + run_test(|| { + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::disallowed_origin(), + Box::new(bridged_asset_hub_location().into()), + 0, + ), + sp_runtime::DispatchError::BadOrigin, + ); + }) + } + + #[test] + fn close_bridge_fails_if_origin_is_not_relative() { + run_test(|| { + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::parent_relay_chain_universal_origin(), + Box::new(bridged_asset_hub_location().into()), + 0, + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::sibling_parachain_universal_origin(), + Box::new(bridged_asset_hub_location().into()), + 0, + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + }) + } + + #[test] + fn close_bridge_fails_if_its_lanes_are_unknown() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let (_, locations) = mock_open_bridge_from(origin.clone()); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().purge(); + assert_noop!( + XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location.into()), + 0, + ), + Error::::LanesManager(LanesManagerError::UnknownInboundLane), + ); + lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().purge(); + + let (_, locations) = mock_open_bridge_from(origin.clone()); + lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().purge(); + assert_noop!( + XcmOverBridge::close_bridge( + origin, + Box::new(locations.bridge_destination_universal_location.into()), + 0, + ), + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), + ); + }); + } + + #[test] + fn close_bridge_works() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let (bridge, locations) = mock_open_bridge_from(origin.clone()); + System::set_block_number(1); + + // remember owner balances + let free_balance = Balances::free_balance(&bridge.bridge_owner_account); + let reserved_balance = Balances::reserved_balance(&bridge.bridge_owner_account); + + // enqueue some messages + for _ in 0..32 { + enqueue_message(locations.lane_id); + } + + // now call the `close_bridge`, which will only partially prune messages + assert_ok!(XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location.clone().into()), + 16, + ),); + + // as a result, the bridge and lanes are switched to the `Closed` state, some messages + // are pruned, but funds are not unreserved + let lanes_manager = LanesManagerOf::::new(); + assert_eq!( + Bridges::::get(locations.lane_id).map(|b| b.state), + Some(BridgeState::Closed) + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager + .any_state_outbound_lane(locations.lane_id) + .unwrap() + .queued_messages() + .checked_len(), + Some(16) + ); + assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { + lane_id: locations.lane_id, + pruned_messages: 16, + enqueued_messages: 16, + }), + topics: vec![], + }), + ); + + // now call the `close_bridge` again, which will only partially prune messages + assert_ok!(XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location.clone().into()), + 8, + ),); + + // nothing is changed (apart from the pruned messages) + assert_eq!( + Bridges::::get(locations.lane_id).map(|b| b.state), + Some(BridgeState::Closed) + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager + .any_state_outbound_lane(locations.lane_id) + .unwrap() + .queued_messages() + .checked_len(), + Some(8) + ); + assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { + lane_id: locations.lane_id, + pruned_messages: 8, + enqueued_messages: 8, + }), + topics: vec![], + }), + ); + + // now call the `close_bridge` again that will prune all remaining messages and the + // bridge + assert_ok!(XcmOverBridge::close_bridge( + origin, + Box::new(locations.bridge_destination_universal_location.into()), + 9, + ),); + + // there's no traces of bridge in the runtime storage and funds are unreserved + assert_eq!(Bridges::::get(locations.lane_id).map(|b| b.state), None); + assert_eq!( + lanes_manager.any_state_inbound_lane(locations.lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(locations.lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + assert_eq!( + Balances::free_balance(&bridge.bridge_owner_account), + free_balance + reserved_balance + ); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), 0); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { + lane_id: locations.lane_id, + pruned_messages: 8, + }), + topics: vec![], + }), + ); + }); } } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 2306174f63fe..673a5790ec08 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -47,6 +47,10 @@ use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u64; +use frame_support::traits::{EnsureOrigin, OriginTrait}; +use polkadot_parachain_primitives::primitives::Sibling; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; + type Block = frame_system::mocking::MockBlock; pub const SIBLING_ASSET_HUB_ID: u32 = 2001; @@ -63,7 +67,7 @@ frame_support::construct_runtime! { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, - XcmOverBridge: pallet_xcm_bridge_hub::{Pallet}, + XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, Event}, XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, } } @@ -178,6 +182,8 @@ parameter_types! { } impl pallet_xcm_bridge_hub::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = BridgedRelayNetworkLocation; type BridgeMessagesPalletInstance = (); @@ -187,6 +193,12 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type Lanes = TestLanes; type LanesSupport = TestXcmBlobHauler; + + type OpenBridgeOrigin = OpenBridgeOrigin; + type BridgeOriginAccountIdConverter = LocationToAccountId; + + type BridgeReserve = BridgeDeposit; + type NativeCurrency = Balances; } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { @@ -309,10 +321,91 @@ impl XcmBlobHauler for TestXcmBlobHauler { type UncongestedMessage = (); } +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the parent `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, +); + +pub struct OpenBridgeOrigin; + +impl OpenBridgeOrigin { + pub fn parent_relay_chain_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([0u8; 32].into()) + } + + pub fn parent_relay_chain_universal_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([1u8; 32].into()) + } + + pub fn sibling_parachain_origin() -> RuntimeOrigin { + let mut account = [0u8; 32]; + account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); + RuntimeOrigin::signed(account.into()) + } + + pub fn sibling_parachain_universal_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([2u8; 32].into()) + } + + pub fn origin_without_sovereign_account() -> RuntimeOrigin { + RuntimeOrigin::signed([3u8; 32].into()) + } + + pub fn disallowed_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([42u8; 32].into()) + } +} + +impl EnsureOrigin for OpenBridgeOrigin { + type Success = Location; + + fn try_origin(o: RuntimeOrigin) -> Result { + let signer = o.clone().into_signer(); + if signer == Self::parent_relay_chain_origin().into_signer() { + return Ok(Location { parents: 1, interior: Here }) + } else if signer == Self::parent_relay_chain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: GlobalConsensus(RelayNetwork::get()).into(), + }) + } else if signer == Self::sibling_parachain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)] + .into(), + }) + } else if signer == Self::origin_without_sovereign_account().into_signer() { + return Ok(Location { + parents: 1, + interior: [Parachain(SIBLING_ASSET_HUB_ID), OnlyChild].into(), + }) + } + + let mut sibling_account = [0u8; 32]; + sibling_account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); + if signer == Some(sibling_account.into()) { + return Ok(Location { parents: 1, interior: Parachain(SIBLING_ASSET_HUB_ID).into() }) + } + + Err(o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(Self::parent_relay_chain_origin()) + } +} + pub struct ThisUnderlyingChain; impl Chain for ThisUnderlyingChain { const ID: ChainId = *b"tuch"; + type BlockNumber = u64; type Hash = H256; type Hasher = BlakeTwo256; @@ -334,16 +427,15 @@ impl Chain for ThisUnderlyingChain { } impl ChainWithMessages for ThisUnderlyingChain { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; - + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithThisChainBridgeMessages"; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; } -pub struct BridgedUnderlyingChain; pub type BridgedHeaderHash = H256; pub type BridgedChainHeader = SubstrateHeader; +pub struct BridgedUnderlyingChain; impl Chain for BridgedUnderlyingChain { const ID: ChainId = *b"bgdc"; type BlockNumber = u64; @@ -367,9 +459,9 @@ impl Chain for BridgedUnderlyingChain { } impl ChainWithMessages for BridgedUnderlyingChain { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithBridgedChainBridgeMessages"; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; } /// Test message dispatcher. @@ -409,6 +501,11 @@ impl bp_header_chain::HeaderChain for BridgedHeaderChain } } +/// Location of bridged asset hub. +pub fn bridged_asset_hub_location() -> InteriorLocation { + [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into() +} + /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { sp_io::TestExternalities::new( diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 509e2d062704..26295dee1801 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -90,19 +90,6 @@ pub trait HeaderChain { } } -impl HeaderChain for () { - fn finalized_header_state_root(_header_hash: HashOf) -> Option> { - None - } - - fn verify_storage_proof( - _header_hash: HashOf, - _db: UnverifiedStorageProof, - ) -> Result { - Err(HeaderChainError::UnknownHeader) - } -} - /// A type that can be used as a parameter in a dispatchable function. /// /// When using `decl_module` all arguments for call functions must implement this trait. diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 540b6a37d794..b6d8660c08d2 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -254,10 +254,6 @@ impl TypeId for LaneId { pub enum LaneState { /// Lane is opened and messages may be sent/received over it. Opened, - /// Lane is closing. It is equal to the `Opened` state, but it will switch to - /// the `Closed` state and then vanish after some period. This state is here - /// to give bridged chain ability to know that the lane is going to be closed. - Closing, /// Lane is closed and all attempts to send/receive messages to/from this lane /// will fail. /// @@ -271,7 +267,7 @@ pub enum LaneState { impl LaneState { /// Returns true if lane state allows sending/receiving messages. pub fn is_active(&self) -> bool { - matches!(*self, LaneState::Opened | LaneState::Closing) + matches!(*self, LaneState::Opened) } } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index b990a232bff1..fa8f9ef0b76f 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -11,16 +11,28 @@ repository.workspace = true workspace = true [dependencies] +codec = { features = ["derive"], default-features = false, workspace = true } +scale-info = { features = ["derive"], workspace = true } + +# Bridge Dependencies +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } # Substrate Dependencies sp-std = { workspace = true } +frame-support = { workspace = true } # Polkadot Dependencies -xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm = { workspace = true } [features] default = ["std"] std = [ + "bp-messages/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "scale-info/std", "sp-std/std", "xcm/std", ] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 78f913273370..44dbb9698241 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -16,9 +16,19 @@ //! Primitives of the xcm-bridge-hub pallet. +#![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use xcm::latest::prelude::*; +use bp_messages::LaneId; +use bp_runtime::{AccountIdOf, BalanceOf, Chain}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + ensure, sp_runtime::RuntimeDebug, CloneNoBound, PalletError, PartialEqNoBound, + RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use sp_std::boxed::Box; +use xcm::{latest::prelude::*, VersionedLocation}; /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. @@ -45,8 +55,7 @@ pub trait LocalXcmChannelManager { /// `owner` chain (in any form), we expect it to stop sending messages to us and queue /// messages at that `owner` chain instead. /// - /// This method will be called if we detect a misbehavior in one of bridges, owned by - /// the `owner`. We expect that: + /// We expect that: /// /// - no more incoming XCM messages from the `owner` will be processed until further /// `resume_inbound_channel` call; @@ -60,9 +69,8 @@ pub trait LocalXcmChannelManager { /// Start handling incoming messages from from given bridge `owner` (parent/sibling chain) /// again. /// - /// This method is called when the `owner` tries to resume bridge operations after - /// resolving "misbehavior" issues. The channel is assumed to be suspended by the previous - /// `suspend_inbound_channel` call, however we don't check it anywhere. + /// The channel is assumed to be suspended by the previous `suspend_inbound_channel` call, + /// however we don't check it anywhere. /// /// This method shall not fail if the channel is already resumed. fn resume_inbound_channel(owner: Location) -> Result<(), ()>; @@ -77,3 +85,416 @@ impl LocalXcmChannelManager for () { Err(()) } } + +/// Bridge state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum BridgeState { + /// Bridge is opened. Associated lanes are also opened. + Opened, + /// Bridge is closed. Associated lanes are also closed. + /// After all outbound messages will be pruned, the bridge will vanish without any traces. + Closed, +} + +/// Bridge metadata. +#[derive( + CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(ThisChain))] +pub struct Bridge { + /// Relative location of the bridge origin chain. + pub bridge_origin_relative_location: Box, + /// Current bridge state. + pub state: BridgeState, + /// Account with the reserved funds. + pub bridge_owner_account: AccountIdOf, + /// Reserved amount on the sovereign account of the sibling bridge origin. + pub reserve: BalanceOf, +} + +/// Locations of bridge endpoints at both sides of the bridge. +#[derive(Clone, RuntimeDebug, PartialEq, Eq)] +pub struct BridgeLocations { + /// Relative (to this bridge hub) location of this side of the bridge. + pub bridge_origin_relative_location: Location, + /// Universal (unique) location of this side of the bridge. + pub bridge_origin_universal_location: InteriorLocation, + /// Universal (unique) location of other side of the bridge. + pub bridge_destination_universal_location: InteriorLocation, + /// An identifier of the dedicated bridge message lane. + pub lane_id: LaneId, +} + +/// Errors that may happen when we check bridge locations. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum BridgeLocationsError { + /// Origin or destination locations are not universal. + NonUniversalLocation, + /// Bridge origin location is not supported. + InvalidBridgeOrigin, + /// Bridge destination is not supported (in general). + InvalidBridgeDestination, + /// Destination location is within the same global consensus. + DestinationIsLocal, + /// Destination network is not the network we are bridged with. + UnreachableDestination, + /// Destination location is unsupported. We only support bridges with relay + /// chain or its parachains. + UnsupportedDestinationLocation, +} + +/// Given XCM locations, generate lane id and universal locations of bridge endpoints. +/// +/// The `here_universal_location` is the universal location of the bridge hub runtime. +/// +/// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`) +/// location of the bridge endpoint at this side of the bridge. It may be the parent relay +/// chain or the sibling parachain. All junctions below parachain level are dropped. +/// +/// The `bridge_destination_universal_location` is the universal location of the bridge +/// destination. It may be the parent relay or the sibling parachain of the **bridged** +/// bridge hub. All junctions below parachain level are dropped. +/// +/// Why we drop all junctions between parachain level - that's because the lane is a bridge +/// between two chains. All routing under this level happens when the message is delivered +/// to the bridge destination. So at bridge level we don't care about low level junctions. +/// +/// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location` +/// local consensus OR if `bridge_destination_universal_location` is not a universal location. +pub fn bridge_locations( + here_universal_location: Box, + bridge_origin_relative_location: Box, + bridge_destination_universal_location: Box, + expected_remote_network: NetworkId, +) -> Result, BridgeLocationsError> { + fn strip_low_level_junctions( + location: InteriorLocation, + ) -> Result { + let mut junctions = location.into_iter(); + + let global_consensus = junctions + .next() + .filter(|junction| matches!(junction, GlobalConsensus(_))) + .ok_or(BridgeLocationsError::NonUniversalLocation)?; + + // we only expect `Parachain` junction here. There are other junctions that + // may need to be supported (like `GeneralKey` and `OnlyChild`), but now we + // only support bridges with relay and parachans + // + // if there's something other than parachain, let's strip it + let maybe_parachain = junctions.next().filter(|junction| matches!(junction, Parachain(_))); + Ok(match maybe_parachain { + Some(parachain) => [global_consensus, parachain].into(), + None => [global_consensus].into(), + }) + } + + // ensure that the `here_universal_location` and `bridge_destination_universal_location` + // are universal locations within different consensus systems + let local_network = here_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + let remote_network = bridge_destination_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal); + ensure!( + remote_network == expected_remote_network, + BridgeLocationsError::UnreachableDestination + ); + + // get universal location of endpoint, located at this side of the bridge + let bridge_origin_universal_location = here_universal_location + .within_global(*bridge_origin_relative_location.clone()) + .map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?; + // strip low-level junctions within universal locations + let bridge_origin_universal_location = + strip_low_level_junctions(bridge_origin_universal_location)?; + let bridge_destination_universal_location = + strip_low_level_junctions(*bridge_destination_universal_location)?; + + // we know that the `bridge_destination_universal_location` starts from the + // `GlobalConsensus` and we know that the `bridge_origin_universal_location` + // is also within the `GlobalConsensus`. So we know that the lane id will be + // the same on both ends of the bridge + let lane_id = LaneId::new( + bridge_origin_universal_location.clone(), + bridge_destination_universal_location.clone(), + ); + + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location: *bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + lane_id, + })) +} + +#[cfg(test)] +mod tests { + use super::*; + + const LOCAL_NETWORK: NetworkId = Kusama; + const REMOTE_NETWORK: NetworkId = Polkadot; + const UNREACHABLE_NETWORK: NetworkId = Rococo; + const SIBLING_PARACHAIN: u32 = 1000; + const LOCAL_BRIDGE_HUB: u32 = 1001; + const REMOTE_PARACHAIN: u32 = 2000; + + struct SuccessfulTest { + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + + bridge_origin_universal_location: InteriorLocation, + bridge_destination_universal_location: InteriorLocation, + } + + fn run_successful_test(test: SuccessfulTest) -> BridgeLocations { + let locations = bridge_locations( + Box::new(test.here_universal_location), + Box::new(test.bridge_origin_relative_location.clone()), + Box::new(test.bridge_destination_universal_location.clone()), + REMOTE_NETWORK, + ); + assert_eq!( + locations, + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location: test.bridge_origin_relative_location.clone(), + bridge_origin_universal_location: test.bridge_origin_universal_location.clone(), + bridge_destination_universal_location: test + .bridge_destination_universal_location + .clone(), + lane_id: LaneId::new( + test.bridge_origin_universal_location, + test.bridge_destination_universal_location, + ), + })), + ); + + *locations.unwrap() + } + + // successful tests that with various origins and destinations + + #[test] + fn at_relay_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + } + + #[test] + fn at_relay_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + }); + } + + // successful tests that show that we are ignoring low-level junctions of bridge origins + + #[test] + fn low_level_junctions_at_bridge_origin_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [PalletInstance(0)].into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + + assert_eq!(locations1.lane_id, locations2.lane_id); + } + + #[test] + fn low_level_junctions_at_bridge_destination_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + }); + + assert_eq!(locations1.lane_id, locations2.lane_id); + } + + // negative tests + + #[test] + fn bridge_locations_fails_when_here_is_not_universal_location() { + assert_eq!( + bridge_locations( + Box::new([Parachain(1000)].into()), + Box::new(Here.into()), + Box::new([GlobalConsensus(REMOTE_NETWORK)].into()), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_not_universal_location() { + assert_eq!( + bridge_locations( + Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), + Box::new(Here.into()), + Box::new([OnlyChild].into()), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_local() { + assert_eq!( + bridge_locations( + Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), + Box::new(Here.into()), + Box::new([GlobalConsensus(LOCAL_NETWORK), OnlyChild].into()), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::DestinationIsLocal), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_unreachable() { + assert_eq!( + bridge_locations( + Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), + Box::new(Here.into()), + Box::new([GlobalConsensus(UNREACHABLE_NETWORK)].into()), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::UnreachableDestination), + ); + } +} From 23c04f335dcec28546656c0e624742a5e6652b09 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 20 Jul 2023 17:34:41 +0300 Subject: [PATCH 14/95] Implement ExportXcm and MessageDispatch for pallet-xcm-bridge-hub (#2285) * implement ExportXcm and MessageDispatch for pallet-xcm-bridge-hub * spelling --- Cargo.lock | 2 - bridges/modules/xcm-bridge-hub/Cargo.toml | 4 - .../modules/xcm-bridge-hub/src/dispatcher.rs | 107 +++++++++++ .../modules/xcm-bridge-hub/src/exporter.rs | 172 ++++++++++++------ bridges/modules/xcm-bridge-hub/src/lib.rs | 87 ++++----- bridges/modules/xcm-bridge-hub/src/mock.rs | 58 ++---- 6 files changed, 275 insertions(+), 155 deletions(-) create mode 100644 bridges/modules/xcm-bridge-hub/src/dispatcher.rs diff --git a/Cargo.lock b/Cargo.lock index 2495b787e0af..938daca729cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11993,11 +11993,9 @@ dependencies = [ name = "pallet-xcm-bridge-hub" version = "0.2.0" dependencies = [ - "bp-header-chain", "bp-messages", "bp-runtime", "bp-xcm-bridge-hub", - "bridge-runtime-common", "frame-support", "frame-system", "log", diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 2cb8d89722e7..e422b58f4fbd 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -20,7 +20,6 @@ bp-messages = { workspace = true } bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } pallet-bridge-messages = { workspace = true } -bridge-runtime-common = { workspace = true } # Substrate Dependencies frame-support = { workspace = true } @@ -35,7 +34,6 @@ xcm-builder = { workspace = true } xcm-executor = { workspace = true } [dev-dependencies] -bp-header-chain = { workspace = true } pallet-balances = { workspace = true } sp-io = { workspace = true } bp-runtime = { features = ["test-helpers"], workspace = true } @@ -48,7 +46,6 @@ std = [ "bp-messages/std", "bp-runtime/std", "bp-xcm-bridge-hub/std", - "bridge-runtime-common/std", "codec/std", "frame-support/std", "frame-system/std", @@ -64,7 +61,6 @@ std = [ "xcm/std", ] runtime-benchmarks = [ - "bridge-runtime-common/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs new file mode 100644 index 000000000000..432896c25ac5 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -0,0 +1,107 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! The code that allows to use the pallet (`pallet-xcm-bridge-hub`) as inbound +//! bridge messages dispatcher. Internally, it just forwards inbound blob to the +//! XCM-level blob dispatcher, which pushes message to some other queue (e.g. +//! to HRMP queue with the sibling target chain). + +use crate::{Config, Pallet, XcmAsPlainPayload, LOG_TARGET}; + +use bp_messages::target_chain::{DispatchMessage, MessageDispatch}; +use bp_runtime::messages::MessageDispatchResult; +use codec::{Decode, Encode}; +use frame_support::{weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, WeightInfoExt}; +use scale_info::TypeInfo; +use sp_runtime::SaturatedConversion; +use xcm_builder::{DispatchBlob, DispatchBlobError}; + +/// Message dispatch result type for single message. +#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] +pub enum XcmBlobMessageDispatchResult { + /// We've been unable to decode message payload. + InvalidPayload, + /// Message has been dispatched. + Dispatched, + /// Message has **NOT** been dispatched because of given error. + NotDispatched(#[codec(skip)] Option), +} + +/// An easy way to access associated messages pallet weights. +type MessagesPalletWeights = + >::BridgeMessagesPalletInstance>>::WeightInfo; + +impl, I: 'static> MessageDispatch for Pallet +where + T: BridgeMessagesConfig, +{ + type DispatchPayload = XcmAsPlainPayload; + type DispatchLevelResult = XcmBlobMessageDispatchResult; + + fn is_active() -> bool { + true + } + + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + match message.data.payload { + Ok(ref payload) => { + let payload_size = payload.encoded_size().saturated_into(); + MessagesPalletWeights::::message_dispatch_weight(payload_size) + }, + Err(_) => Weight::zero(), + } + } + + fn dispatch( + message: DispatchMessage, + ) -> MessageDispatchResult { + let payload = match message.data.payload { + Ok(payload) => payload, + Err(e) => { + log::error!( + target: LOG_TARGET, + "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", + e, + message.key.nonce + ); + return MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, + } + }, + }; + let dispatch_level_result = match T::BlobDispatcher::dispatch_blob(payload) { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", + message.key.nonce + ); + XcmBlobMessageDispatchResult::Dispatched + }, + Err(e) => { + log::error!( + target: LOG_TARGET, + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", + e, message.key.nonce + ); + XcmBlobMessageDispatchResult::NotDispatched(Some(e)) + }, + }; + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 40669d4dfda9..5262b289aea2 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -22,16 +22,19 @@ use crate::{Config, Pallet, LOG_TARGET}; -use bp_messages::source_chain::MessagesBridge; use bp_xcm_bridge_hub::XcmAsPlainPayload; -use bridge_runtime_common::messages_xcm_extension::{LocalXcmQueueManager, SenderAndLane}; -use pallet_bridge_messages::{Config as BridgeMessagesConfig, Pallet as BridgeMessagesPallet}; + +use bp_messages::{source_chain::MessagesBridge, LaneId}; +use frame_support::traits::Get; +use pallet_bridge_messages::{ + Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet, +}; use xcm::prelude::*; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::ExportXcm; /// An easy way to access `HaulBlobExporter`. -pub type PalletAsHaulBlobExporter = HaulBlobExporter< +type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, >::BridgedNetwork, >::DestinationVersion, @@ -45,7 +48,7 @@ where T: BridgeMessagesConfig, { type Ticket = ( - SenderAndLane, + LaneId, as MessagesBridge>::SendMessageArgs, XcmHash, ); @@ -57,12 +60,12 @@ where destination: &mut Option, message: &mut Option>, ) -> Result<(Self::Ticket, Assets), SendError> { - // Find supported lane_id. - let sender_and_lane = Self::lane_for( - universal_source.as_ref().ok_or(SendError::MissingArgument)?, - (&network, destination.as_ref().ok_or(SendError::MissingArgument)?), - ) - .ok_or(SendError::NotApplicable)?; + // `HaulBlobExporter` may consume the `universal_source` and `destination` arguments, so + // let's save them before + let bridge_origin_universal_location = + universal_source.clone().take().ok_or(SendError::MissingArgument)?; + let bridge_destination_interior_location = + destination.clone().take().ok_or(SendError::MissingArgument)?; // check if we are able to route the message. We use existing `HaulBlobExporter` for that. // It will make all required changes and will encode message properly, so that the @@ -75,23 +78,53 @@ where message, )?; - let bridge_message = MessagesPallet::::validate_message(sender_and_lane.lane, &blob) - .map_err(|e| { - log::error!( - target: LOG_TARGET, - "XCM message {:?} cannot be exported because of bridge error {:?} on bridge {:?}", - id, - e, - sender_and_lane.lane, - ); - SendError::Transport("BridgeValidateError") - })?; - - Ok(((sender_and_lane, bridge_message, id), price)) + // ok - now we know that the message may be routed by the pallet, let's prepare the + // destination universal location + let mut bridge_destination_universal_location: InteriorLocation = + GlobalConsensus(network).into(); + bridge_destination_universal_location + .append_with(bridge_destination_interior_location) + .map_err(|_| SendError::Unroutable)?; + + // .. and the origin relative location + let bridge_origin_relative_location = + bridge_origin_universal_location.relative_to(&T::UniversalLocation::get()); + + // then we are able to compute the lane id used to send messages + let bridge_locations = Self::bridge_locations( + Box::new(bridge_origin_relative_location), + Box::new(bridge_destination_universal_location.into()), + ) + .map_err(|_| SendError::Unroutable)?; + + let bridge_message = + MessagesPallet::::validate_message(bridge_locations.lane_id, &blob).map_err( + |e| { + match e { + Error::LanesManager(ref ei) => + log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), + Error::MessageRejectedByPallet(ref ei) => + log::error!(target: LOG_TARGET, "MessageRejectedByPallet: {ei:?}"), + Error::ReceptionConfirmation(ref ei) => + log::error!(target: LOG_TARGET, "ReceptionConfirmation: {ei:?}"), + _ => (), + }; + + log::error!( + target: LOG_TARGET, + "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?}", + id, + e, + bridge_locations, + ); + SendError::Transport("BridgeValidateError") + }, + )?; + + Ok(((bridge_locations.lane_id, bridge_message, id), price)) } - fn deliver((sender_and_lane, bridge_message, id): Self::Ticket) -> Result { - let lane_id = sender_and_lane.lane; + fn deliver((lane_id, bridge_message, id): Self::Ticket) -> Result { let artifacts = MessagesPallet::::send_message(bridge_message); log::info!( @@ -102,12 +135,6 @@ where artifacts.nonce, ); - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_message_enqueued( - &sender_and_lane, - artifacts.enqueued_messages, - ); - Ok(id) } } @@ -119,7 +146,7 @@ where /// else. But bridge messages pallet may have a dedicated channel (lane) for every pair of bridged /// chains. So we are using our own `ExportXcm` implementation, but to utilize `HaulBlobExporter` we /// still need this `DummyHaulBlob`. -pub struct DummyHaulBlob; +struct DummyHaulBlob; impl HaulBlob for DummyHaulBlob { fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> { @@ -130,9 +157,11 @@ impl HaulBlob for DummyHaulBlob { #[cfg(test)] mod tests { use super::*; - use crate::mock::*; + use crate::{mock::*, Bridges, LanesManagerOf}; + use bp_messages::{LaneState, OutboundLaneData}; use bp_runtime::RangeInclusiveExt; + use bp_xcm_bridge_hub::{Bridge, BridgeState}; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; @@ -145,22 +174,49 @@ mod tests { } #[test] - fn export_works() { + fn proper_lane_is_used_by_export_xcm() { run_test(|| { - pallet_bridge_messages::OutboundLanes::::insert( - test_lane_id(), - OutboundLaneData { state: LaneState::Opened, ..Default::default() }, - ); - assert_ok!(export_xcm::( + // open expected outbound lane + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let with = bridged_asset_hub_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + assert!(lanes_manager + .active_outbound_lane(locations.lane_id) + .unwrap() + .queued_messages() + .is_empty()); + + // now let's try to enqueue message using our `ExportXcm` implementation + export_xcm::( BridgedRelayNetwork::get(), 0, - universal_source(), - bridged_relative_destination(), + locations.bridge_origin_universal_location, + locations.bridge_destination_universal_location.split_first().0, vec![Instruction::ClearOrigin].into(), - )); + ) + .unwrap(); }) } + #[test] + fn exporter_works() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + + // double check that the message has been pushed to the expected lane + // (it should already been checked during `send_message` call) + assert!(!LanesManagerOf::::new() + .active_outbound_lane(bridge_id.lane_id()) + .unwrap() + .queued_messages() + .is_empty()); + }); + } + #[test] fn export_fails_if_argument_is_missing() { run_test(|| { @@ -191,12 +247,23 @@ mod tests { #[test] fn exporter_computes_correct_lane_id() { run_test(|| { - let expected_lane_id = test_lane_id(); - - pallet_bridge_messages::OutboundLanes::::insert( - expected_lane_id, - OutboundLaneData { state: LaneState::Opened, ..Default::default() }, - ); + let expected_bridge_id = + BridgeId::new(&universal_source().into(), &universal_destination().into()); + + if LanesManagerOf::::new() + .create_outbound_lane(expected_bridge_id.lane_id()) + .is_ok() + { + Bridges::::insert( + expected_bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(universal_destination().into()), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + reserve: 0, + }, + ); + } assert_eq!( XcmOverBridge::validate( @@ -208,11 +275,10 @@ mod tests { ) .unwrap() .0 - .0 - .lane, - expected_lane_id, + .0, + expected_bridge_id ); - }) + }); } #[test] diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index af3709b5a252..957ac73933fe 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -51,24 +51,24 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler; - -pub use exporter::PalletAsHaulBlobExporter; -pub use pallet::*; - -mod exporter; use bp_messages::{LaneId, LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; use bp_xcm_bridge_hub::{ - bridge_locations, Bridge, BridgeLocations, BridgeLocationsError, BridgeState, + bridge_locations, Bridge, BridgeLocations, BridgeLocationsError, BridgeState, XcmAsPlainPayload, }; use frame_support::traits::{Currency, ReservableCurrency}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; use sp_runtime::traits::Zero; use xcm::prelude::*; +use xcm_builder::DispatchBlob; use xcm_executor::traits::ConvertLocation; +pub use dispatcher::XcmBlobMessageDispatchResult; +pub use pallet::*; + +mod dispatcher; +mod exporter; mod mock; /// The target that will be used when publishing logs related to this pallet. @@ -77,7 +77,6 @@ pub const LOG_TARGET: &str = "runtime::bridge-xcm"; #[frame_support::pallet] pub mod pallet { use super::*; - use bridge_runtime_common::messages_xcm_extension::SenderAndLane; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::{BlockNumberFor, *}; @@ -107,13 +106,6 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; - /// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`). - /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) - type Lanes: Get>; - /// Support for point-to-point links - /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) - type LanesSupport: XcmBlobHauler; - /// A set of XCM locations within local consensus system that are allowed to open /// bridges with remote destinations. // TODO: there's only one impl of `EnsureOrigin` - @@ -132,6 +124,9 @@ pub mod pallet { type BridgeReserve: Get>>; /// Currency used to pay for bridge registration. type NativeCurrency: ReservableCurrency; + + /// XCM-level dispatcher for inbound bridge messages. + type BlobDispatcher: DispatchBlob; } /// An alias for the bridge metadata. @@ -182,7 +177,7 @@ pub mod pallet { ) -> DispatchResult { // check and compute required bridge locations let locations = - Self::bridge_locations(origin, bridge_destination_universal_location.clone())?; + Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; // reserve balance on the parachain sovereign account let reserve = T::BridgeReserve::get(); @@ -262,7 +257,8 @@ pub mod pallet { may_prune_messages: MessageNonce, ) -> DispatchResult { // compute required bridge locations - let locations = Self::bridge_locations(origin, bridge_destination_universal_location)?; + let locations = + Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - may do refund here, if // bridge/lanes are already closed + for messages that are not pruned @@ -362,19 +358,28 @@ pub mod pallet { } } - impl, I: 'static> Pallet - where - T: frame_system::Config>>, - T::NativeCurrency: Currency>>, - { + impl, I: 'static> Pallet { + /// Return bridge endpoint locations and dedicated lane identifier. This method converts + /// runtime `origin` argument to relative `Location` using the `T::OpenBridgeOrigin` + /// converter. + pub fn bridge_locations_from_origin( + origin: OriginFor, + bridge_destination_universal_location: Box, + ) -> Result, sp_runtime::DispatchError> { + Self::bridge_locations( + Box::new(T::OpenBridgeOrigin::ensure_origin(origin)?), + bridge_destination_universal_location, + ) + } + /// Return bridge endpoint locations and dedicated lane identifier. pub fn bridge_locations( - origin: OriginFor, + bridge_origin_relative_location: Box, bridge_destination_universal_location: Box, ) -> Result, sp_runtime::DispatchError> { bridge_locations( Box::new(T::UniversalLocation::get()), - Box::new(T::OpenBridgeOrigin::ensure_origin(origin)?), + bridge_origin_relative_location, Box::new( (*bridge_destination_universal_location) .try_into() @@ -454,31 +459,6 @@ pub mod pallet { /// The version of XCM location argument is unsupported. UnsupportedXcmVersion, } - - impl, I: 'static> Pallet { - /// Returns dedicated/configured lane identifier. - pub(crate) fn lane_for( - source: &InteriorLocation, - dest: (&NetworkId, &InteriorLocation), - ) -> Option { - let source = source.clone().relative_to(&T::UniversalLocation::get()); - - // Check that we have configured a point-to-point lane for 'source' and `dest`. - T::Lanes::get() - .into_iter() - .find_map(|(lane_source, (lane_dest_network, lane_dest))| { - if lane_source.location == source && - &lane_dest_network == dest.0 && - Self::bridged_network_id().as_ref() == Ok(dest.0) && - &lane_dest == dest.1 - { - Some(lane_source) - } else { - None - } - }) - } - } } #[cfg(test)] @@ -502,7 +482,8 @@ mod tests { with: InteriorLocation, ) -> (BridgeOf, BridgeLocations) { let reserve = BridgeDeposit::get(); - let locations = XcmOverBridge::bridge_locations(origin, Box::new(with.into())).unwrap(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); let bridge_owner_account = fund_origin_sovereign_account(&locations, reserve + ExistentialDeposit::get()); Balances::reserve(&bridge_owner_account, reserve).unwrap(); @@ -643,7 +624,7 @@ mod tests { fn open_bridge_fails_if_it_already_exists() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let locations = XcmOverBridge::bridge_locations( + let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), Box::new(bridged_asset_hub_location().into()), ) @@ -676,7 +657,7 @@ mod tests { fn open_bridge_fails_if_its_lanes_already_exists() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let locations = XcmOverBridge::bridge_locations( + let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), Box::new(bridged_asset_hub_location().into()), ) @@ -728,7 +709,7 @@ mod tests { System::reset_events(); // compute all other locations - let locations = XcmOverBridge::bridge_locations( + let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), Box::new(bridged_asset_hub_location().into()), ) diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 673a5790ec08..cfaf3998e259 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -22,8 +22,7 @@ use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, ChainWithMessages, LaneId, MessageNonce, }; -use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; -use bridge_runtime_common::messages_xcm_extension::{SenderAndLane, XcmBlobHauler}; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, @@ -39,8 +38,9 @@ use sp_runtime::{ use sp_std::cell::RefCell; use xcm::prelude::*; use xcm_builder::{ - AllowUnpaidExecutionFrom, FixedWeightBounds, InspectMessageQueues, NetworkExportTable, - NetworkExportTableItem, + AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds, + InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, + SiblingParachainConvertsVia, }; use xcm_executor::XcmExecutor; @@ -49,7 +49,6 @@ pub type Balance = u64; use frame_support::traits::{EnsureOrigin, OriginTrait}; use polkadot_parachain_primitives::primitives::Sibling; -use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; type Block = frame_system::mocking::MockBlock; @@ -57,11 +56,6 @@ pub const SIBLING_ASSET_HUB_ID: u32 = 2001; pub const THIS_BRIDGE_HUB_ID: u32 = 2002; pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; -/// Message lane used in tests. -pub fn test_lane_id() -> LaneId { - bridge_runtime_common::messages_xcm_extension::LaneIdFromChainId::::get() -} - frame_support::construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, @@ -103,7 +97,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type ThisChain = ThisUnderlyingChain; type BridgedChain = BridgedUnderlyingChain; - type BridgedHeaderChain = BridgedHeaderChain; + type BridgedHeaderChain = (); } pub struct TestMessagesWeights; @@ -164,7 +158,6 @@ parameter_types! { pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; pub const BridgeDeposit: Balance = 100_000; - pub const Penalty: Balance = 1_000; // configuration for pallet_xcm_bridge_hub_router pub BridgeHubLocation: Location = Here.into(); @@ -191,14 +184,13 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; - type Lanes = TestLanes; - type LanesSupport = TestXcmBlobHauler; - type OpenBridgeOrigin = OpenBridgeOrigin; type BridgeOriginAccountIdConverter = LocationToAccountId; type BridgeReserve = BridgeDeposit; type NativeCurrency = Balances; + + type BlobDispatcher = TestBlobDispatcher; } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { @@ -302,25 +294,6 @@ impl TestExportXcmWithXcmOverBridge { } } -parameter_types! { - pub TestSenderAndLane: SenderAndLane = SenderAndLane { - location: SiblingLocation::get(), - lane: test_lane_id(), - }; - pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ - (TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedRelativeDestination::get())) - ]; -} - -pub struct TestXcmBlobHauler; -impl XcmBlobHauler for TestXcmBlobHauler { - type Runtime = TestRuntime; - type MessagesInstance = (); - type ToSourceChainSender = (); - type CongestedMessage = (); - type UncongestedMessage = (); -} - /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used /// when determining ownership of accounts for asset transacting and when attempting to use XCM /// `Transact` in order to determine the dispatch Origin. @@ -401,6 +374,14 @@ impl EnsureOrigin for OpenBridgeOrigin { } } +pub struct TestBlobDispatcher; + +impl DispatchBlob for TestBlobDispatcher { + fn dispatch_blob(_blob: Vec) -> Result<(), DispatchBlobError> { + Ok(()) + } +} + pub struct ThisUnderlyingChain; impl Chain for ThisUnderlyingChain { @@ -492,15 +473,6 @@ impl MessageDispatch for TestMessageDispatch { } } -pub struct BridgedHeaderChain; -impl bp_header_chain::HeaderChain for BridgedHeaderChain { - fn finalized_header_state_root( - _hash: HashOf, - ) -> Option> { - unreachable!() - } -} - /// Location of bridged asset hub. pub fn bridged_asset_hub_location() -> InteriorLocation { [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into() From 6756a25d427fc4b9a2f21e61c732a30bab3c3ab8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 1 Aug 2023 12:43:11 +0300 Subject: [PATCH 15/95] Implement additional require primitives for dynamic fees directly for pallet-xcm-bridge-hub (#2261) Xcm bridge hub router v2 (backport to master branch) (#2312) * copy new pallet (palle-xcm-bridge-hub-router) from dynamic-fees-v1 branch * added remaining traces of pallet-xcm-bridge-hub-router * added comment about sharing delivery fee factor between all bridges, opened by this chain * spelling * clippy Implement additional require primitives for dynamic fees directly for pallet-xcm-bridge-hub (#2261) * added backoff mechanism to inbound bridge queue * impl backpressure in the XcmBlobHaulerAdapter * leave TODOs * BridgeMessageProcessor prototype * another TODO * Revert "also temporary (?) remove BridgesByLocalOrigin because the storage format will likely change to be able to resume bridges from the on_iniitalize/on_idle" This reverts commit bdd7ae11a8942b58c5db6ac6d4e7922aa28cece4. * prototype for QueuePausedQuery * implement ExportXcm and MessageDispatch for pallet-xcm-bridge-hub * spelling * flush * small comments to myself * more backports from dynamic-fees-v1 * use new pallet as exporter and dispatcher in Millau * use new pallet as exporter and dispatcher in Rialto * use new pallet as exporter and dispatcher in RialtoParachain * flush * fix remaining compilation issues * warnings + fmt * fix tests * LocalXcmChannelManager * change lane ids * it works! * remove bp-xcm-bridge-hub-router and use LocalXcmChannelManager everywhere * removed commented code * cleaning up * cleaning up * cleaning up * - separated BridgeId and LaneId - BridgeId now uses versioned universal locations - added missing stuff to exporter.rs * OnMessagesDelivered is back * start using bp-xcm-bridge-hub as OnMessagesDelivered * cleaning up * spelling * fix stupid issues * Backport latest relevant dynamic fees changes from v1 to v2 (#2372) * backport latest relevant dynamic fees changes from v1 to v2 * fix comment Added remaining unit tests for pallet-xcm-bridge-hub (#2499) * added backoff mechanism to inbound bridge queue * impl backpressure in the XcmBlobHaulerAdapter * leave TODOs * BridgeMessageProcessor prototype * another TODO * Revert "also temporary (?) remove BridgesByLocalOrigin because the storage format will likely change to be able to resume bridges from the on_iniitalize/on_idle" This reverts commit bdd7ae11a8942b58c5db6ac6d4e7922aa28cece4. * prototype for QueuePausedQuery * implement ExportXcm and MessageDispatch for pallet-xcm-bridge-hub * spelling * flush * small comments to myself * more backports from dynamic-fees-v1 * use new pallet as exporter and dispatcher in Millau * use new pallet as exporter and dispatcher in Rialto * use new pallet as exporter and dispatcher in RialtoParachain * flush * fix remaining compilation issues * warnings + fmt * fix tests * LocalXcmChannelManager * change lane ids * it works! * remove bp-xcm-bridge-hub-router and use LocalXcmChannelManager everywhere * removed commented code * cleaning up * cleaning up * cleaning up * - separated BridgeId and LaneId - BridgeId now uses versioned universal locations - added missing stuff to exporter.rs * OnMessagesDelivered is back * start using bp-xcm-bridge-hub as OnMessagesDelivered * cleaning up * spelling * fix stupid issues * added remaining unit tests for pallet-xcm-bridge-hub fixed benchmarks (#2504) Remove pallet_xcm_bridge_hub::SuspendedBridges (#2505) * remove pallet_xcm_bridge_hub::SuspendedBridges * apply review suggestions --- Cargo.lock | 3 + .../extensions/refund_relayer_extension.rs | 22 +- bridges/bin/runtime-common/src/lib.rs | 3 - .../runtime-common/src/messages_call_ext.rs | 7 +- .../src/messages_xcm_extension.rs | 524 ------------------ bridges/bin/runtime-common/src/mock.rs | 17 +- bridges/modules/messages/src/lanes_manager.rs | 37 +- bridges/modules/messages/src/lib.rs | 6 +- bridges/modules/messages/src/tests/mock.rs | 34 +- .../messages/src/tests/pallet_tests.rs | 86 ++- .../modules/xcm-bridge-hub-router/Cargo.toml | 5 +- .../xcm-bridge-hub-router/src/benchmarking.rs | 43 +- .../modules/xcm-bridge-hub-router/src/lib.rs | 291 ++++------ .../modules/xcm-bridge-hub-router/src/mock.rs | 34 +- .../xcm-bridge-hub-router/src/weights.rs | 133 +---- bridges/modules/xcm-bridge-hub/Cargo.toml | 1 + .../modules/xcm-bridge-hub/src/dispatcher.rs | 119 +++- .../modules/xcm-bridge-hub/src/exporter.rs | 371 +++++++++++-- bridges/modules/xcm-bridge-hub/src/lib.rs | 209 +++++-- bridges/modules/xcm-bridge-hub/src/mock.rs | 80 ++- .../primitives/messages/src/target_chain.rs | 4 +- bridges/primitives/xcm-bridge-hub/Cargo.toml | 2 + bridges/primitives/xcm-bridge-hub/src/lib.rs | 153 +++-- 23 files changed, 1092 insertions(+), 1092 deletions(-) delete mode 100644 bridges/bin/runtime-common/src/messages_xcm_extension.rs diff --git a/Cargo.lock b/Cargo.lock index 938daca729cb..ed3a7a678aa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2012,6 +2012,7 @@ dependencies = [ "frame-support", "parity-scale-codec", "scale-info", + "serde", "sp-std 14.0.0", "staging-xcm", ] @@ -11993,6 +11994,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub" version = "0.2.0" dependencies = [ + "bp-header-chain", "bp-messages", "bp-runtime", "bp-xcm-bridge-hub", @@ -12018,6 +12020,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ + "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-benchmarking", "frame-support", diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 668ca94dd7ce..42a3d118854d 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -19,11 +19,8 @@ //! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). -use crate::{ - messages_call_ext::{ - CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, - }, - messages_xcm_extension::LaneIdFromChainId, +use crate::messages_call_ext::{ + CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, }; use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; @@ -95,15 +92,17 @@ pub trait RefundableMessagesLaneId { } /// Default implementation of `RefundableMessagesLaneId`. -pub struct RefundableMessagesLane(PhantomData<(Runtime, Instance)>); +pub struct RefundableMessagesLane(PhantomData<(Runtime, Instance, Lane)>); -impl RefundableMessagesLaneId for RefundableMessagesLane +impl RefundableMessagesLaneId + for RefundableMessagesLane where Runtime: MessagesConfig, Instance: 'static, + Lane: Get, { type Instance = Instance; - type Id = LaneIdFromChainId; + type Id = Lane; } /// Refund calculator. @@ -982,13 +981,14 @@ pub(crate) mod tests { TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain, ); + pub TestLaneId: LaneId = test_lane_id(); } bp_runtime::generate_static_str_provider!(TestExtension); type TestMessagesExtensionProvider = RefundBridgedMessages< TestRuntime, - RefundableMessagesLane, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, @@ -997,7 +997,7 @@ pub(crate) mod tests { type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< TestRuntime, (), - RefundableMessagesLane, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, @@ -1006,7 +1006,7 @@ pub(crate) mod tests { type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, RefundableParachain<(), BridgedUnderlyingParachain>, - RefundableMessagesLane, + RefundableMessagesLane, ActualFeeRefund, ConstU64<1>, StrTestExtension, diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index b65bb6041d56..3e3394688f18 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -24,12 +24,9 @@ pub mod extensions; pub mod messages_api; pub mod messages_benchmarking; pub mod messages_call_ext; -pub mod messages_xcm_extension; pub mod parachains_benchmarking; mod mock; #[cfg(feature = "integrity-test")] pub mod integrity; - -const LOG_TARGET_BRIDGE_DISPATCH: &str = "runtime::bridge-dispatch"; diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index c4e5a5e25829..2101e2a5ffce 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -302,7 +302,8 @@ impl< return sp_runtime::transaction_validity::InvalidTransaction::Call.into() }, Some(CallInfo::ReceiveMessagesProof(proof_info)) - if proof_info.is_obsolete(T::MessageDispatch::is_active()) => + if proof_info + .is_obsolete(T::MessageDispatch::is_active(proof_info.base.lane_id)) => { log::trace!( target: pallet_bridge_messages::LOG_TARGET, @@ -486,12 +487,12 @@ mod tests { #[test] fn extension_reject_call_when_dispatcher_is_inactive() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver message 11..=15 // => tx is accepted, but we have inactive dispatcher, so... deliver_message_10(); - DummyMessageDispatch::deactivate(); + DummyMessageDispatch::deactivate(test_lane_id()); assert!(!validate_message_delivery(11, 15)); }); } diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs deleted file mode 100644 index 5ce906bef61d..000000000000 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! Module provides utilities for easier XCM handling, e.g: -//! `XcmExecutor` -> `MessageSender` -> `OutboundMessageQueue` -//! | -//! `Relayer` -//! | -//! `XcmRouter` <- `MessageDispatch` <- `InboundMessageQueue` - -use bp_messages::{ - source_chain::OnMessagesDelivered, - target_chain::{DispatchMessage, MessageDispatch}, - LaneId, MessageNonce, -}; -use bp_runtime::{messages::MessageDispatchResult, Chain}; -pub use bp_xcm_bridge_hub::XcmAsPlainPayload; -use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; -use codec::{Decode, Encode}; -use frame_support::{traits::Get, weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; -use pallet_bridge_messages::{ - Config as MessagesConfig, OutboundLanesCongestedSignals, WeightInfoExt as MessagesPalletWeights, -}; -use scale_info::TypeInfo; -use sp_runtime::SaturatedConversion; -use sp_std::{fmt::Debug, marker::PhantomData}; -use xcm::prelude::*; - -use xcm_builder::{DispatchBlob, DispatchBlobError}; - -/// Make LaneId from chain identifiers of two bridge endpoints. -// TODO: https://github.com/paritytech/parity-bridges-common/issues/1666: this function -// is a temporary solution, because `ChainId` and will be removed soon. -pub struct LaneIdFromChainId(PhantomData<(R, I)>); - -impl Get for LaneIdFromChainId -where - R: pallet_bridge_messages::Config, - I: 'static, -{ - fn get() -> LaneId { - LaneId::new( - pallet_bridge_messages::ThisChainOf::::ID, - pallet_bridge_messages::BridgedChainOf::::ID, - ) - } -} - -/// Message dispatch result type for single message. -#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] -pub enum XcmBlobMessageDispatchResult { - /// We've been unable to decode message payload. - InvalidPayload, - /// Message has been dispatched. - Dispatched, - /// Message has **NOT** been dispatched because of given error. - NotDispatched(#[codec(skip)] Option), -} - -/// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages -/// -/// It needs to be used at the target bridge hub. -pub struct XcmBlobMessageDispatch { - _marker: sp_std::marker::PhantomData<(DispatchBlob, Weights, Channel)>, -} - -impl< - BlobDispatcher: DispatchBlob, - Weights: MessagesPalletWeights, - Channel: XcmChannelStatusProvider, - > MessageDispatch for XcmBlobMessageDispatch -{ - type DispatchPayload = XcmAsPlainPayload; - type DispatchLevelResult = XcmBlobMessageDispatchResult; - - fn is_active() -> bool { - !Channel::is_congested() - } - - fn dispatch_weight(message: &mut DispatchMessage) -> Weight { - match message.data.payload { - Ok(ref payload) => { - let payload_size = payload.encoded_size().saturated_into(); - Weights::message_dispatch_weight(payload_size) - }, - Err(_) => Weight::zero(), - } - } - - fn dispatch( - message: DispatchMessage, - ) -> MessageDispatchResult { - let payload = match message.data.payload { - Ok(payload) => payload, - Err(e) => { - log::error!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", - e, - message.key.nonce - ); - return MessageDispatchResult { - unspent_weight: Weight::zero(), - dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, - } - }, - }; - let dispatch_level_result = match BlobDispatcher::dispatch_blob(payload) { - Ok(_) => { - log::debug!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", - message.key.nonce - ); - XcmBlobMessageDispatchResult::Dispatched - }, - Err(e) => { - log::error!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", - e, message.key.nonce - ); - XcmBlobMessageDispatchResult::NotDispatched(Some(e)) - }, - }; - MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } - } -} - -/// A pair of sending chain location and message lane, used by this chain to send messages -/// over the bridge. -#[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] -pub struct SenderAndLane { - /// Sending chain relative location. - pub location: Location, - /// Message lane, used by the sending chain. - pub lane: LaneId, -} - -impl SenderAndLane { - /// Create new object using provided location and lane. - pub fn new(location: Location, lane: LaneId) -> Self { - SenderAndLane { location, lane } - } -} - -/// [`XcmBlobHauler`] is responsible for sending messages to the bridge "point-to-point link" from -/// one side, where on the other it can be dispatched by [`XcmBlobMessageDispatch`]. -pub trait XcmBlobHauler { - /// Runtime that has messages pallet deployed. - type Runtime: MessagesConfig; - /// Instance of the messages pallet that is used to send messages. - type MessagesInstance: 'static; - - /// Actual XCM message sender (`HRMP` or `UMP`) to the source chain - /// location (`Self::SenderAndLane::get().location`). - type ToSourceChainSender: SendXcm; - /// An XCM message that is sent to the sending chain when the bridge queue becomes congested. - type CongestedMessage: Get>>; - /// An XCM message that is sent to the sending chain when the bridge queue becomes not - /// congested. - type UncongestedMessage: Get>>; - - /// Returns `true` if we want to handle congestion. - fn supports_congestion_detection() -> bool { - Self::CongestedMessage::get().is_some() || Self::UncongestedMessage::get().is_some() - } -} - -/// XCM bridge adapter which connects [`XcmBlobHauler`] with [`pallet_bridge_messages`] and -/// makes sure that XCM blob is sent to the outbound lane to be relayed. -/// -/// It needs to be used at the source bridge hub. -pub struct XcmBlobHaulerAdapter( - sp_std::marker::PhantomData<(XcmBlobHauler, Lanes)>, -); - -impl< - H: XcmBlobHauler, - Lanes: Get>, - > OnMessagesDelivered for XcmBlobHaulerAdapter -{ - fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) { - if let Some(sender_and_lane) = - Lanes::get().iter().find(|link| link.0.lane == lane).map(|link| &link.0) - { - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_messages_delivered( - sender_and_lane, - enqueued_messages, - ); - } - } -} - -/// Manager of local XCM queues (and indirectly - underlying transport channels) that -/// controls the queue state. -/// -/// It needs to be used at the source bridge hub. -pub struct LocalXcmQueueManager(PhantomData); - -/// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we -/// send a "congestion" XCM message to the sending chain. -const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192; - -/// After we have sent "congestion" XCM message to the sending chain, we wait until number -/// of messages in the outbound bridge queue drops to this count, before sending `uncongestion` -/// XCM message. -const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024; - -impl LocalXcmQueueManager { - /// Must be called whenever we push a message to the bridge lane. - pub fn on_bridge_message_enqueued( - sender_and_lane: &SenderAndLane, - enqueued_messages: MessageNonce, - ) { - // skip if we dont want to handle congestion - if !H::supports_congestion_detection() { - return - } - - // if we have already sent the congestion signal, we don't want to do anything - if Self::is_congested_signal_sent(sender_and_lane.lane) { - return - } - - // if the bridge queue is not congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD; - if !is_congested { - return - } - - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Sending 'congested' XCM message to {:?} to avoid overloading lane {:?}: there are\ - {} messages queued at the bridge queue", - sender_and_lane.location, - sender_and_lane.lane, - enqueued_messages, - ); - - if let Err(e) = Self::send_congested_signal(sender_and_lane) { - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Failed to send the 'congested' XCM message to {:?}: {:?}", - sender_and_lane.location, - e, - ); - } - } - - /// Must be called whenever we receive a message delivery confirmation. - pub fn on_bridge_messages_delivered( - sender_and_lane: &SenderAndLane, - enqueued_messages: MessageNonce, - ) { - // skip if we don't want to handle congestion - if !H::supports_congestion_detection() { - return - } - - // if we have not sent the congestion signal before, we don't want to do anything - if !Self::is_congested_signal_sent(sender_and_lane.lane) { - return - } - - // if the bridge queue is still congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; - if is_congested { - return - } - - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Sending 'uncongested' XCM message to {:?}. Lane {:?}: there are\ - {} messages queued at the bridge queue", - sender_and_lane.location, - sender_and_lane.lane, - enqueued_messages, - ); - - if let Err(e) = Self::send_uncongested_signal(sender_and_lane) { - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Failed to send the 'uncongested' XCM message to {:?}: {:?}", - sender_and_lane.location, - e, - ); - } - } - - /// Returns true if we have sent "congested" signal to the `sending_chain_location`. - fn is_congested_signal_sent(lane: LaneId) -> bool { - OutboundLanesCongestedSignals::::get(lane) - } - - /// Send congested signal to the `sending_chain_location`. - fn send_congested_signal(sender_and_lane: &SenderAndLane) -> Result<(), SendError> { - if let Some(msg) = H::CongestedMessage::get() { - send_xcm::(sender_and_lane.location.clone(), msg)?; - OutboundLanesCongestedSignals::::insert( - sender_and_lane.lane, - true, - ); - } - Ok(()) - } - - /// Send `uncongested` signal to the `sending_chain_location`. - fn send_uncongested_signal(sender_and_lane: &SenderAndLane) -> Result<(), SendError> { - if let Some(msg) = H::UncongestedMessage::get() { - send_xcm::(sender_and_lane.location.clone(), msg)?; - OutboundLanesCongestedSignals::::remove( - sender_and_lane.lane, - ); - } - Ok(()) - } -} - -/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal -/// configured XCM version between the destination `dest` and the bridge hub location provided as -/// `Get`. -pub struct XcmVersionOfDestAndRemoteBridge( - sp_std::marker::PhantomData<(Version, RemoteBridge)>, -); -impl> GetVersion - for XcmVersionOfDestAndRemoteBridge -{ - fn get_version_for(dest: &Location) -> Option { - let dest_version = Version::get_version_for(dest); - let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); - - match (dest_version, bridge_hub_version) { - (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), - (Some(dv), None) => Some(dv), - (None, Some(bhv)) => Some(bhv), - (None, None) => None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::*; - - use bp_messages::{LaneState, OutboundLaneData}; - use frame_support::parameter_types; - use pallet_bridge_messages::OutboundLanes; - - parameter_types! { - pub TestSenderAndLane: SenderAndLane = SenderAndLane { - location: Location::new(1, [Parachain(1000)]), - lane: test_lane_id(), - }; - pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ - (TestSenderAndLane::get(), (NetworkId::ByGenesis([0; 32]), InteriorLocation::Here)) - ]; - pub DummyXcmMessage: Xcm<()> = Xcm::new(); - } - - struct DummySendXcm; - - impl DummySendXcm { - fn messages_sent() -> u32 { - frame_support::storage::unhashed::get(b"DummySendXcm").unwrap_or(0) - } - } - - impl SendXcm for DummySendXcm { - type Ticket = (); - - fn validate( - _destination: &mut Option, - _message: &mut Option>, - ) -> SendResult { - Ok(((), Default::default())) - } - - fn deliver(_ticket: Self::Ticket) -> Result { - let messages_sent: u32 = Self::messages_sent(); - frame_support::storage::unhashed::put(b"DummySendXcm", &(messages_sent + 1)); - Ok(XcmHash::default()) - } - } - - struct TestBlobHauler; - - impl XcmBlobHauler for TestBlobHauler { - type Runtime = TestRuntime; - type MessagesInstance = (); - - type ToSourceChainSender = DummySendXcm; - type CongestedMessage = DummyXcmMessage; - type UncongestedMessage = DummyXcmMessage; - } - - type TestBlobHaulerAdapter = XcmBlobHaulerAdapter; - - fn fill_up_lane_to_congestion() -> MessageNonce { - let latest_generated_nonce = OUTBOUND_LANE_CONGESTED_THRESHOLD; - OutboundLanes::::insert( - test_lane_id(), - OutboundLaneData { - state: LaneState::Opened, - oldest_unpruned_nonce: 0, - latest_received_nonce: 0, - latest_generated_nonce, - }, - ); - latest_generated_nonce - } - - #[test] - fn congested_signal_is_not_sent_twice() { - run_test(|| { - let enqueued = fill_up_lane_to_congestion(); - - // next sent message leads to congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - - // next sent message => we don't sent another congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn congested_signal_is_not_sent_when_outbound_lane_is_not_congested() { - run_test(|| { - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 0); - }); - } - - #[test] - fn congested_signal_is_sent_when_outbound_lane_is_congested() { - run_test(|| { - let enqueued = fill_up_lane_to_congestion(); - - // next sent message leads to congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - assert!(LocalXcmQueueManager::::is_congested_signal_sent( - test_lane_id() - )); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_when_messages_are_delivered_at_other_lane() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - // when we receive a delivery report for other lane, we don't send an uncongested signal - TestBlobHaulerAdapter::on_messages_delivered(LaneId::new(1, 3), 0); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_when_we_havent_send_congested_signal_before() { - run_test(|| { - TestBlobHaulerAdapter::on_messages_delivered(test_lane_id(), 0); - assert_eq!(DummySendXcm::messages_sent(), 0); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_if_outbound_lane_is_still_congested() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - TestBlobHaulerAdapter::on_messages_delivered( - test_lane_id(), - OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn uncongested_signal_is_sent_if_outbound_lane_is_uncongested() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - TestBlobHaulerAdapter::on_messages_delivered( - test_lane_id(), - OUTBOUND_LANE_UNCONGESTED_THRESHOLD, - ); - assert_eq!(DummySendXcm::messages_sent(), 2); - }); - } -} diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 83ee83f517f8..917b529be834 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -18,8 +18,6 @@ #![cfg(test)] -use crate::messages_xcm_extension::XcmAsPlainPayload; - use bp_header_chain::ChainWithGrandpa; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, @@ -28,12 +26,12 @@ use bp_messages::{ use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::PayRewardFromAccount; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Parachain}; +use codec::Encode; use frame_support::{ derive_impl, parameter_types, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, }; use pallet_transaction_payment::Multiplier; -use sp_core::Get; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8}, @@ -87,7 +85,7 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< /// Message lane used in tests. pub fn test_lane_id() -> LaneId { - crate::messages_xcm_extension::LaneIdFromChainId::::get() + LaneId::new(1, 2) } /// Bridged chain id used in tests. @@ -189,7 +187,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; - type OutboundPayload = XcmAsPlainPayload; + type OutboundPayload = Vec; type InboundPayload = Vec; type DeliveryPayments = (); @@ -220,8 +218,8 @@ impl pallet_bridge_relayers::Config for TestRuntime { pub struct DummyMessageDispatch; impl DummyMessageDispatch { - pub fn deactivate() { - frame_support::storage::unhashed::put(&b"inactive"[..], &false); + pub fn deactivate(lane: LaneId) { + frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } @@ -229,8 +227,9 @@ impl MessageDispatch for DummyMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); - fn is_active() -> bool { - frame_support::storage::unhashed::take::(&b"inactive"[..]) != Some(false) + fn is_active(lane: LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) } fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs index 911bed9fcb67..b3455202259c 100644 --- a/bridges/modules/messages/src/lanes_manager.rs +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -21,8 +21,8 @@ use crate::{ }; use bp_messages::{ - ChainWithMessages, InboundLaneData, LaneId, LaneState, MessageKey, MessageNonce, - OutboundLaneData, + target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, LaneState, + MessageKey, MessageNonce, OutboundLaneData, }; use bp_runtime::AccountIdOf; use codec::{Decode, Encode, MaxEncodedLen}; @@ -45,6 +45,9 @@ pub enum LanesManagerError { ClosedInboundLane, /// Outbound lane with given id is closed. ClosedOutboundLane, + /// Message dispatcher is inactive at given inbound lane. This is logical equivalent + /// of the [`Self::ClosedInboundLane`] variant. + LaneDispatcherInactive, } /// Message lanes manager. @@ -145,10 +148,32 @@ impl, I: 'static> RuntimeInboundLaneStorage { ) -> Result, LanesManagerError> { let cached_data = InboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownInboundLane)?; - ensure!( - !check_active || cached_data.state.is_active(), - LanesManagerError::ClosedInboundLane - ); + + if check_active { + // check that the lane is not explicitly closed + ensure!(cached_data.state.is_active(), LanesManagerError::ClosedInboundLane); + // apart from the explicit closure, the lane may be unable to receive any messages. + // Right now we do an additional check here, but it may be done later (e.g. by + // explicitly closing the lane and reopening it from + // `pallet-xcm-bridge-hub::on-initialize`) + // + // The fact that we only check it here, means that the `MessageDispatch` may switch + // to inactive state during some message dispatch in the middle of message delivery + // transaction. But we treat result of `MessageDispatch::is_active()` as a hint, so + // we know that it won't drop messages - just it experiences problems with processing. + // This would allow us to check that in our signed extensions, and invalidate + // transaction early, thus avoiding losing honest relayers funds. This problem should + // gone with relayers coordination protocol. + // + // There's a limit on number of messages in the message delivery transaction, so even + // if we dispatch (enqueue) some additional messages, we'll know the maximal queue + // length; + ensure!( + T::MessageDispatch::is_active(lane_id), + LanesManagerError::LaneDispatcherInactive + ); + } + Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into(), diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 554db4faa8ec..03fae73f2552 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -213,9 +213,6 @@ pub mod pallet { Error::::TooManyMessagesInTheProof ); - // if message dispatcher is currently inactive, we won't accept any messages - ensure!(T::MessageDispatch::is_active(), Error::::MessageDispatchInactive); - // why do we need to know the weight of this (`receive_messages_proof`) call? Because // we may want to return some funds for not-dispatching (or partially dispatching) some // messages to the call origin (relayer). And this is done by returning actual weight @@ -463,8 +460,6 @@ pub mod pallet { pub enum Error { /// Pallet is not in Normal operating mode. NotOperatingNormally, - /// The inbound message dispatcher is inactive. - MessageDispatchInactive, /// Error that is reported by the lanes manager. LanesManager(LanesManagerError), /// Message has been treated as invalid by the pallet logic. @@ -702,6 +697,7 @@ where lane_id: LaneId, message: &T::OutboundPayload, ) -> Result, Self::Error> { + // we can't accept any messages if the pallet is halted ensure_normal_operating_mode::()?; // check lane diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index 9d24233929bf..2caea9813e82 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -43,7 +43,7 @@ use bp_runtime::{ }; use codec::{Decode, Encode}; use frame_support::{ - derive_impl, parameter_types, + derive_impl, weights::{constants::RocksDbWeight, Weight}, }; use scale_info::TypeInfo; @@ -183,11 +183,6 @@ impl pallet_bridge_grandpa::Config for TestRuntime { type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } -parameter_types! { - pub const MaxMessagesToPruneAtOnce: u64 = 10; - pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; -} - /// weights of messages pallet calls we use in tests. pub type TestWeightInfo = (); @@ -346,8 +341,18 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment pub struct TestMessageDispatch; impl TestMessageDispatch { - pub fn deactivate() { - frame_support::storage::unhashed::put(b"TestMessageDispatch.IsCongested", &true) + pub fn deactivate(lane: LaneId) { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1; + for _ in 1..=latest_received_nonce { + Self::emulate_enqueued_message(lane); + } + } + + pub fn emulate_enqueued_message(lane: LaneId) { + let key = (b"dispatched", lane).encode(); + let dispatched = frame_support::storage::unhashed::get_or_default::(&key[..]); + frame_support::storage::unhashed::put(&key[..], &(dispatched + 1)); } } @@ -355,10 +360,10 @@ impl MessageDispatch for TestMessageDispatch { type DispatchPayload = TestPayload; type DispatchLevelResult = TestDispatchLevelResult; - fn is_active() -> bool { - !frame_support::storage::unhashed::get_or_default::( - b"TestMessageDispatch.IsCongested", - ) + fn is_active(lane: LaneId) -> bool { + frame_support::storage::unhashed::get_or_default::( + &(b"dispatched", lane).encode()[..], + ) <= BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX } fn dispatch_weight(message: &mut DispatchMessage) -> Weight { @@ -372,7 +377,10 @@ impl MessageDispatch for TestMessageDispatch { message: DispatchMessage, ) -> MessageDispatchResult { match message.data.payload.as_ref() { - Ok(payload) => payload.dispatch_result.clone(), + Ok(payload) => { + Self::emulate_enqueued_message(message.key.lane_id); + payload.dispatch_result.clone() + }, Err(_) => dispatch_result(0), } } diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 13d5af15a3be..a3497c4b66dd 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -28,7 +28,7 @@ use crate::{ use bp_messages::{ source_chain::{FromBridgedChainMessagesDeliveryProof, MessagesBridge}, - target_chain::FromBridgedChainMessagesProof, + target_chain::{FromBridgedChainMessagesProof, MessageDispatch}, BridgeMessagesCall, ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, LaneState, MessageKey, MessageNonce, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState, @@ -168,7 +168,7 @@ fn pallet_rejects_transactions_if_halted() { #[test] fn receive_messages_fails_if_dispatcher_is_inactive() { run_test(|| { - TestMessageDispatch::deactivate(); + TestMessageDispatch::deactivate(test_lane_id()); let proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); assert_noop!( Pallet::::receive_messages_proof( @@ -178,7 +178,7 @@ fn receive_messages_fails_if_dispatcher_is_inactive() { 1, REGULAR_PAYLOAD.declared_weight, ), - Error::::MessageDispatchInactive, + Error::::LanesManager(LanesManagerError::LaneDispatcherInactive), ); }); } @@ -347,6 +347,86 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }); } +#[test] +fn receive_messages_proof_fails_when_dispatcher_is_inactive() { + run_test(|| { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1; + for _ in 1..=latest_received_nonce { + TestMessageDispatch::emulate_enqueued_message(test_lane_id()); + } + assert!(!TestMessageDispatch::is_active(test_lane_id())); + InboundLanes::::insert( + test_lane_id(), + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: latest_received_nonce, + relayers: vec![].into(), + }, + ); + + // try to delvier next message - it should fail because dispatcher is in "suspended" state + // at the beginning of the call + let messages_proof = + prepare_messages_proof(vec![message(latest_received_nonce + 1, REGULAR_PAYLOAD)], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + messages_proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::LanesManager(LanesManagerError::LaneDispatcherInactive) + ); + assert!(!TestMessageDispatch::is_active(test_lane_id())); + }); +} + +#[test] +fn receive_messages_succeeds_when_dispatcher_becomes_inactive_in_the_middle_of_transaction() { + run_test(|| { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX / 2; + for _ in 1..=latest_received_nonce { + TestMessageDispatch::emulate_enqueued_message(test_lane_id()); + } + assert!(TestMessageDispatch::is_active(test_lane_id())); + InboundLanes::::insert( + test_lane_id(), + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: latest_received_nonce, + relayers: vec![].into(), + }, + ); + + // try to delvier next `BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` messages + // - it will lead to dispatcher deactivation, but the transaction shall not fail and all + // messages must be delivered + let messages_begin = latest_received_nonce + 1; + let messages_end = + messages_begin + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + let messages_range = messages_begin..messages_end; + let messages_count = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof( + messages_range.map(|nonce| message(nonce, REGULAR_PAYLOAD)).collect(), + None, + ), + messages_count as _, + REGULAR_PAYLOAD.declared_weight * messages_count, + ),); + assert_eq!( + inbound_unrewarded_relayers_state(test_lane_id()).last_delivered_nonce, + messages_end - 1, + ); + assert!(!TestMessageDispatch::is_active(test_lane_id())); + }); +} + #[test] fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() { run_test(|| { diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index ec7c3b562832..1cda8893967e 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -16,11 +16,10 @@ log = { workspace = true } scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } # Bridge dependencies - bp-xcm-bridge-hub-router = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Dependencies - frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } @@ -29,7 +28,6 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } # Polkadot Dependencies - xcm = { workspace = true } xcm-builder = { workspace = true } @@ -41,6 +39,7 @@ sp-std = { workspace = true, default-features = true } default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", + "bp-xcm-bridge-hub/std", "codec/std", "frame-benchmarking/std", "frame-support/std", diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index c4f9f534c1a4..3c4a10f82e7d 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -18,11 +18,9 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{Bridge, Call}; - -use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; +use crate::{DeliveryFeeFactor, MINIMAL_DELIVERY_FEE_FACTOR}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; -use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; +use frame_support::traits::{Get, Hooks}; use sp_runtime::traits::Zero; use xcm::prelude::*; @@ -47,49 +45,16 @@ pub trait Config: crate::Config { benchmarks_instance_pallet! { on_initialize_when_non_congested { - Bridge::::put(BridgeState { - is_congested: false, - delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, - }); + DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); }: { crate::Pallet::::on_initialize(Zero::zero()) } on_initialize_when_congested { - Bridge::::put(BridgeState { - is_congested: false, - delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, - }); - + DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) } - - report_bridge_status { - Bridge::::put(BridgeState::default()); - - let origin: T::RuntimeOrigin = T::BridgeHubOrigin::try_successful_origin().expect("expected valid BridgeHubOrigin"); - let bridge_id = Default::default(); - let is_congested = true; - - let call = Call::::report_bridge_status { bridge_id, is_congested }; - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert!(Bridge::::get().is_congested); - } - - send_message { - let dest = T::ensure_bridged_target_destination()?; - let xcm = sp_std::vec![].into(); - - // make local queue congested, because it means additional db write - T::make_congested(); - }: { - send_xcm::>(dest, xcm).expect("message is sent") - } - verify { - assert!(Bridge::::get().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR); - } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 607394603466..89474bd53fcb 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -30,12 +30,9 @@ #![cfg_attr(not(feature = "std"), no_std)] -use bp_xcm_bridge_hub_router::{ - BridgeState, XcmChannelStatusProvider, MINIMAL_DELIVERY_FEE_FACTOR, -}; +use bp_xcm_bridge_hub::LocalXcmChannelManager; use codec::Encode; use frame_support::traits::Get; -use sp_core::H256; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; use sp_std::vec::Vec; use xcm::prelude::*; @@ -49,6 +46,9 @@ pub mod weights; mod mock; +/// Minimal delivery fee factor. +pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); + /// The factor that is used to increase current message fee factor when bridge experiencing /// some lags. const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05 @@ -82,6 +82,8 @@ pub mod pallet { /// Universal location of this runtime. type UniversalLocation: Get; + /// Relative location of the supported sibling bridge hub. + type SiblingBridgeHubLocation: Get; /// The bridged network that this config is for if specified. /// Also used for filtering `Bridges` by `BridgedNetworkId`. /// If not specified, allows all networks pass through. @@ -97,9 +99,8 @@ pub mod pallet { type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. type ToBridgeHubSender: SendXcm + InspectMessageQueues; - /// Underlying channel with the sibling bridge hub. It must match the channel, used - /// by the `Self::ToBridgeHubSender`. - type WithBridgeHubChannel: XcmChannelStatusProvider; + /// Local XCM channel manager. + type LocalXcmChannelManager: LocalXcmChannelManager; /// Additional fee that is paid for every byte of the outbound message. type ByteFee: Get; @@ -113,115 +114,95 @@ pub mod pallet { #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { - // TODO: make sure that `WithBridgeHubChannel::is_congested` returns true if either - // of XCM channels (outbound/inbound) is suspended. Because if outbound is suspended - // that is definitely congestion. If inbound is suspended, then we are not able to - // receive the "report_bridge_status" signal (that maybe sent by the bridge hub). - - // if the channel with sibling/child bridge hub is suspended, we don't change - // anything - if T::WithBridgeHubChannel::is_congested() { + // if XCM channel is still congested, we don't change anything + if T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { return T::WeightInfo::on_initialize_when_congested() } - // if bridge has reported congestion, we don't change anything - let mut bridge = Self::bridge(); - if bridge.is_congested { + // if we can't decrease the delivery fee factor anymore, we don't change anything + let mut delivery_fee_factor = Self::delivery_fee_factor(); + if delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { return T::WeightInfo::on_initialize_when_congested() } - // if fee factor is already minimal, we don't change anything - if bridge.delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { - return T::WeightInfo::on_initialize_when_congested() - } - - let previous_factor = bridge.delivery_fee_factor; - bridge.delivery_fee_factor = - MINIMAL_DELIVERY_FEE_FACTOR.max(bridge.delivery_fee_factor / EXPONENTIAL_FEE_BASE); + let previous_factor = delivery_fee_factor; + delivery_fee_factor = + MINIMAL_DELIVERY_FEE_FACTOR.max(delivery_fee_factor / EXPONENTIAL_FEE_BASE); log::info!( target: LOG_TARGET, - "Bridge queue is uncongested. Decreased fee factor from {} to {}", + "Bridge channel is uncongested. Decreased fee factor from {} to {}", previous_factor, - bridge.delivery_fee_factor, + delivery_fee_factor, ); + DeliveryFeeFactor::::put(delivery_fee_factor); - Bridge::::put(bridge); T::WeightInfo::on_initialize_when_non_congested() } } - #[pallet::call] - impl, I: 'static> Pallet { - /// Notification about congested bridge queue. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::report_bridge_status())] - pub fn report_bridge_status( - origin: OriginFor, - // this argument is not currently used, but to ease future migration, we'll keep it - // here - bridge_id: H256, - is_congested: bool, - ) -> DispatchResult { - let _ = T::BridgeHubOrigin::ensure_origin(origin)?; - - log::info!( - target: LOG_TARGET, - "Received bridge status from {:?}: congested = {}", - bridge_id, - is_congested, - ); - - Bridge::::mutate(|bridge| { - bridge.is_congested = is_congested; - }); - Ok(()) - } + /// Initialization value for the delivery fee factor. + #[pallet::type_value] + pub fn InitialFactor() -> FixedU128 { + MINIMAL_DELIVERY_FEE_FACTOR } - /// Bridge that we are using. + /// The number to multiply the base delivery fee by. + /// + /// This factor is shared by all bridges, served by this pallet. For example, if this + /// chain (`Config::UniversalLocation`) opens two bridges ( + /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(1000))` and + /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(2000))`), then they + /// both will be sharing the same fee factor. This is because both bridges are sharing + /// the same local XCM channel with the child/sibling bridge hub, which we are using + /// to detect congestion: /// - /// **bridges-v1** assumptions: all outbound messages through this router are using single lane - /// and to single remote consensus. If there is some other remote consensus that uses the same - /// bridge hub, the separate pallet instance shall be used, In `v2` we'll have all required - /// primitives (lane-id aka bridge-id, derived from XCM locations) to support multiple bridges - /// by the same pallet instance. + /// ```nocompile + /// ThisChain --- Local XCM chanel --> Sibling Bridge Hub ------ + /// | | + /// | | + /// | | + /// Lane1 Lane2 + /// | | + /// | | + /// | | + /// \ / | + /// Parachain1 <-- Local XCM channel --- Remote Bridge Hub <------ + /// | + /// | + /// Parachain1 <-- Local XCM channel --------- + /// ``` + /// + /// If at least one of other channels is congested, the local XCM channel with sibling + /// bridge hub eventually becomes congested too. And we have no means to detect - which + /// bridge exactly causes the congestion. So the best solution here is not to make + /// any differences between all bridges, started by this chain. #[pallet::storage] - #[pallet::getter(fn bridge)] - pub type Bridge, I: 'static = ()> = StorageValue<_, BridgeState, ValueQuery>; + #[pallet::getter(fn delivery_fee_factor)] + pub type DeliveryFeeFactor, I: 'static = ()> = + StorageValue<_, FixedU128, ValueQuery, InitialFactor>; impl, I: 'static> Pallet { /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. pub(crate) fn on_message_sent_to_bridge(message_size: u32) { - log::trace!( - target: LOG_TARGET, - "on_message_sent_to_bridge - message_size: {message_size:?}", - ); - let _ = Bridge::::try_mutate(|bridge| { - let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested(); - let is_bridge_congested = bridge.is_congested; - - // if outbound queue is not congested AND bridge has not reported congestion, do - // nothing - if !is_channel_with_bridge_hub_congested && !is_bridge_congested { - return Err(()) - } - - // ok - we need to increase the fee factor, let's do that - let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) - .saturating_mul(MESSAGE_SIZE_FEE_BASE); - let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); - let previous_factor = bridge.delivery_fee_factor; - bridge.delivery_fee_factor = - bridge.delivery_fee_factor.saturating_mul(total_factor); + // if outbound channel is not congested, do nothing + if !T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { + return + } + // ok - we need to increase the fee factor, let's do that + let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) + .saturating_mul(MESSAGE_SIZE_FEE_BASE); + let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); + DeliveryFeeFactor::::mutate(|f| { + let previous_factor = *f; + *f = f.saturating_mul(total_factor); log::info!( target: LOG_TARGET, "Bridge channel is congested. Increased fee factor from {} to {}", previous_factor, - bridge.delivery_fee_factor, + f, ); - - Ok(()) + *f }); } } @@ -259,17 +240,25 @@ impl, I: 'static> ExporterFor for Pallet { } // ensure that the message is sent to the expected bridged network and location. - let Some((bridge_hub_location, maybe_payment)) = - T::Bridges::exporter_for(network, remote_location, message) - else { - log::trace!( - target: LOG_TARGET, - "Router with bridged_network_id {:?} does not support bridging to network {:?} and remote_location {:?}!", - T::BridgedNetworkId::get(), - network, - remote_location, - ); - return None + let (bridge_hub_location, maybe_payment) = match T::Bridges::exporter_for( + network, + remote_location, + message, + ) { + Some((bridge_hub_location, maybe_payment)) + if bridge_hub_location.eq(&T::SiblingBridgeHubLocation::get()) => + (bridge_hub_location, maybe_payment), + _ => { + log::trace!( + target: LOG_TARGET, + "Router configured with bridged_network_id {:?} and sibling_bridge_hub_location: {:?} does not support bridging to network {:?} and remote_location {:?}!", + T::BridgedNetworkId::get(), + T::SiblingBridgeHubLocation::get(), + network, + remote_location, + ); + return None + }, }; // take `base_fee` from `T::Brides`, but it has to be the same `T::FeeAsset` @@ -279,8 +268,8 @@ impl, I: 'static> ExporterFor for Pallet { invalid_asset => { log::error!( target: LOG_TARGET, - "Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} which is not \ - compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", + "Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} \ + which is not compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", T::BridgedNetworkId::get(), T::FeeAsset::get(), invalid_asset, @@ -300,18 +289,18 @@ impl, I: 'static> ExporterFor for Pallet { let message_size = message.encoded_size(); let message_fee = (message_size as u128).saturating_mul(T::ByteFee::get()); let fee_sum = base_fee.saturating_add(message_fee); - let fee_factor = Self::bridge().delivery_fee_factor; - let fee = fee_factor.saturating_mul_int(fee_sum); + let fee_factor = Self::delivery_fee_factor(); + let fee = fee_factor.saturating_mul_int(fee_sum); let fee = if fee > 0 { Some((T::FeeAsset::get(), fee).into()) } else { None }; log::info!( target: LOG_TARGET, - "Validate send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", + "Going to send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", (network, remote_location), message_size, fee, - fee_factor + fee_factor, ); Some((bridge_hub_location, fee)) @@ -412,65 +401,39 @@ mod tests { use frame_support::traits::Hooks; use sp_runtime::traits::One; - fn congested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { - BridgeState { is_congested: true, delivery_fee_factor } - } - - fn uncongested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { - BridgeState { is_congested: false, delivery_fee_factor } - } - #[test] fn initial_fee_factor_is_one() { run_test(|| { - assert_eq!( - Bridge::::get(), - uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR), - ); + assert_eq!(DeliveryFeeFactor::::get(), MINIMAL_DELIVERY_FEE_FACTOR); }) } #[test] fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() { run_test(|| { - Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); - TestWithBridgeHubChannel::make_congested(); - - // it should not decrease, because xcm channel is congested - let old_bridge = XcmBridgeHubRouter::bridge(); - XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); - }) - } - - #[test] - fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_has_reported_congestion() { - run_test(|| { - Bridge::::put(congested_bridge(FixedU128::from_rational(125, 100))); + DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); - // it should not decrease, because bridge congested - let old_bridge = XcmBridgeHubRouter::bridge(); + // it should not decrease, because queue is congested + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); + assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), old_delivery_fee_factor); }) } #[test] fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { run_test(|| { - Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); + DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); - // it should eventually decreased to one - while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR { + // it shold eventually decreased to one + while XcmBridgeHubRouter::delivery_fee_factor() > MINIMAL_DELIVERY_FEE_FACTOR { XcmBridgeHubRouter::on_initialize(One::one()); } // verify that it doesn't decreases anymore XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!( - XcmBridgeHubRouter::bridge(), - uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR) - ); + assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), MINIMAL_DELIVERY_FEE_FACTOR); }) } @@ -577,7 +540,7 @@ mod tests { // but when factor is larger than one, it increases the fee, so it becomes: // `(BASE_FEE + BYTE_FEE * msg_size) * F + HRMP_FEE` let factor = FixedU128::from_rational(125, 100); - Bridge::::put(uncongested_bridge(factor)); + DeliveryFeeFactor::::put(factor); let expected_fee = (FixedU128::saturating_from_integer(BASE_FEE + BYTE_FEE * (msg_size as u128)) * factor) @@ -591,45 +554,29 @@ mod tests { } #[test] - fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() { + fn sent_message_doesnt_increase_factor_if_queue_is_uncongested() { run_test(|| { - let old_bridge = XcmBridgeHubRouter::bridge(); - assert_ok!(send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop)); + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + assert_eq!( + send_xcm::( + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), + vec![ClearOrigin].into(), + ) + .map(drop), + Ok(()), + ); assert!(TestToBridgeHubSender::is_message_sent()); - assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); + assert_eq!(old_delivery_fee_factor, XcmBridgeHubRouter::delivery_fee_factor()); }); } #[test] fn sent_message_increases_factor_if_xcm_channel_is_congested() { run_test(|| { - TestWithBridgeHubChannel::make_congested(); - - let old_bridge = XcmBridgeHubRouter::bridge(); - assert_ok!(send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop)); - - assert!(TestToBridgeHubSender::is_message_sent()); - assert!( - old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor - ); - }); - } - - #[test] - fn sent_message_increases_factor_if_bridge_has_reported_congestion() { - run_test(|| { - Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); - let old_bridge = XcmBridgeHubRouter::bridge(); + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); assert_ok!(send_xcm::( Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), vec![ClearOrigin].into(), @@ -637,9 +584,7 @@ mod tests { .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); - assert!( - old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor - ); + assert!(old_delivery_fee_factor < XcmBridgeHubRouter::delivery_fee_factor()); }); } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 3e2c1bb369cb..e829aae5e7d5 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -18,7 +18,7 @@ use crate as pallet_xcm_bridge_hub_router; -use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ construct_runtime, derive_impl, parameter_types, @@ -75,6 +75,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type WeightInfo = (); type UniversalLocation = UniversalLocation; + type SiblingBridgeHubLocation = SiblingBridgeHubLocation; type BridgedNetworkId = BridgedNetworkId; type Bridges = NetworkExportTable; type DestinationVersion = @@ -82,7 +83,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; - type WithBridgeHubChannel = TestWithBridgeHubChannel; + type LocalXcmChannelManager = TestLocalXcmChannelManager; type ByteFee = ConstU128; type FeeAsset = BridgeFeeAsset; @@ -147,17 +148,32 @@ impl InspectMessageQueues for TestToBridgeHubSender { } } -pub struct TestWithBridgeHubChannel; +pub struct TestLocalXcmChannelManager; -impl TestWithBridgeHubChannel { - pub fn make_congested() { - frame_support::storage::unhashed::put(b"TestWithBridgeHubChannel.Congested", &true); +impl TestLocalXcmChannelManager { + pub fn make_congested(with: &Location) { + frame_support::storage::unhashed::put( + &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], + &true, + ); } } -impl XcmChannelStatusProvider for TestWithBridgeHubChannel { - fn is_congested() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestWithBridgeHubChannel.Congested") +impl LocalXcmChannelManager for TestLocalXcmChannelManager { + type Error = (); + + fn is_congested(with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default( + &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], + ) + } + + fn suspend_bridge(_with: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) + } + + fn resume_bridge(_with: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index b0c8fc6252cd..d9a0426fecaf 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -52,8 +52,6 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn on_initialize_when_non_congested() -> Weight; fn on_initialize_when_congested() -> Weight; - fn report_bridge_status() -> Weight; - fn send_message() -> Weight; } /// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. @@ -61,30 +59,20 @@ pub trait WeightInfo { /// Those weights are test only and must never be used in production. pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) + /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) + /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), + /// added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `3518` - // Minimum execution time: 11_934 nanoseconds. - Weight::from_parts(12_201_000, 3518) + // Measured: `52` + // Estimated: `3517` + // Minimum execution time: 11_141 nanoseconds. + Weight::from_parts(11_339_000, 3517) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// @@ -92,117 +80,44 @@ impl WeightInfo for BridgeWeight { /// w:0) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `94` - // Estimated: `3559` - // Minimum execution time: 9_010 nanoseconds. - Weight::from_parts(9_594_000, 3559) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `1502` - // Minimum execution time: 10_427 nanoseconds. - Weight::from_parts(10_682_000, 1502) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 19_709 nanoseconds. - Weight::from_parts(20_110_000, 3517) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 4_239 nanoseconds. + Weight::from_parts(4_383_000, 3547).saturating_add(T::DbWeight::get().reads(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 /// w:0) - fn on_initialize_when_non_congested() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `3518` - // Minimum execution time: 11_934 nanoseconds. - Weight::from_parts(12_201_000, 3518) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) + /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn on_initialize_when_congested() -> Weight { + /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), + /// added: 511, mode: `MaxEncodedLen`) + fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `94` - // Estimated: `3559` - // Minimum execution time: 9_010 nanoseconds. - Weight::from_parts(9_594_000, 3559) + // Measured: `52` + // Estimated: `3517` + // Minimum execution time: 11_141 nanoseconds. + Weight::from_parts(11_339_000, 3517) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `1502` - // Minimum execution time: 10_427 nanoseconds. - Weight::from_parts(10_682_000, 1502) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 /// w:0) - fn send_message() -> Weight { + fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 19_709 nanoseconds. - Weight::from_parts(20_110_000, 3517) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 4_239 nanoseconds. + Weight::from_parts(4_383_000, 3547).saturating_add(RocksDbWeight::get().reads(1_u64)) } } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index e422b58f4fbd..a1c623cb0b38 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -37,6 +37,7 @@ xcm-executor = { workspace = true } pallet-balances = { workspace = true } sp-io = { workspace = true } bp-runtime = { features = ["test-helpers"], workspace = true } +bp-header-chain = { workspace = true } pallet-xcm-bridge-hub-router = { workspace = true } polkadot-parachain-primitives = { workspace = true } diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index 432896c25ac5..f88a825e41bb 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -18,16 +18,23 @@ //! bridge messages dispatcher. Internally, it just forwards inbound blob to the //! XCM-level blob dispatcher, which pushes message to some other queue (e.g. //! to HRMP queue with the sibling target chain). +//! +//! This code is executed at the target bridge hub. -use crate::{Config, Pallet, XcmAsPlainPayload, LOG_TARGET}; +use crate::{Config, Pallet, LOG_TARGET}; -use bp_messages::target_chain::{DispatchMessage, MessageDispatch}; +use bp_messages::{ + target_chain::{DispatchMessage, MessageDispatch}, + LaneId, +}; use bp_runtime::messages::MessageDispatchResult; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager, XcmAsPlainPayload}; use codec::{Decode, Encode}; use frame_support::{weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; use pallet_bridge_messages::{Config as BridgeMessagesConfig, WeightInfoExt}; use scale_info::TypeInfo; use sp_runtime::SaturatedConversion; +use xcm::prelude::*; use xcm_builder::{DispatchBlob, DispatchBlobError}; /// Message dispatch result type for single message. @@ -52,8 +59,12 @@ where type DispatchPayload = XcmAsPlainPayload; type DispatchLevelResult = XcmBlobMessageDispatchResult; - fn is_active() -> bool { - true + fn is_active(lane: LaneId) -> bool { + let bridge_id = BridgeId::from_lane_id(lane); + Pallet::::bridge(bridge_id) + .and_then(|bridge| bridge.bridge_origin_relative_location.try_as().cloned().ok()) + .map(|recipient: Location| !T::LocalXcmChannelManager::is_congested(&recipient)) + .unwrap_or(false) } fn dispatch_weight(message: &mut DispatchMessage) -> Weight { @@ -105,3 +116,103 @@ where MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::*, Bridges}; + + use bp_messages::{target_chain::DispatchMessageData, MessageKey}; + use bp_xcm_bridge_hub::{Bridge, BridgeState}; + + fn bridge_id() -> BridgeId { + BridgeId::from_lane_id(LaneId::new(1, 2)) + } + + fn run_test_with_opened_bridge(test: impl FnOnce()) { + run_test(|| { + Bridges::::insert( + bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new(Location::new(0, Here).into()), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + reserve: 0, + }, + ); + + test(); + }); + } + + fn invalid_message() -> DispatchMessage> { + DispatchMessage { + key: MessageKey { lane_id: LaneId::new(1, 2), nonce: 1 }, + data: DispatchMessageData { payload: Err(codec::Error::from("test")) }, + } + } + + fn valid_message() -> DispatchMessage> { + DispatchMessage { + key: MessageKey { lane_id: LaneId::new(1, 2), nonce: 1 }, + data: DispatchMessageData { payload: Ok(vec![42]) }, + } + } + + #[test] + fn dispatcher_is_inactive_when_channel_with_target_chain_is_congested() { + run_test_with_opened_bridge(|| { + TestLocalXcmChannelManager::make_congested(); + assert!(!XcmOverBridge::is_active(bridge_id().lane_id())); + }); + } + + #[test] + fn dispatcher_is_active_when_channel_with_target_chain_is_not_congested() { + run_test_with_opened_bridge(|| { + assert!(XcmOverBridge::is_active(bridge_id().lane_id())); + }); + } + + #[test] + fn dispatch_weight_is_zero_if_we_have_failed_to_decode_message() { + run_test(|| { + assert_eq!(XcmOverBridge::dispatch_weight(&mut invalid_message()), Weight::zero()); + }); + } + + #[test] + fn dispatch_weight_is_non_zero_if_we_have_decoded_message() { + run_test(|| { + assert_ne!(XcmOverBridge::dispatch_weight(&mut valid_message()), Weight::zero()); + }); + } + + #[test] + fn message_is_not_dispatched_when_we_have_failed_to_decode_message() { + run_test(|| { + assert_eq!( + XcmOverBridge::dispatch(invalid_message()), + MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, + }, + ); + assert!(!TestBlobDispatcher::is_dispatched()); + }); + } + + #[test] + fn message_is_dispatched_when_we_have_decoded_message() { + run_test(|| { + assert_eq!( + XcmOverBridge::dispatch(valid_message()), + MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::Dispatched, + }, + ); + assert!(TestBlobDispatcher::is_dispatched()); + }); + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 5262b289aea2..7848bafe2ed2 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -22,19 +22,32 @@ use crate::{Config, Pallet, LOG_TARGET}; -use bp_xcm_bridge_hub::XcmAsPlainPayload; +use crate::{BridgeOf, Bridges}; -use bp_messages::{source_chain::MessagesBridge, LaneId}; +use bp_messages::{ + source_chain::{MessagesBridge, OnMessagesDelivered}, + LaneId, MessageNonce, +}; +use bp_xcm_bridge_hub::{BridgeId, BridgeState, LocalXcmChannelManager, XcmAsPlainPayload}; use frame_support::traits::Get; use pallet_bridge_messages::{ Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet, }; +use sp_std::boxed::Box; use xcm::prelude::*; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::ExportXcm; +/// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we +/// suspend a bridge. +const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192; + +/// After we have suspended the bridge, we wait until number of messages in the outbound bridge +/// queue drops to this count, before sending resuming the bridge. +const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024; + /// An easy way to access `HaulBlobExporter`. -type PalletAsHaulBlobExporter = HaulBlobExporter< +pub type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, >::BridgedNetwork, >::DestinationVersion, @@ -48,7 +61,8 @@ where T: BridgeMessagesConfig, { type Ticket = ( - LaneId, + BridgeId, + BridgeOf, as MessagesBridge>::SendMessageArgs, XcmHash, ); @@ -64,7 +78,7 @@ where // let's save them before let bridge_origin_universal_location = universal_source.clone().take().ok_or(SendError::MissingArgument)?; - let bridge_destination_interior_location = + let bridge_destination_universal_location = destination.clone().take().ok_or(SendError::MissingArgument)?; // check if we are able to route the message. We use existing `HaulBlobExporter` for that. @@ -78,28 +92,22 @@ where message, )?; - // ok - now we know that the message may be routed by the pallet, let's prepare the - // destination universal location - let mut bridge_destination_universal_location: InteriorLocation = - GlobalConsensus(network).into(); - bridge_destination_universal_location - .append_with(bridge_destination_interior_location) - .map_err(|_| SendError::Unroutable)?; - - // .. and the origin relative location + // prepare the origin relative location let bridge_origin_relative_location = bridge_origin_universal_location.relative_to(&T::UniversalLocation::get()); // then we are able to compute the lane id used to send messages - let bridge_locations = Self::bridge_locations( + let locations = Self::bridge_locations( Box::new(bridge_origin_relative_location), Box::new(bridge_destination_universal_location.into()), ) .map_err(|_| SendError::Unroutable)?; + let bridge = Self::bridge(locations.bridge_id).ok_or(SendError::Unroutable)?; let bridge_message = - MessagesPallet::::validate_message(bridge_locations.lane_id, &blob).map_err( - |e| { + MessagesPallet::::validate_message(locations.bridge_id.lane_id(), &blob) + .map_err(|e| { + // TODO:(bridges-v2) - add test/std feature gate? match e { Error::LanesManager(ref ei) => log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), @@ -112,33 +120,180 @@ where log::error!( target: LOG_TARGET, - "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?}", + "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?} and laneId: {:?}", id, e, - bridge_locations, + locations, + locations.bridge_id.lane_id(), ); SendError::Transport("BridgeValidateError") - }, - )?; + })?; - Ok(((bridge_locations.lane_id, bridge_message, id), price)) + Ok(((locations.bridge_id, bridge, bridge_message, id), price)) } - fn deliver((lane_id, bridge_message, id): Self::Ticket) -> Result { + fn deliver( + (bridge_id, bridge, bridge_message, id): Self::Ticket, + ) -> Result { let artifacts = MessagesPallet::::send_message(bridge_message); log::info!( target: LOG_TARGET, "XCM message {:?} has been enqueued at bridge {:?} with nonce {}", id, - lane_id, + bridge_id, artifacts.nonce, ); + // maybe we need switch to congested state + Self::on_bridge_message_enqueued(bridge_id, bridge, artifacts.enqueued_messages); + Ok(id) } } +impl, I: 'static> OnMessagesDelivered for Pallet { + fn on_messages_delivered(lane_id: LaneId, enqueued_messages: MessageNonce) { + Self::on_bridge_messages_delivered(lane_id, enqueued_messages); + } +} + +impl, I: 'static> Pallet { + /// Called when new message is pushed onto outbound bridge queue. + fn on_bridge_message_enqueued( + bridge_id: BridgeId, + bridge: BridgeOf, + enqueued_messages: MessageNonce, + ) { + // if the bridge queue is not congested, we don't want to do anything + let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD; + if !is_congested { + return + } + + // TODO: https://github.com/paritytech/parity-bridges-common/issues/2006 we either need fishermens + // to watch this rule violation (suspended, but keep sending new messages), or we need a + // hard limit for that like other XCM queues have + + // check if the lane is already suspended. If it is, do nothing. We still accept new + // messages to the suspended bridge, hoping that it'll be actually suspended soon + if bridge.state == BridgeState::Suspended { + return + } + + // else - suspend the bridge + let bridge_origin_relative_location = match bridge.bridge_origin_relative_location.try_as() + { + Ok(bridge_origin_relative_location) => bridge_origin_relative_location, + Err(_) => { + log::debug!( + target: LOG_TARGET, + "Failed to convert the bridge {:?} origin location {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + ); + + return + }, + }; + let suspend_result = + T::LocalXcmChannelManager::suspend_bridge(bridge_origin_relative_location, bridge_id); + match suspend_result { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "Suspended the bridge {:?}, originated by the {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + ); + }, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to suspended the bridge {:?}, originated by the {:?}: {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + e, + ); + + return + }, + } + + // and remember that we have suspended the bridge + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + } + + /// Must be called whenever we receive a message delivery confirmation. + fn on_bridge_messages_delivered(lane_id: LaneId, enqueued_messages: MessageNonce) { + // if the bridge queue is still congested, we don't want to do anything + let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; + if is_congested { + return + } + + // if we have not suspended the bridge before (or it is closed), we don't want to do + // anything + let bridge_id = BridgeId::from_lane_id(lane_id); + let bridge = match Self::bridge(bridge_id) { + Some(bridge) if bridge.state == BridgeState::Suspended => bridge, + _ => { + // if there is no bridge or it has been closed, then we don't need to send resume + // signal to the local origin - it has closed bridge itself, so it should have + // alrady pruned everything else + return + }, + }; + + // else - resume the bridge + let bridge_origin_relative_location = (*bridge.bridge_origin_relative_location).try_into(); + let bridge_origin_relative_location = match bridge_origin_relative_location { + Ok(bridge_origin_relative_location) => bridge_origin_relative_location, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to convert the bridge {:?} location: {:?}", + lane_id, + e, + ); + + return + }, + }; + + let resume_result = + T::LocalXcmChannelManager::resume_bridge(&bridge_origin_relative_location, bridge_id); + match resume_result { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "Resumed the bridge {:?}, originated by the {:?}", + lane_id, + bridge_origin_relative_location, + ); + }, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to resume the bridge {:?}, originated by the {:?}: {:?}", + lane_id, + bridge_origin_relative_location, + e, + ); + + return + }, + } + + // and forget that we have previously suspended the bridge + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Opened; + }); + } +} + /// Dummy implementation of the `HaulBlob` trait that is never called. /// /// We are using `HaulBlobExporter`, which requires `HaulBlob` implementation. It assumes that @@ -146,7 +301,7 @@ where /// else. But bridge messages pallet may have a dedicated channel (lane) for every pair of bridged /// chains. So we are using our own `ExportXcm` implementation, but to utilize `HaulBlobExporter` we /// still need this `DummyHaulBlob`. -struct DummyHaulBlob; +pub struct DummyHaulBlob; impl HaulBlob for DummyHaulBlob { fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> { @@ -159,9 +314,8 @@ mod tests { use super::*; use crate::{mock::*, Bridges, LanesManagerOf}; - use bp_messages::{LaneState, OutboundLaneData}; use bp_runtime::RangeInclusiveExt; - use bp_xcm_bridge_hub::{Bridge, BridgeState}; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; @@ -173,33 +327,56 @@ mod tests { BridgedRelativeDestination::get() } - #[test] - fn proper_lane_is_used_by_export_xcm() { - run_test(|| { - // open expected outbound lane - let origin = OpenBridgeOrigin::sibling_parachain_origin(); - let with = bridged_asset_hub_location(); - let locations = - XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); - - let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + fn universal_destination() -> InteriorLocation { + [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into() + } + + fn open_lane() -> BridgeLocations { + // open expected outbound lane + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let with = bridged_asset_hub_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).is_ok() { assert!(lanes_manager - .active_outbound_lane(locations.lane_id) + .active_outbound_lane(locations.bridge_id.lane_id()) .unwrap() .queued_messages() .is_empty()); - // now let's try to enqueue message using our `ExportXcm` implementation - export_xcm::( - BridgedRelayNetwork::get(), - 0, - locations.bridge_origin_universal_location, - locations.bridge_destination_universal_location.split_first().0, - vec![Instruction::ClearOrigin].into(), - ) - .unwrap(); - }) + // insert bridge + Bridges::::insert( + locations.bridge_id, + Bridge { + bridge_origin_relative_location: Box::new( + Location::new(1, Parachain(SIBLING_ASSET_HUB_ID)).into(), + ), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + reserve: 0, + }, + ); + } + + *locations + } + + fn open_lane_and_send_regular_message() -> BridgeId { + let locations = open_lane(); + + // now let's try to enqueue message using our `ExportXcm` implementation + export_xcm::( + BridgedRelayNetwork::get(), + 0, + locations.bridge_origin_universal_location, + locations.bridge_destination_universal_location, + vec![Instruction::ClearOrigin].into(), + ) + .unwrap(); + + locations.bridge_id } #[test] @@ -217,6 +394,96 @@ mod tests { }); } + #[test] + fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + }); + } + + #[test] + fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + + open_lane_and_send_regular_message(); + assert!(TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + bridge_id.lane_id(), + OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_it_was_not_suspended_before() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + XcmOverBridge::on_bridge_messages_delivered( + bridge_id.lane_id(), + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn bridge_is_resumed_when_enough_messages_are_delivered() { + run_test(|| { + let bridge_id = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + bridge_id.lane_id(), + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + }); + } + #[test] fn export_fails_if_argument_is_missing() { run_test(|| { @@ -286,13 +553,9 @@ mod tests { run_test(|| { // valid routable destination let dest = Location::new(2, BridgedUniversalDestination::get()); - let expected_lane_id = test_lane_id(); // open bridge - pallet_bridge_messages::OutboundLanes::::insert( - expected_lane_id, - OutboundLaneData { state: LaneState::Opened, ..Default::default() }, - ); + let expected_lane_id = open_lane().bridge_id.lane_id(); // check before - no messages assert_eq!( diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 957ac73933fe..e9ccdfbf8e8e 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -51,20 +51,26 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bp_messages::{LaneId, LaneState, MessageNonce}; +use bp_messages::{LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; use bp_xcm_bridge_hub::{ - bridge_locations, Bridge, BridgeLocations, BridgeLocationsError, BridgeState, XcmAsPlainPayload, + bridge_locations, Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, + LocalXcmChannelManager, +}; +use frame_support::{ + traits::{Currency, ReservableCurrency}, + DefaultNoBound, }; -use frame_support::traits::{Currency, ReservableCurrency}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; use sp_runtime::traits::Zero; +use sp_std::{boxed::Box, vec::Vec}; use xcm::prelude::*; use xcm_builder::DispatchBlob; use xcm_executor::traits::ConvertLocation; pub use dispatcher::XcmBlobMessageDispatchResult; +pub use exporter::PalletAsHaulBlobExporter; pub use pallet::*; mod dispatcher; @@ -101,7 +107,7 @@ pub mod pallet { /// `BridgedNetworkId` consensus. type BridgeMessagesPalletInstance: 'static; - /// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`). + /// Price of single message export to the bridged consensus (`Self::BridgedNetwork`). type MessageExportPrice: Get; /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; @@ -125,6 +131,8 @@ pub mod pallet { /// Currency used to pay for bridge registration. type NativeCurrency: ReservableCurrency; + /// Local XCM channel manager. + type LocalXcmChannelManager: LocalXcmChannelManager; /// XCM-level dispatcher for inbound bridge messages. type BlobDispatcher: DispatchBlob; } @@ -145,10 +153,10 @@ pub mod pallet { impl, I: 'static> Hooks> for Pallet { fn integrity_test() { assert!( - Self::bridged_network_id().is_ok(), - "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", - T::BridgedNetwork::get() - ) + Self::bridged_network_id().is_ok(), + "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", + T::BridgedNetwork::get() + ) } } @@ -189,7 +197,7 @@ pub mod pallet { .map_err(|_| Error::::FailedToReserveBridgeReserve)?; // save bridge metadata - Bridges::::try_mutate(locations.lane_id, |bridge| match bridge { + Bridges::::try_mutate(locations.bridge_id, |bridge| match bridge { Some(_) => Err(Error::::BridgeAlreadyExists), None => { *bridge = Some(BridgeOf:: { @@ -207,24 +215,24 @@ pub mod pallet { // create new lanes. Under normal circumstances, following calls shall never fail let lanes_manager = LanesManagerOf::::new(); lanes_manager - .create_inbound_lane(locations.lane_id) + .create_inbound_lane(locations.bridge_id.lane_id()) .map_err(Error::::LanesManager)?; lanes_manager - .create_outbound_lane(locations.lane_id) + .create_outbound_lane(locations.bridge_id.lane_id()) .map_err(Error::::LanesManager)?; // write something to log log::trace!( target: LOG_TARGET, "Bridge {:?} between {:?} and {:?} has been opened", - locations.lane_id, + locations.bridge_id, locations.bridge_origin_universal_location, locations.bridge_destination_universal_location, ); // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, local_endpoint: Box::new(locations.bridge_origin_universal_location), remote_endpoint: Box::new(locations.bridge_destination_universal_location), }); @@ -265,7 +273,7 @@ pub mod pallet { // update bridge metadata - this also guarantees that the bridge is in the proper state let bridge = - Bridges::::try_mutate_exists(locations.lane_id, |bridge| match bridge { + Bridges::::try_mutate_exists(locations.bridge_id, |bridge| match bridge { Some(bridge) => { bridge.state = BridgeState::Closed; Ok(bridge.clone()) @@ -276,10 +284,10 @@ pub mod pallet { // close inbound and outbound lanes let lanes_manager = LanesManagerOf::::new(); let mut inbound_lane = lanes_manager - .any_state_inbound_lane(locations.lane_id) + .any_state_inbound_lane(locations.bridge_id.lane_id()) .map_err(Error::::LanesManager)?; let mut outbound_lane = lanes_manager - .any_state_outbound_lane(locations.lane_id) + .any_state_outbound_lane(locations.bridge_id.lane_id()) .map_err(Error::::LanesManager)?; // now prune queued messages @@ -304,7 +312,7 @@ pub mod pallet { log::trace!( target: LOG_TARGET, "Bridge {:?} between {:?} and {:?} is closing. {} messages remaining", - locations.lane_id, + locations.bridge_id, locations.bridge_origin_universal_location, locations.bridge_destination_universal_location, enqueued_messages, @@ -312,7 +320,7 @@ pub mod pallet { // deposit the `ClosingBridge` event Self::deposit_event(Event::::ClosingBridge { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, pruned_messages, enqueued_messages, }); @@ -323,7 +331,7 @@ pub mod pallet { // else we have pruned all messages, so lanes and the bridge itself may gone inbound_lane.purge(); outbound_lane.purge(); - Bridges::::remove(locations.lane_id); + Bridges::::remove(locations.bridge_id); // unreserve remaining amount let failed_to_unreserve = @@ -335,7 +343,7 @@ pub mod pallet { target: LOG_TARGET, "Failed to unreserve {:?} during ridge {:?} closure", failed_to_unreserve, - locations.lane_id, + locations.bridge_id, ); } @@ -343,14 +351,14 @@ pub mod pallet { log::trace!( target: LOG_TARGET, "Bridge {:?} between {:?} and {:?} has been closed", - locations.lane_id, + locations.bridge_id, locations.bridge_origin_universal_location, locations.bridge_destination_universal_location, ); // deposit the `BridgePruned` event Self::deposit_event(Event::::BridgePruned { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, pruned_messages, }); @@ -406,8 +414,56 @@ pub mod pallet { /// All registered bridges. #[pallet::storage] + #[pallet::getter(fn bridge)] pub type Bridges, I: 'static = ()> = - StorageMap<_, Identity, LaneId, BridgeOf>; + StorageMap<_, Identity, BridgeId, BridgeOf>; + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig, I: 'static = ()> { + /// Opened bridges. + /// + /// Keep in mind that we are **NOT** reserving any amount for the bridges, opened at + /// genesis. We are **NOT** opening lanes, used by this bridge. It all must be done using + /// other pallets genesis configuration or some other means. + pub opened_bridges: Vec<(Location, InteriorLocation)>, + /// Dummy marker. + pub phantom: sp_std::marker::PhantomData<(T, I)>, + } + + #[pallet::genesis_build] + impl, I: 'static> BuildGenesisConfig for GenesisConfig + where + T: frame_system::Config>>, + { + fn build(&self) { + for (bridge_origin_relative_location, bridge_destination_universal_location) in + &self.opened_bridges + { + let locations = Pallet::::bridge_locations( + Box::new(bridge_origin_relative_location.clone()), + Box::new(bridge_destination_universal_location.clone().into()), + ) + .expect("Invalid genesis configuration"); + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + &locations.bridge_origin_relative_location, + ) + .expect("Invalid genesis configuration"); + + Bridges::::insert( + locations.bridge_id, + Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location.into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + reserve: Zero::zero(), + }, + ); + } + } + } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -418,13 +474,13 @@ pub mod pallet { local_endpoint: Box, /// Universal location of remote bridge endpoint. remote_endpoint: Box, - /// Bridge and its lane identifier. - lane_id: LaneId, + /// Bridge identifier. + bridge_id: BridgeId, }, /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. ClosingBridge { - /// Bridge and its lane identifier. - lane_id: LaneId, + /// Bridge identifier. + bridge_id: BridgeId, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, /// Number of enqueued messages that need to be pruned in follow up calls. @@ -433,8 +489,8 @@ pub mod pallet { /// Bridge has been closed and pruned from the runtime storage. It now may be reopened /// again by any participant. BridgePruned { - /// Bridge and its lane identifier. - lane_id: LaneId, + /// Bridge identifier. + bridge_id: BridgeId, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, }, @@ -448,6 +504,8 @@ pub mod pallet { InvalidBridgeOriginAccount, /// The bridge is already registered in this pallet. BridgeAlreadyExists, + /// The local origin already owns a maximal number of bridges. + TooManyBridgesForLocalOrigin, /// Trying to close already closed bridge. BridgeAlreadyClosed, /// Lanes manager error. @@ -466,6 +524,7 @@ mod tests { use super::*; use mock::*; + use bp_messages::LaneId; use frame_support::{assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; use frame_system::{EventRecord, Phase}; @@ -496,11 +555,11 @@ mod tests { bridge_owner_account, reserve, }; - Bridges::::insert(locations.lane_id, bridge.clone()); + Bridges::::insert(locations.bridge_id, bridge.clone()); let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_inbound_lane(locations.lane_id).unwrap(); - lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + lanes_manager.create_inbound_lane(locations.bridge_id.lane_id()).unwrap(); + lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).unwrap(); (bridge, *locations) } @@ -635,7 +694,7 @@ mod tests { ); Bridges::::insert( - locations.lane_id, + locations.bridge_id, Bridge { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location.into(), @@ -669,7 +728,7 @@ mod tests { let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_inbound_lane(locations.lane_id).unwrap(); + lanes_manager.create_inbound_lane(locations.bridge_id.lane_id()).unwrap(); assert_noop!( XcmOverBridge::open_bridge( origin.clone(), @@ -678,8 +737,11 @@ mod tests { Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), ); - lanes_manager.active_inbound_lane(locations.lane_id).unwrap().purge(); - lanes_manager.create_outbound_lane(locations.lane_id).unwrap(); + lanes_manager + .active_inbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .purge(); + lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).unwrap(); assert_noop!( XcmOverBridge::open_bridge(origin, Box::new(bridged_asset_hub_location().into()),), Error::::LanesManager( @@ -716,13 +778,13 @@ mod tests { .unwrap(); // ensure that there's no bridge and lanes in the storage - assert_eq!(Bridges::::get(locations.lane_id), None); + assert_eq!(Bridges::::get(locations.bridge_id), None); assert_eq!( - lanes_manager.active_inbound_lane(locations.lane_id).map(drop), + lanes_manager.active_inbound_lane(locations.bridge_id.lane_id()).map(drop), Err(LanesManagerError::UnknownInboundLane) ); assert_eq!( - lanes_manager.active_outbound_lane(locations.lane_id).map(drop), + lanes_manager.active_outbound_lane(locations.bridge_id.lane_id()).map(drop), Err(LanesManagerError::UnknownOutboundLane) ); @@ -745,7 +807,7 @@ mod tests { // ensure that everything has been set up in the runtime storage assert_eq!( - Bridges::::get(locations.lane_id), + Bridges::::get(locations.bridge_id), Some(Bridge { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location.into() @@ -756,11 +818,15 @@ mod tests { }), ); assert_eq!( - lanes_manager.active_inbound_lane(locations.lane_id).map(|l| l.state()), + lanes_manager + .active_inbound_lane(locations.bridge_id.lane_id()) + .map(|l| l.state()), Ok(LaneState::Opened) ); assert_eq!( - lanes_manager.active_outbound_lane(locations.lane_id).map(|l| l.state()), + lanes_manager + .active_outbound_lane(locations.bridge_id.lane_id()) + .map(|l| l.state()), Ok(LaneState::Opened) ); assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); @@ -772,7 +838,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, local_endpoint: Box::new(locations.bridge_origin_universal_location), remote_endpoint: Box::new( locations.bridge_destination_universal_location @@ -833,7 +899,10 @@ mod tests { let (_, locations) = mock_open_bridge_from(origin.clone()); let lanes_manager = LanesManagerOf::::new(); - lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().purge(); + lanes_manager + .any_state_inbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .purge(); assert_noop!( XcmOverBridge::close_bridge( origin.clone(), @@ -842,10 +911,16 @@ mod tests { ), Error::::LanesManager(LanesManagerError::UnknownInboundLane), ); - lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().purge(); + lanes_manager + .any_state_outbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .purge(); let (_, locations) = mock_open_bridge_from(origin.clone()); - lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().purge(); + lanes_manager + .any_state_outbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .purge(); assert_noop!( XcmOverBridge::close_bridge( origin, @@ -870,7 +945,7 @@ mod tests { // enqueue some messages for _ in 0..32 { - enqueue_message(locations.lane_id); + enqueue_message(locations.bridge_id.lane_id()); } // now call the `close_bridge`, which will only partially prune messages @@ -884,20 +959,26 @@ mod tests { // are pruned, but funds are not unreserved let lanes_manager = LanesManagerOf::::new(); assert_eq!( - Bridges::::get(locations.lane_id).map(|b| b.state), + Bridges::::get(locations.bridge_id).map(|b| b.state), Some(BridgeState::Closed) ); assert_eq!( - lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().state(), + lanes_manager + .any_state_inbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .state(), LaneState::Closed ); assert_eq!( - lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().state(), + lanes_manager + .any_state_outbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .state(), LaneState::Closed ); assert_eq!( lanes_manager - .any_state_outbound_lane(locations.lane_id) + .any_state_outbound_lane(locations.bridge_id.lane_id()) .unwrap() .queued_messages() .checked_len(), @@ -910,7 +991,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, pruned_messages: 16, enqueued_messages: 16, }), @@ -927,20 +1008,26 @@ mod tests { // nothing is changed (apart from the pruned messages) assert_eq!( - Bridges::::get(locations.lane_id).map(|b| b.state), + Bridges::::get(locations.bridge_id).map(|b| b.state), Some(BridgeState::Closed) ); assert_eq!( - lanes_manager.any_state_inbound_lane(locations.lane_id).unwrap().state(), + lanes_manager + .any_state_inbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .state(), LaneState::Closed ); assert_eq!( - lanes_manager.any_state_outbound_lane(locations.lane_id).unwrap().state(), + lanes_manager + .any_state_outbound_lane(locations.bridge_id.lane_id()) + .unwrap() + .state(), LaneState::Closed ); assert_eq!( lanes_manager - .any_state_outbound_lane(locations.lane_id) + .any_state_outbound_lane(locations.bridge_id.lane_id()) .unwrap() .queued_messages() .checked_len(), @@ -953,7 +1040,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, pruned_messages: 8, enqueued_messages: 8, }), @@ -970,13 +1057,13 @@ mod tests { ),); // there's no traces of bridge in the runtime storage and funds are unreserved - assert_eq!(Bridges::::get(locations.lane_id).map(|b| b.state), None); + assert_eq!(Bridges::::get(locations.bridge_id).map(|b| b.state), None); assert_eq!( - lanes_manager.any_state_inbound_lane(locations.lane_id).map(drop), + lanes_manager.any_state_inbound_lane(locations.bridge_id.lane_id()).map(drop), Err(LanesManagerError::UnknownInboundLane) ); assert_eq!( - lanes_manager.any_state_outbound_lane(locations.lane_id).map(drop), + lanes_manager.any_state_outbound_lane(locations.bridge_id.lane_id()).map(drop), Err(LanesManagerError::UnknownOutboundLane) ); assert_eq!( @@ -989,7 +1076,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { - lane_id: locations.lane_id, + bridge_id: locations.bridge_id, pruned_messages: 8, }), topics: vec![], diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index cfaf3998e259..15c59b0af16f 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -22,11 +22,12 @@ use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, ChainWithMessages, LaneId, MessageNonce, }; -use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId}; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{Everything, Get, NeverEnsureOrigin}, + traits::{Everything, NeverEnsureOrigin}, weights::RuntimeDbWeight, }; use sp_core::H256; @@ -88,16 +89,18 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestMessagesWeights; + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingChain; + type BridgedHeaderChain = BridgedHeaderChain; + type OutboundPayload = Vec; type InboundPayload = Vec; + type DeliveryPayments = (); type DeliveryConfirmationPayments = (); type OnMessagesDelivered = (); - type MessageDispatch = TestMessageDispatch; - type ThisChain = ThisUnderlyingChain; - type BridgedChain = BridgedUnderlyingChain; - type BridgedHeaderChain = (); + type MessageDispatch = TestMessageDispatch; } pub struct TestMessagesWeights; @@ -124,8 +127,8 @@ impl pallet_bridge_messages::WeightInfo for TestMessagesWeights { fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { Weight::zero() } - fn receive_single_n_bytes_message_proof_with_dispatch(_: u32) -> Weight { - Weight::zero() + fn receive_single_n_bytes_message_proof_with_dispatch(_n: u32) -> Weight { + Weight::from_parts(1, 0) } } @@ -190,6 +193,8 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type BridgeReserve = BridgeDeposit; type NativeCurrency = Balances; + type LocalXcmChannelManager = TestLocalXcmChannelManager; + type BlobDispatcher = TestBlobDispatcher; } @@ -197,17 +202,17 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type WeightInfo = (); type UniversalLocation = UniversalLocation; + type SiblingBridgeHubLocation = BridgeHubLocation; type BridgedNetworkId = BridgedRelayNetwork; type Bridges = NetworkExportTable; type DestinationVersion = AlwaysLatest; type BridgeHubOrigin = NeverEnsureOrigin; type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; + type LocalXcmChannelManager = TestLocalXcmChannelManager; type ByteFee = ConstU128<0>; type FeeAsset = BridgeFeeAsset; - - type WithBridgeHubChannel = (); } pub struct XcmConfig; @@ -374,10 +379,51 @@ impl EnsureOrigin for OpenBridgeOrigin { } } +pub struct TestLocalXcmChannelManager; + +impl TestLocalXcmChannelManager { + pub fn make_congested() { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Congested", &true); + } + + pub fn is_bridge_suspened() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Suspended") + } + + pub fn is_bridge_resumed() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Resumed") + } +} + +impl LocalXcmChannelManager for TestLocalXcmChannelManager { + type Error = (); + + fn is_congested(_with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") + } + + fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Suspended", &true); + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Resumed", &true); + Ok(()) + } +} + pub struct TestBlobDispatcher; +impl TestBlobDispatcher { + pub fn is_dispatched() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestBlobDispatcher.Dispatched") + } +} + impl DispatchBlob for TestBlobDispatcher { fn dispatch_blob(_blob: Vec) -> Result<(), DispatchBlobError> { + frame_support::storage::unhashed::put(b"TestBlobDispatcher.Dispatched", &true); Ok(()) } } @@ -445,6 +491,15 @@ impl ChainWithMessages for BridgedUnderlyingChain { const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; } +pub struct BridgedHeaderChain; +impl bp_header_chain::HeaderChain for BridgedHeaderChain { + fn finalized_header_state_root( + _hash: HashOf, + ) -> Option> { + unreachable!() + } +} + /// Test message dispatcher. pub struct TestMessageDispatch; @@ -458,8 +513,9 @@ impl MessageDispatch for TestMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); - fn is_active() -> bool { - frame_support::storage::unhashed::take::(&(b"inactive").encode()[..]) != Some(false) + fn is_active(lane: LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) } fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index b351cef42afa..67868ff7c7cd 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -103,7 +103,7 @@ pub trait MessageDispatch { /// /// We check it in the messages delivery transaction prologue. So if it becomes `false` /// after some portion of messages is already dispatched, it doesn't fail the whole transaction. - fn is_active() -> bool; + fn is_active(lane: LaneId) -> bool; /// Estimate dispatch weight. /// @@ -179,7 +179,7 @@ impl MessageDispatch for ForbidInboundMessages bool { + fn is_active(_: LaneId) -> bool { false } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index fa8f9ef0b76f..9949108af21f 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] codec = { features = ["derive"], default-features = false, workspace = true } scale-info = { features = ["derive"], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } # Bridge Dependencies bp-messages = { path = "../messages", default-features = false } @@ -33,6 +34,7 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", + "serde/std", "sp-std/std", "xcm/std", ] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 44dbb9698241..3aabe2201530 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -27,62 +27,112 @@ use frame_support::{ RuntimeDebugNoBound, }; use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; use sp_std::boxed::Box; -use xcm::{latest::prelude::*, VersionedLocation}; +use xcm::{latest::prelude::*, VersionedInteriorLocation, VersionedLocation}; /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; -/// A manager of XCM communication channels between the bridge hub and parent/sibling chains -/// that have opened bridges at this bridge hub. -/// -/// We use this interface to suspend and resume channels programmatically to implement backpressure -/// mechanism for bridge queues. -#[allow(clippy::result_unit_err)] // XCM uses `Result<(), ()>` everywhere -pub trait LocalXcmChannelManager { - // TODO: https://github.com/paritytech/parity-bridges-common/issues/2255 - // check following assumptions. They are important at least for following cases: - // 1) we now close the associated outbound lane when misbehavior is reported. If we'll keep - // handling inbound XCM messages after the `suspend_inbound_channel`, they will be dropped - // 2) the sender will be able to enqueue message to othe lanes if we won't stop handling inbound - // XCM immediately. He even may open additional bridges - - /// Stop handling new incoming XCM messages from given bridge `owner` (parent/sibling chain). - /// - /// We assume that the channel will be suspended immediately, but we don't mind if inbound - /// messages will keep piling up here for some time. Once this is communicated to the - /// `owner` chain (in any form), we expect it to stop sending messages to us and queue - /// messages at that `owner` chain instead. - /// - /// We expect that: +/// Bridge identifier. +#[derive( + Clone, + Copy, + Decode, + Default, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + RuntimeDebug, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct BridgeId(LaneId); + +impl BridgeId { + /// Create bridge identifier from two universal locations. /// - /// - no more incoming XCM messages from the `owner` will be processed until further - /// `resume_inbound_channel` call; + /// The fact that we are using versioned locations here means that XCM version upgrades must + /// be coordinated at all involved chains (at source and target chains + at bridge hubs). + /// Otherwise messages may simply be dropped anywhere on its path to the target chain. + pub fn new( + universal_location1: &VersionedInteriorLocation, + universal_location2: &VersionedInteriorLocation, + ) -> Self { + // a tricky helper struct that adds required `Ord` support for + // `VersionedInteriorMultiLocation` + #[derive(Eq, PartialEq, Ord, PartialOrd)] + struct EncodedVersionedInteriorMultiLocation(sp_std::vec::Vec); + + impl Encode for EncodedVersionedInteriorMultiLocation { + fn encode(&self) -> sp_std::vec::Vec { + self.0.clone() + } + } + + Self(LaneId::new( + EncodedVersionedInteriorMultiLocation(universal_location1.encode()), + EncodedVersionedInteriorMultiLocation(universal_location2.encode()), + )) + } + + /// Creates bridge id using lane id. /// - /// - soon after the call, the channel will switch to the state when incoming messages are - /// piling up at the sending chain, not at the bridge hub. + /// **ATTENTION**: this function may be removed in the future. + pub fn from_lane_id(lane_id: LaneId) -> Self { + // in the future we may want to keep using the same lane identifiers if we'll be upgrading + // the XCM version (and `VersionedInteriorMultiLocation` will change) + Self(lane_id) + } + + /// Return lane id, used by this bridge. + pub fn lane_id(&self) -> LaneId { + self.0 + } +} + +/// Local XCM channel manager. +pub trait LocalXcmChannelManager { + /// Error that may be returned when suspending/resuming the bridge. + type Error: sp_std::fmt::Debug; + + /// Returns true if the channel with given location is currently congested. /// - /// This method shall not fail if the channel is already suspended. - fn suspend_inbound_channel(owner: Location) -> Result<(), ()>; + /// The `with` is guaranteed to be in the same consensus. However, it may point to something + /// below the chain level - like the constract or pallet instance, for example. + fn is_congested(with: &Location) -> bool; - /// Start handling incoming messages from from given bridge `owner` (parent/sibling chain) - /// again. + /// Suspend the bridge, opened by given origin. /// - /// The channel is assumed to be suspended by the previous `suspend_inbound_channel` call, - /// however we don't check it anywhere. + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the constract or pallet instance, for example. + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; + + /// Resume the previously suspended bridge, opened by given origin. /// - /// This method shall not fail if the channel is already resumed. - fn resume_inbound_channel(owner: Location) -> Result<(), ()>; + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the constract or pallet instance, for example. + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; } impl LocalXcmChannelManager for () { - fn suspend_inbound_channel(_owner: Location) -> Result<(), ()> { + type Error = (); + + fn is_congested(_with: &Location) -> bool { + false + } + + fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { Ok(()) } - fn resume_inbound_channel(_owner: Location) -> Result<(), ()> { - Err(()) + fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) } } @@ -91,6 +141,11 @@ impl LocalXcmChannelManager for () { pub enum BridgeState { /// Bridge is opened. Associated lanes are also opened. Opened, + /// Bridge is suspended. Associated lanes are opened. + /// + /// We keep accepting messages to the bridge. The only difference with the `Opened` state + /// is that we have sent the "Suspended" message/signal to the local bridge origin. + Suspended, /// Bridge is closed. Associated lanes are also closed. /// After all outbound messages will be pruned, the bridge will vanish without any traces. Closed, @@ -122,7 +177,7 @@ pub struct BridgeLocations { /// Universal (unique) location of other side of the bridge. pub bridge_destination_universal_location: InteriorLocation, /// An identifier of the dedicated bridge message lane. - pub lane_id: LaneId, + pub bridge_id: BridgeId, } /// Errors that may happen when we check bridge locations. @@ -217,16 +272,16 @@ pub fn bridge_locations( // `GlobalConsensus` and we know that the `bridge_origin_universal_location` // is also within the `GlobalConsensus`. So we know that the lane id will be // the same on both ends of the bridge - let lane_id = LaneId::new( - bridge_origin_universal_location.clone(), - bridge_destination_universal_location.clone(), + let bridge_id = BridgeId::new( + &bridge_origin_universal_location.clone().into(), + &bridge_destination_universal_location.clone().into(), ); Ok(Box::new(BridgeLocations { bridge_origin_relative_location: *bridge_origin_relative_location, bridge_origin_universal_location, bridge_destination_universal_location, - lane_id, + bridge_id, })) } @@ -259,14 +314,14 @@ mod tests { assert_eq!( locations, Ok(Box::new(BridgeLocations { - bridge_origin_relative_location: test.bridge_origin_relative_location.clone(), + bridge_origin_relative_location: test.bridge_origin_relative_location, bridge_origin_universal_location: test.bridge_origin_universal_location.clone(), bridge_destination_universal_location: test .bridge_destination_universal_location .clone(), - lane_id: LaneId::new( - test.bridge_origin_universal_location, - test.bridge_destination_universal_location, + bridge_id: BridgeId::new( + &test.bridge_origin_universal_location.into(), + &test.bridge_destination_universal_location.into(), ), })), ); @@ -421,7 +476,7 @@ mod tests { bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), }); - assert_eq!(locations1.lane_id, locations2.lane_id); + assert_eq!(locations1.bridge_id, locations2.bridge_id); } #[test] @@ -441,7 +496,7 @@ mod tests { bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), }); - assert_eq!(locations1.lane_id, locations2.lane_id); + assert_eq!(locations1.bridge_id, locations2.bridge_id); } // negative tests From 0b481d874655a8255a25ef4cdc3805c46bccaed3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 27 Dec 2023 19:13:05 +0300 Subject: [PATCH 16/95] emit events from bridge hub router (#2760) --- .../modules/xcm-bridge-hub-router/src/lib.rs | 57 ++++++++++++++++++- .../modules/xcm-bridge-hub-router/src/mock.rs | 10 +++- bridges/modules/xcm-bridge-hub/src/mock.rs | 1 + 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 89474bd53fcb..55fa3be2e675 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -77,6 +77,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Benchmarks results from runtime we're plugged into. type WeightInfo: WeightInfo; @@ -134,6 +137,10 @@ pub mod pallet { previous_factor, delivery_fee_factor, ); + Self::deposit_event(Event::DeliveryFeeFactorDecreased { + new_value: delivery_fee_factor, + }); + DeliveryFeeFactor::::put(delivery_fee_factor); T::WeightInfo::on_initialize_when_non_congested() @@ -202,10 +209,26 @@ pub mod pallet { previous_factor, f, ); + Self::deposit_event(Event::DeliveryFeeFactorIncreased { new_value: *f }); *f }); } } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// Delivery fee factor has been decreased. + DeliveryFeeFactorDecreased { + /// New value of the `DeliveryFeeFactor`. + new_value: FixedU128, + }, + /// Delivery fee factor has been increased. + DeliveryFeeFactorIncreased { + /// New value of the `DeliveryFeeFactor`. + new_value: FixedU128, + }, + } } /// We'll be using `SovereignPaidRemoteExporter` to send remote messages over the sibling/child @@ -399,6 +422,7 @@ mod tests { use mock::*; use frame_support::traits::Hooks; + use frame_system::{EventRecord, Phase}; use sp_runtime::traits::One; #[test] @@ -418,13 +442,16 @@ mod tests { let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); XcmBridgeHubRouter::on_initialize(One::one()); assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), old_delivery_fee_factor); + + assert_eq!(System::events(), vec![]); }) } #[test] fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { run_test(|| { - DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); + let initial_fee_factor = FixedU128::from_rational(125, 100); + DeliveryFeeFactor::::put(initial_fee_factor); // it shold eventually decreased to one while XcmBridgeHubRouter::delivery_fee_factor() > MINIMAL_DELIVERY_FEE_FACTOR { @@ -434,6 +461,19 @@ mod tests { // verify that it doesn't decreases anymore XcmBridgeHubRouter::on_initialize(One::one()); assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), MINIMAL_DELIVERY_FEE_FACTOR); + + // check emitted event + let first_system_event = System::events().first().cloned(); + assert_eq!( + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter(Event::DeliveryFeeFactorDecreased { + new_value: initial_fee_factor / EXPONENTIAL_FEE_BASE, + }), + topics: vec![], + }) + ); }) } @@ -568,6 +608,8 @@ mod tests { assert!(TestToBridgeHubSender::is_message_sent()); assert_eq!(old_delivery_fee_factor, XcmBridgeHubRouter::delivery_fee_factor()); + + assert_eq!(System::events(), vec![]); }); } @@ -585,6 +627,19 @@ mod tests { assert!(TestToBridgeHubSender::is_message_sent()); assert!(old_delivery_fee_factor < XcmBridgeHubRouter::delivery_fee_factor()); + + // check emitted event + let first_system_event = System::events().first().cloned(); + assert!(matches!( + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter( + Event::DeliveryFeeFactorIncreased { .. } + ), + .. + }) + )); }); } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index e829aae5e7d5..e3a52879d856 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -44,7 +44,7 @@ construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, - XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage}, + XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage, Event}, } } @@ -72,6 +72,7 @@ impl frame_system::Config for TestRuntime { } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type UniversalLocation = UniversalLocation; @@ -185,7 +186,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - new_test_ext().execute_with(test) + new_test_ext().execute_with(|| { + System::set_block_number(1); + System::reset_events(); + + test() + }) } pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 15c59b0af16f..c8f5fdb6668a 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -199,6 +199,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type UniversalLocation = UniversalLocation; From 0c3eaf802386898e367d948e1f63938a67de1f95 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 2 Aug 2023 11:57:44 +0300 Subject: [PATCH 17/95] use saturating_len where possible (#2316) --- bridges/modules/xcm-bridge-hub/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index e9ccdfbf8e8e..949c01733f32 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -308,7 +308,7 @@ pub mod pallet { outbound_lane.set_state(LaneState::Closed); // write something to log - let enqueued_messages = outbound_lane.queued_messages().checked_len().unwrap_or(0); + let enqueued_messages = outbound_lane.queued_messages().saturating_len(); log::trace!( target: LOG_TARGET, "Bridge {:?} between {:?} and {:?} is closing. {} messages remaining", From 3ab2661cfb1dd54180d22f05496142f523f6b474 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 22 Sep 2023 12:33:45 +0300 Subject: [PATCH 18/95] move messages_call_ext.rs from bridge-runtime-common to pallet-bridge-messages (#2580) --- .../extensions/check_obsolete_extension.rs | 6 +- .../extensions/refund_relayer_extension.rs | 21 ++- bridges/bin/runtime-common/src/lib.rs | 1 - .../messages/src/call_ext.rs} | 137 +++++++----------- bridges/modules/messages/src/lib.rs | 2 + 5 files changed, 67 insertions(+), 100 deletions(-) rename bridges/{bin/runtime-common/src/messages_call_ext.rs => modules/messages/src/call_ext.rs} (85%) diff --git a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs index df75092af6e8..e401fc446174 100644 --- a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs @@ -18,15 +18,13 @@ //! obsolete (duplicated) data or do not pass some additional pallet-specific //! checks. -use crate::{ - extensions::refund_relayer_extension::RefundableParachainId, - messages_call_ext::MessagesCallSubType, -}; +use crate::extensions::refund_relayer_extension::RefundableParachainId; use bp_relayers::ExplicitOrAccountParams; use bp_runtime::Parachain; use pallet_bridge_grandpa::{ BridgedBlockNumber, CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, }; +use pallet_bridge_messages::CallSubType as MessagesCallSubType; use pallet_bridge_parachains::{ CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, }; diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 42a3d118854d..42b1648779f4 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -19,9 +19,6 @@ //! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). -use crate::messages_call_ext::{ - CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, -}; use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Chain, Parachain, RangeInclusiveExt, StaticStrProvider}; @@ -35,7 +32,10 @@ use frame_support::{ use pallet_bridge_grandpa::{ CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, }; -use pallet_bridge_messages::Config as MessagesConfig; +use pallet_bridge_messages::{ + CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, + CallSubType as MessagesCallSubType, Config as MessagesConfig, +}; use pallet_bridge_parachains::{ BoundedBridgeGrandpaConfig, CallSubType as ParachainsCallSubType, Config as ParachainsConfig, RelayBlockNumber, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, @@ -935,13 +935,7 @@ where #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::{ - messages_call_ext::{ - BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, - UnrewardedRelayerOccupation, - }, - mock::*, - }; + use crate::mock::*; use bp_header_chain::StoredHeaderDataBuilder; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, @@ -959,7 +953,10 @@ pub(crate) mod tests { weights::Weight, }; use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet}; - use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet}; + use pallet_bridge_messages::{ + BaseMessagesProofInfo, Call as MessagesCall, Pallet as MessagesPallet, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, + }; use pallet_bridge_parachains::{ Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, }; diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 3e3394688f18..de9ee1b0bbbc 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -23,7 +23,6 @@ pub mod extensions; pub mod messages_api; pub mod messages_benchmarking; -pub mod messages_call_ext; pub mod parachains_benchmarking; mod mock; diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/modules/messages/src/call_ext.rs similarity index 85% rename from bridges/bin/runtime-common/src/messages_call_ext.rs rename to bridges/modules/messages/src/call_ext.rs index 2101e2a5ffce..a7e1d4d347a6 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/modules/messages/src/call_ext.rs @@ -16,12 +16,13 @@ //! Helpers for easier manipulation of call processing with signed extensions. +use crate::{BridgedChainOf, Config, InboundLanes, OutboundLanes, Pallet, LOG_TARGET}; + use bp_messages::{ target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, MessageNonce, }; use bp_runtime::{AccountIdOf, OwnedBridgeModule}; use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; -use pallet_bridge_messages::{BridgedChainOf, Config, Pallet}; use sp_runtime::{transaction_validity::TransactionValidity, RuntimeDebug}; use sp_std::ops::RangeInclusive; @@ -145,11 +146,10 @@ impl, I: 'static> CallHelper { pub fn was_successful(info: &CallInfo) -> bool { match info { CallInfo::ReceiveMessagesProof(info) => { - let inbound_lane_data = - match pallet_bridge_messages::InboundLanes::::get(info.base.lane_id) { - Some(inbound_lane_data) => inbound_lane_data, - None => return false, - }; + let inbound_lane_data = match InboundLanes::::get(info.base.lane_id) { + Some(inbound_lane_data) => inbound_lane_data, + None => return false, + }; if info.base.bundled_range.is_empty() { let post_occupation = unrewarded_relayers_occupation::(&inbound_lane_data); @@ -164,11 +164,10 @@ impl, I: 'static> CallHelper { inbound_lane_data.last_delivered_nonce() == *info.base.bundled_range.end() }, CallInfo::ReceiveMessagesDeliveryProof(info) => { - let outbound_lane_data = - match pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id) { - Some(outbound_lane_data) => outbound_lane_data, - None => return false, - }; + let outbound_lane_data = match OutboundLanes::::get(info.0.lane_id) { + Some(outbound_lane_data) => outbound_lane_data, + None => return false, + }; outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end() }, } @@ -176,7 +175,7 @@ impl, I: 'static> CallHelper { } /// Trait representing a call that is a sub type of `pallet_bridge_messages::Call`. -pub trait MessagesCallSubType, I: 'static>: +pub trait CallSubType, I: 'static>: IsSubType, T>> { /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call. @@ -217,15 +216,13 @@ impl< Call: IsSubType, T>>, T: frame_system::Config + Config, I: 'static, - > MessagesCallSubType for T::RuntimeCall + > CallSubType for T::RuntimeCall { fn receive_messages_proof_info(&self) -> Option { - if let Some(pallet_bridge_messages::Call::::receive_messages_proof { - ref proof, - .. - }) = self.is_sub_type() + if let Some(crate::Call::::receive_messages_proof { ref proof, .. }) = + self.is_sub_type() { - let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane)?; + let inbound_lane_data = InboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -243,14 +240,13 @@ impl< } fn receive_messages_delivery_proof_info(&self) -> Option { - if let Some(pallet_bridge_messages::Call::::receive_messages_delivery_proof { + if let Some(crate::Call::::receive_messages_delivery_proof { ref proof, ref relayers_state, .. }) = self.is_sub_type() { - let outbound_lane_data = - pallet_bridge_messages::OutboundLanes::::get(proof.lane)?; + let outbound_lane_data = OutboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: proof.lane, @@ -294,7 +290,7 @@ impl< match self.call_info() { Some(proof_info) if is_pallet_halted => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting messages transaction on halted pallet: {:?}", proof_info ); @@ -306,7 +302,7 @@ impl< .is_obsolete(T::MessageDispatch::is_active(proof_info.base.lane_id)) => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting obsolete messages delivery transaction: {:?}", proof_info ); @@ -317,7 +313,7 @@ impl< if proof_info.is_obsolete() => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting obsolete messages confirmation transaction: {:?}", proof_info, ); @@ -351,10 +347,7 @@ fn unrewarded_relayers_occupation, I: 'static>( #[cfg(test)] mod tests { use super::*; - use crate::{ - messages_call_ext::MessagesCallSubType, - mock::{BridgedUnderlyingChain, DummyMessageDispatch, TestRuntime, ThisChainRuntimeCall}, - }; + use crate::tests::mock::*; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState, @@ -367,38 +360,30 @@ mod tests { } fn fill_unrewarded_relayers() { - let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(test_lane_id()).unwrap(); - for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { + let mut inbound_lane_state = InboundLanes::::get(test_lane_id()).unwrap(); + for n in 0..BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { begin: n + 1, end: n + 1 }, }); } - pallet_bridge_messages::InboundLanes::::insert( - test_lane_id(), - inbound_lane_state, - ); + InboundLanes::::insert(test_lane_id(), inbound_lane_state); } fn fill_unrewarded_messages() { - let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(test_lane_id()).unwrap(); + let mut inbound_lane_state = InboundLanes::::get(test_lane_id()).unwrap(); inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { begin: 1, - end: BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + end: BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }); - pallet_bridge_messages::InboundLanes::::insert( - test_lane_id(), - inbound_lane_state, - ); + InboundLanes::::insert(test_lane_id(), inbound_lane_state); } fn deliver_message_10() { - pallet_bridge_messages::InboundLanes::::insert( + InboundLanes::::insert( test_lane_id(), bp_messages::InboundLaneData { state: LaneState::Opened, @@ -412,35 +397,26 @@ mod tests { nonces_start: bp_messages::MessageNonce, nonces_end: bp_messages::MessageNonce, ) -> bool { - ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_proof { - relayer_id_at_bridged_chain: 42, - messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) - as u32, - dispatch_weight: frame_support::weights::Weight::zero(), - proof: Box::new(FromBridgedChainMessagesProof { - bridged_header_hash: Default::default(), - storage_proof: Default::default(), - lane: test_lane_id(), - nonces_start, - nonces_end, - }), - }, - ) + RuntimeCall::Messages(crate::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: 42, + messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) as u32, + dispatch_weight: frame_support::weights::Weight::zero(), + proof: Box::new(FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: test_lane_id(), + nonces_start, + nonces_end, + }), + }) .check_obsolete_call() .is_ok() } fn run_test(test: impl Fn() -> T) -> T { sp_io::TestExternalities::new(Default::default()).execute_with(|| { - pallet_bridge_messages::InboundLanes::::insert( - test_lane_id(), - InboundLaneData::opened(), - ); - pallet_bridge_messages::OutboundLanes::::insert( - test_lane_id(), - OutboundLaneData::opened(), - ); + InboundLanes::::insert(test_lane_id(), InboundLaneData::opened()); + OutboundLanes::::insert(test_lane_id(), OutboundLaneData::opened()); test() }) } @@ -492,7 +468,7 @@ mod tests { // => tx is accepted, but we have inactive dispatcher, so... deliver_message_10(); - DummyMessageDispatch::deactivate(test_lane_id()); + TestMessageDispatch::deactivate(test_lane_id()); assert!(!validate_message_delivery(11, 15)); }); } @@ -522,8 +498,8 @@ mod tests { run_test(|| { fill_unrewarded_messages(); assert!(validate_message_delivery( - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - 1 + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - 1 )); }); } @@ -539,7 +515,7 @@ mod tests { } fn confirm_message_10() { - pallet_bridge_messages::OutboundLanes::::insert( + OutboundLanes::::insert( test_lane_id(), bp_messages::OutboundLaneData { state: LaneState::Opened, @@ -551,19 +527,14 @@ mod tests { } fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool { - ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_delivery_proof { - proof: FromBridgedChainMessagesDeliveryProof { - bridged_header_hash: Default::default(), - storage_proof: Default::default(), - lane: test_lane_id(), - }, - relayers_state: UnrewardedRelayersState { - last_delivered_nonce, - ..Default::default() - }, + RuntimeCall::Messages(crate::Call::::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: test_lane_id(), }, - ) + relayers_state: UnrewardedRelayersState { last_delivered_nonce, ..Default::default() }, + }) .check_obsolete_call() .is_ok() } @@ -623,7 +594,7 @@ mod tests { free_message_slots: if is_empty { 0 } else { - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX }, }, }, diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 03fae73f2552..3d89494f7463 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -72,6 +72,7 @@ use codec::{Decode, Encode}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound}; use sp_std::{marker::PhantomData, prelude::*}; +mod call_ext; mod inbound_lane; mod lanes_manager; mod outbound_lane; @@ -84,6 +85,7 @@ pub mod weights; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; +pub use call_ext::*; pub use pallet::*; #[cfg(feature = "test-helpers")] pub use tests::*; From e0bc5bdc1cc177916079a2b1063e06e194b8cce1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 25 Sep 2023 13:31:17 +0300 Subject: [PATCH 19/95] moved all call-related definitions to primitives (#2583) --- .../extensions/check_obsolete_extension.rs | 5 +- .../extensions/refund_relayer_extension.rs | 25 ++- bridges/modules/grandpa/src/call_ext.rs | 43 +---- bridges/modules/messages/src/call_ext.rs | 162 ++++------------- bridges/modules/parachains/src/call_ext.rs | 20 +-- bridges/modules/parachains/src/lib.rs | 2 +- .../primitives/header-chain/src/call_info.rs | 97 +++++++++++ bridges/primitives/header-chain/src/lib.rs | 37 +--- bridges/primitives/messages/src/call_info.rs | 164 ++++++++++++++++++ bridges/primitives/messages/src/lib.rs | 33 +--- .../primitives/parachains/src/call_info.rs | 59 +++++++ bridges/primitives/parachains/src/lib.rs | 22 +-- 12 files changed, 388 insertions(+), 281 deletions(-) create mode 100644 bridges/primitives/header-chain/src/call_info.rs create mode 100644 bridges/primitives/messages/src/call_info.rs create mode 100644 bridges/primitives/parachains/src/call_info.rs diff --git a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs index e401fc446174..433ab7916892 100644 --- a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs @@ -19,15 +19,14 @@ //! checks. use crate::extensions::refund_relayer_extension::RefundableParachainId; +use bp_parachains::SubmitParachainHeadsInfo; use bp_relayers::ExplicitOrAccountParams; use bp_runtime::Parachain; use pallet_bridge_grandpa::{ BridgedBlockNumber, CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, }; use pallet_bridge_messages::CallSubType as MessagesCallSubType; -use pallet_bridge_parachains::{ - CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, -}; +use pallet_bridge_parachains::{CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper}; use pallet_bridge_relayers::Pallet as RelayersPallet; use sp_runtime::{ traits::{Get, PhantomData, UniqueSaturatedInto}, diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 42b1648779f4..1418c8aea3a9 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -19,7 +19,9 @@ //! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). -use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; +use bp_header_chain::SubmitFinalityProofInfo; +use bp_messages::{ChainWithMessages, LaneId, MessageNonce, MessagesCallInfo}; +use bp_parachains::SubmitParachainHeadsInfo; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Chain, Parachain, RangeInclusiveExt, StaticStrProvider}; use codec::{Codec, Decode, Encode}; @@ -29,16 +31,13 @@ use frame_support::{ weights::Weight, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; -use pallet_bridge_grandpa::{ - CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, -}; +use pallet_bridge_grandpa::{CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper}; use pallet_bridge_messages::{ - CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, - CallSubType as MessagesCallSubType, Config as MessagesConfig, + CallHelper as MessagesCallHelper, CallSubType as MessagesCallSubType, Config as MessagesConfig, }; use pallet_bridge_parachains::{ BoundedBridgeGrandpaConfig, CallSubType as ParachainsCallSubType, Config as ParachainsConfig, - RelayBlockNumber, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, + RelayBlockNumber, SubmitParachainHeadsHelper, }; use pallet_bridge_relayers::{ Config as RelayersConfig, Pallet as RelayersPallet, WeightInfoExt as _, @@ -939,9 +938,10 @@ pub(crate) mod tests { use bp_header_chain::StoredHeaderDataBuilder; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState, - MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, DeliveredMessages, + InboundLaneData, LaneState, MessageNonce, MessagesOperatingMode, OutboundLaneData, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayer, + UnrewardedRelayerOccupation, UnrewardedRelayersState, }; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; @@ -953,10 +953,7 @@ pub(crate) mod tests { weights::Weight, }; use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet}; - use pallet_bridge_messages::{ - BaseMessagesProofInfo, Call as MessagesCall, Pallet as MessagesPallet, - ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, - }; + use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet}; use pallet_bridge_parachains::{ Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, }; diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index f08eb4c5d1ab..5690b8b4b18c 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -18,7 +18,10 @@ use crate::{ weights::WeightInfo, BestFinalized, BridgedBlockNumber, BridgedHeader, Config, CurrentAuthoritySet, Error, FreeHeadersRemaining, Pallet, }; -use bp_header_chain::{justification::GrandpaJustification, submit_finality_proof_limits_extras}; +use bp_header_chain::{ + justification::GrandpaJustification, submit_finality_proof_limits_extras, + SubmitFinalityProofInfo, +}; use bp_runtime::{BlockNumberOf, Chain, OwnedBridgeModule}; use frame_support::{ dispatch::CallableCallFor, @@ -32,33 +35,6 @@ use sp_runtime::{ RuntimeDebug, SaturatedConversion, }; -/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. -#[derive(Copy, Clone, PartialEq, RuntimeDebug)] -pub struct SubmitFinalityProofInfo { - /// Number of the finality target. - pub block_number: N, - /// An identifier of the validators set that has signed the submitted justification. - /// It might be `None` if deprecated version of the `submit_finality_proof` is used. - pub current_set_id: Option, - /// If `true`, then the call proves new **mandatory** header. - pub is_mandatory: bool, - /// If `true`, then the call must be free (assuming that everything else is valid) to - /// be treated as valid. - pub is_free_execution_expected: bool, - /// Extra weight that we assume is included in the call. - /// - /// We have some assumptions about headers and justifications of the bridged chain. - /// We know that if our assumptions are correct, then the call must not have the - /// weight above some limit. The fee paid for weight above that limit, is never refunded. - pub extra_weight: Weight, - /// Extra size (in bytes) that we assume are included in the call. - /// - /// We have some assumptions about headers and justifications of the bridged chain. - /// We know that if our assumptions are correct, then the call must not have the - /// weight above some limit. The fee paid for bytes above that limit, is never refunded. - pub extra_size: u32, -} - /// Verified `SubmitFinalityProofInfo`. #[derive(Copy, Clone, PartialEq, RuntimeDebug)] pub struct VerifiedSubmitFinalityProofInfo { @@ -69,13 +45,6 @@ pub struct VerifiedSubmitFinalityProofInfo { pub improved_by: N, } -impl SubmitFinalityProofInfo { - /// Returns `true` if call size/weight is below our estimations for regular calls. - pub fn fits_limits(&self) -> bool { - self.extra_weight.is_zero() && self.extra_size.is_zero() - } -} - /// Helper struct that provides methods for working with the `SubmitFinalityProof` call. pub struct SubmitFinalityProofHelper, I: 'static> { _phantom_data: sp_std::marker::PhantomData<(T, I)>, @@ -336,9 +305,9 @@ mod tests { TestRuntime, }, BestFinalized, Config, CurrentAuthoritySet, FreeHeadersRemaining, PalletOperatingMode, - StoredAuthoritySet, SubmitFinalityProofInfo, WeightInfo, + StoredAuthoritySet, WeightInfo, }; - use bp_header_chain::ChainWithGrandpa; + use bp_header_chain::{ChainWithGrandpa, SubmitFinalityProofInfo}; use bp_runtime::{BasicOperatingMode, HeaderId}; use bp_test_utils::{ make_default_justification, make_justification_for_header, JustificationGeneratorParams, diff --git a/bridges/modules/messages/src/call_ext.rs b/bridges/modules/messages/src/call_ext.rs index a7e1d4d347a6..8e021c8e5e24 100644 --- a/bridges/modules/messages/src/call_ext.rs +++ b/bridges/modules/messages/src/call_ext.rs @@ -19,119 +19,15 @@ use crate::{BridgedChainOf, Config, InboundLanes, OutboundLanes, Pallet, LOG_TARGET}; use bp_messages::{ - target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, MessageNonce, + target_chain::MessageDispatch, BaseMessagesProofInfo, ChainWithMessages, InboundLaneData, + LaneId, MessageNonce, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, + ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, }; use bp_runtime::{AccountIdOf, OwnedBridgeModule}; use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; -use sp_runtime::{transaction_validity::TransactionValidity, RuntimeDebug}; -use sp_std::ops::RangeInclusive; - -/// Generic info about a messages delivery/confirmation proof. -#[derive(PartialEq, RuntimeDebug)] -pub struct BaseMessagesProofInfo { - /// Message lane, used by the call. - pub lane_id: LaneId, - /// Nonces of messages, included in the call. - /// - /// For delivery transaction, it is nonces of bundled messages. For confirmation - /// transaction, it is nonces that are to be confirmed during the call. - pub bundled_range: RangeInclusive, - /// Nonce of the best message, stored by this chain before the call is dispatched. - /// - /// For delivery transaction, it is the nonce of best delivered message before the call. - /// For confirmation transaction, it is the nonce of best confirmed message before the call. - pub best_stored_nonce: MessageNonce, -} - -impl BaseMessagesProofInfo { - /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. - fn appends_to_stored_nonce(&self) -> bool { - Some(*self.bundled_range.start()) == self.best_stored_nonce.checked_add(1) - } -} - -/// Occupation state of the unrewarded relayers vector. -#[derive(PartialEq, RuntimeDebug)] -#[cfg_attr(test, derive(Default))] -pub struct UnrewardedRelayerOccupation { - /// The number of remaining unoccupied entries for new relayers. - pub free_relayer_slots: MessageNonce, - /// The number of messages that we are ready to accept. - pub free_message_slots: MessageNonce, -} - -/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesProofInfo { - /// Base messages proof info - pub base: BaseMessagesProofInfo, - /// State of unrewarded relayers vector. - pub unrewarded_relayers: UnrewardedRelayerOccupation, -} - -impl ReceiveMessagesProofInfo { - /// Returns true if: - /// - /// - either inbound lane is ready to accept bundled messages; - /// - /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed - /// messages and/or unrewarded relayers. - fn is_obsolete(&self, is_dispatcher_active: bool) -> bool { - // if dispatcher is inactive, we don't accept any delivery transactions - if !is_dispatcher_active { - return true - } - - // transactions with zero bundled nonces are not allowed, unless they're message - // delivery transactions, which brings reward confirmations required to unblock - // the lane - if self.base.bundled_range.is_empty() { - let empty_transactions_allowed = - // we allow empty transactions when we can't accept delivery from new relayers - self.unrewarded_relayers.free_relayer_slots == 0 || - // or if we can't accept new messages at all - self.unrewarded_relayers.free_message_slots == 0; - - return !empty_transactions_allowed - } - - // otherwise we require bundled messages to continue stored range - !self.base.appends_to_stored_nonce() - } -} - -/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); - -impl ReceiveMessagesDeliveryProofInfo { - /// Returns true if outbound lane is ready to accept confirmations of bundled messages. - fn is_obsolete(&self) -> bool { - self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() - } -} - -/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call -/// which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub enum CallInfo { - /// Messages delivery call info. - ReceiveMessagesProof(ReceiveMessagesProofInfo), - /// Messages delivery confirmation call info. - ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), -} - -impl CallInfo { - /// Returns range of messages, bundled with the call. - pub fn bundled_messages(&self) -> RangeInclusive { - match *self { - Self::ReceiveMessagesProof(ref info) => info.base.bundled_range.clone(), - Self::ReceiveMessagesDeliveryProof(ref info) => info.0.bundled_range.clone(), - } - } -} +use sp_runtime::transaction_validity::TransactionValidity; -/// Helper struct that provides methods for working with a call supported by `CallInfo`. +/// Helper struct that provides methods for working with a call supported by `MessagesCallInfo`. pub struct CallHelper, I: 'static> { _phantom_data: sp_std::marker::PhantomData<(T, I)>, } @@ -143,9 +39,9 @@ impl, I: 'static> CallHelper { /// /// - call is `receive_messages_delivery_proof` and all messages confirmations have been /// received. - pub fn was_successful(info: &CallInfo) -> bool { + pub fn was_successful(info: &MessagesCallInfo) -> bool { match info { - CallInfo::ReceiveMessagesProof(info) => { + MessagesCallInfo::ReceiveMessagesProof(info) => { let inbound_lane_data = match InboundLanes::::get(info.base.lane_id) { Some(inbound_lane_data) => inbound_lane_data, None => return false, @@ -163,7 +59,7 @@ impl, I: 'static> CallHelper { inbound_lane_data.last_delivered_nonce() == *info.base.bundled_range.end() }, - CallInfo::ReceiveMessagesDeliveryProof(info) => { + MessagesCallInfo::ReceiveMessagesDeliveryProof(info) => { let outbound_lane_data = match OutboundLanes::::get(info.0.lane_id) { Some(outbound_lane_data) => outbound_lane_data, None => return false, @@ -185,13 +81,13 @@ pub trait CallSubType, I: 'static>: /// a `ReceiveMessagesDeliveryProof` call. fn receive_messages_delivery_proof_info(&self) -> Option; - /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call. - fn call_info(&self) -> Option; + fn call_info(&self) -> Option; - /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call, if the call is for the provided lane. - fn call_info_for(&self, lane_id: LaneId) -> Option; + fn call_info_for(&self, lane_id: LaneId) -> Option; /// Ensures that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call: /// @@ -263,23 +159,23 @@ impl< None } - fn call_info(&self) -> Option { + fn call_info(&self) -> Option { if let Some(info) = self.receive_messages_proof_info() { - return Some(CallInfo::ReceiveMessagesProof(info)) + return Some(MessagesCallInfo::ReceiveMessagesProof(info)) } if let Some(info) = self.receive_messages_delivery_proof_info() { - return Some(CallInfo::ReceiveMessagesDeliveryProof(info)) + return Some(MessagesCallInfo::ReceiveMessagesDeliveryProof(info)) } None } - fn call_info_for(&self, lane_id: LaneId) -> Option { + fn call_info_for(&self, lane_id: LaneId) -> Option { self.call_info().filter(|info| { let actual_lane_id = match info { - CallInfo::ReceiveMessagesProof(info) => info.base.lane_id, - CallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, + MessagesCallInfo::ReceiveMessagesProof(info) => info.base.lane_id, + MessagesCallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, }; actual_lane_id == lane_id }) @@ -297,7 +193,7 @@ impl< return sp_runtime::transaction_validity::InvalidTransaction::Call.into() }, - Some(CallInfo::ReceiveMessagesProof(proof_info)) + Some(MessagesCallInfo::ReceiveMessagesProof(proof_info)) if proof_info .is_obsolete(T::MessageDispatch::is_active(proof_info.base.lane_id)) => { @@ -309,7 +205,7 @@ impl< return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() }, - Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info)) + Some(MessagesCallInfo::ReceiveMessagesDeliveryProof(proof_info)) if proof_info.is_obsolete() => { log::trace!( @@ -582,7 +478,7 @@ mod tests { bundled_range: RangeInclusive, is_empty: bool, ) -> bool { - CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( + CallHelper::::was_successful(&MessagesCallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { lane_id: test_lane_id(), @@ -643,13 +539,15 @@ mod tests { } fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { - CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( - ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: test_lane_id(), - bundled_range, - best_stored_nonce: 0, // doesn't matter for `was_successful` - }), - )) + CallHelper::::was_successful( + &MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: test_lane_id(), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }, + )), + ) } #[test] diff --git a/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index 0f77eaf2c5a9..b67da03a6315 100644 --- a/bridges/modules/parachains/src/call_ext.rs +++ b/bridges/modules/parachains/src/call_ext.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{Config, GrandpaPalletOf, Pallet, RelayBlockHash, RelayBlockNumber}; +use crate::{Config, GrandpaPalletOf, Pallet, RelayBlockNumber}; use bp_header_chain::HeaderChain; -use bp_parachains::BestParaHeadHash; -use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use bp_parachains::{BestParaHeadHash, SubmitParachainHeadsInfo}; use bp_runtime::{HeaderId, OwnedBridgeModule}; use frame_support::{ dispatch::CallableCallFor, @@ -30,21 +29,6 @@ use sp_runtime::{ RuntimeDebug, }; -/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. -#[derive(PartialEq, RuntimeDebug)] -pub struct SubmitParachainHeadsInfo { - /// Number and hash of the finalized relay block that has been used to prove parachain - /// finality. - pub at_relay_block: HeaderId, - /// Parachain identifier. - pub para_id: ParaId, - /// Hash of the bundled parachain head. - pub para_head_hash: ParaHash, - /// If `true`, then the call must be free (assuming that everything else is valid) to - /// be treated as valid. - pub is_free_execution_expected: bool, -} - /// Verified `SubmitParachainHeadsInfo`. #[derive(PartialEq, RuntimeDebug)] pub struct VerifiedSubmitParachainHeadsInfo { diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index e2c30ce9aecc..9d8ced5e1b3f 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -28,7 +28,7 @@ pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; use bp_header_chain::{HeaderChain, HeaderChainError}; -use bp_parachains::{ParaInfo, ParaStoredHeaderData}; +use bp_parachains::{ParaInfo, ParaStoredHeaderData, SubmitParachainHeadsInfo}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain}; use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound}; diff --git a/bridges/primitives/header-chain/src/call_info.rs b/bridges/primitives/header-chain/src/call_info.rs new file mode 100644 index 000000000000..6f880e939414 --- /dev/null +++ b/bridges/primitives/header-chain/src/call_info.rs @@ -0,0 +1,97 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-grandpa` pallet. + +use crate::{justification, InitializationData}; + +use bp_runtime::HeaderOf; +use codec::{Decode, Encode}; +use frame_support::weights::Weight; +use scale_info::TypeInfo; +use sp_consensus_grandpa::SetId; +use sp_runtime::{ + traits::{Header as HeaderT, Zero}, + RuntimeDebug, +}; +use sp_std::boxed::Box; + +/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeGrandpaCall { + /// `pallet-bridge-grandpa::Call::submit_finality_proof` + #[codec(index = 0)] + submit_finality_proof { + /// The header that we are going to finalize. + finality_target: Box
, + /// Finality justification for the `finality_target`. + justification: justification::GrandpaJustification
, + }, + /// `pallet-bridge-grandpa::Call::initialize` + #[codec(index = 1)] + initialize { + /// All data, required to initialize the pallet. + init_data: InitializationData
, + }, + /// `pallet-bridge-grandpa::Call::submit_finality_proof_ex` + #[codec(index = 4)] + submit_finality_proof_ex { + /// The header that we are going to finalize. + finality_target: Box
, + /// Finality justification for the `finality_target`. + justification: justification::GrandpaJustification
, + /// An identifier of the validators set, that have signed the justification. + current_set_id: SetId, + }, +} + +/// The `BridgeGrandpaCall` for a pallet that bridges with given `C`; +pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; + +/// A digest information on the `BridgeGrandpaCall::submit_finality_proof` call. +#[derive(Copy, Clone, PartialEq, RuntimeDebug)] +pub struct SubmitFinalityProofInfo { + /// Number of the finality target. + pub block_number: N, + /// An identifier of the validators set that has signed the submitted justification. + /// It might be `None` if deprecated version of the `submit_finality_proof` is used. + pub current_set_id: Option, + /// If `true`, then the call proves new **mandatory** header. + pub is_mandatory: bool, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, + /// Extra weight that we assume is included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for weight above that limit, is never refunded. + pub extra_weight: Weight, + /// Extra size (in bytes) that we assume are included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for bytes above that limit, is never refunded. + pub extra_size: u32, +} + +impl SubmitFinalityProofInfo { + /// Returns `true` if call size/weight is below our estimations for regular calls. + pub fn fits_limits(&self) -> bool { + self.extra_weight.is_zero() && self.extra_size.is_zero() + } +} diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 26295dee1801..48326bf5c19d 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -38,6 +38,10 @@ use sp_consensus_grandpa::{ use sp_runtime::{traits::Header as HeaderT, Digest, RuntimeDebug, SaturatedConversion}; use sp_std::{boxed::Box, vec::Vec}; +pub use call_info::{BridgeGrandpaCall, BridgeGrandpaCallOf, SubmitFinalityProofInfo}; + +mod call_info; + pub mod justification; pub mod storage_keys; @@ -228,39 +232,6 @@ pub trait FindEquivocations Result, Self::Error>; } -/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeGrandpaCall { - /// `pallet-bridge-grandpa::Call::submit_finality_proof` - #[codec(index = 0)] - submit_finality_proof { - /// The header that we are going to finalize. - finality_target: Box
, - /// Finality justification for the `finality_target`. - justification: justification::GrandpaJustification
, - }, - /// `pallet-bridge-grandpa::Call::initialize` - #[codec(index = 1)] - initialize { - /// All data, required to initialize the pallet. - init_data: InitializationData
, - }, - /// `pallet-bridge-grandpa::Call::submit_finality_proof_ex` - #[codec(index = 4)] - submit_finality_proof_ex { - /// The header that we are going to finalize. - finality_target: Box
, - /// Finality justification for the `finality_target`. - justification: justification::GrandpaJustification
, - /// An identifier of the validators set, that have signed the justification. - current_set_id: SetId, - }, -} - -/// The `BridgeGrandpaCall` used by a chain. -pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; - /// Substrate-based chain that is using direct GRANDPA finality. /// /// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement diff --git a/bridges/primitives/messages/src/call_info.rs b/bridges/primitives/messages/src/call_info.rs new file mode 100644 index 000000000000..4cc3b9d4afea --- /dev/null +++ b/bridges/primitives/messages/src/call_info.rs @@ -0,0 +1,164 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-messages` pallet. + +use crate::{source_chain, target_chain, LaneId, MessageNonce, UnrewardedRelayersState}; + +use bp_runtime::{AccountIdOf, HashOf}; +use codec::{Decode, Encode}; +use frame_support::weights::Weight; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; +use sp_std::ops::RangeInclusive; + +/// The `BridgeMessagesCall` used to bridge with a given chain. +pub type BridgeMessagesCallOf = BridgeMessagesCall< + AccountIdOf, + target_chain::FromBridgedChainMessagesProof>, + source_chain::FromBridgedChainMessagesDeliveryProof>, +>; + +/// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeMessagesCall { + /// `pallet-bridge-messages::Call::receive_messages_proof` + #[codec(index = 2)] + receive_messages_proof { + /// Account id of relayer at the **bridged** chain. + relayer_id_at_bridged_chain: AccountId, + /// Messages proof. + proof: MessagesProof, + /// A number of messages in the proof. + messages_count: u32, + /// Total dispatch weight of messages in the proof. + dispatch_weight: Weight, + }, + /// `pallet-bridge-messages::Call::receive_messages_delivery_proof` + #[codec(index = 3)] + receive_messages_delivery_proof { + /// Messages delivery proof. + proof: MessagesDeliveryProof, + /// "Digest" of unrewarded relayers state at the bridged chain. + relayers_state: UnrewardedRelayersState, + }, +} + +/// Generic info about a messages delivery/confirmation proof. +#[derive(PartialEq, RuntimeDebug)] +pub struct BaseMessagesProofInfo { + /// Message lane, used by the call. + pub lane_id: LaneId, + /// Nonces of messages, included in the call. + /// + /// For delivery transaction, it is nonces of bundled messages. For confirmation + /// transaction, it is nonces that are to be confirmed during the call. + pub bundled_range: RangeInclusive, + /// Nonce of the best message, stored by this chain before the call is dispatched. + /// + /// For delivery transaction, it is the nonce of best delivered message before the call. + /// For confirmation transaction, it is the nonce of best confirmed message before the call. + pub best_stored_nonce: MessageNonce, +} + +impl BaseMessagesProofInfo { + /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. + pub fn appends_to_stored_nonce(&self) -> bool { + Some(*self.bundled_range.start()) == self.best_stored_nonce.checked_add(1) + } +} + +/// Occupation state of the unrewarded relayers vector. +#[derive(PartialEq, RuntimeDebug)] +#[cfg_attr(test, derive(Default))] +pub struct UnrewardedRelayerOccupation { + /// The number of remaining unoccupied entries for new relayers. + pub free_relayer_slots: MessageNonce, + /// The number of messages that we are ready to accept. + pub free_message_slots: MessageNonce, +} + +/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesProofInfo { + /// Base messages proof info + pub base: BaseMessagesProofInfo, + /// State of unrewarded relayers vector. + pub unrewarded_relayers: UnrewardedRelayerOccupation, +} + +impl ReceiveMessagesProofInfo { + /// Returns true if: + /// + /// - either inbound lane is ready to accept bundled messages; + /// + /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed + /// messages and/or unrewarded relayers. + pub fn is_obsolete(&self, is_dispatcher_active: bool) -> bool { + // if dispatcher is inactive, we don't accept any delivery transactions + if !is_dispatcher_active { + return true + } + + // transactions with zero bundled nonces are not allowed, unless they're message + // delivery transactions, which brings reward confirmations required to unblock + // the lane + if self.base.bundled_range.is_empty() { + let empty_transactions_allowed = + // we allow empty transactions when we can't accept delivery from new relayers + self.unrewarded_relayers.free_relayer_slots == 0 || + // or if we can't accept new messages at all + self.unrewarded_relayers.free_message_slots == 0; + + return !empty_transactions_allowed + } + + // otherwise we require bundled messages to continue stored range + !self.base.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); + +impl ReceiveMessagesDeliveryProofInfo { + /// Returns true if outbound lane is ready to accept confirmations of bundled messages. + pub fn is_obsolete(&self) -> bool { + self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call +/// which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub enum MessagesCallInfo { + /// Messages delivery call info. + ReceiveMessagesProof(ReceiveMessagesProofInfo), + /// Messages delivery confirmation call info. + ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), +} + +impl MessagesCallInfo { + /// Returns range of messages, bundled with the call. + pub fn bundled_messages(&self) -> RangeInclusive { + match *self { + Self::ReceiveMessagesProof(ref info) => info.base.bundled_range.clone(), + Self::ReceiveMessagesDeliveryProof(ref info) => info.0.bundled_range.clone(), + } + } +} diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index b6d8660c08d2..37dc61e8b483 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -35,6 +35,13 @@ use sp_core::{RuntimeDebug, TypeId, H256}; use sp_io::hashing::blake2_256; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; +pub use call_info::{ + BaseMessagesProofInfo, BridgeMessagesCall, BridgeMessagesCallOf, MessagesCallInfo, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, +}; + +mod call_info; + pub mod source_chain; pub mod storage_keys; pub mod target_chain; @@ -612,32 +619,6 @@ where relayers_rewards } -/// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeMessagesCall { - /// `pallet-bridge-messages::Call::receive_messages_proof` - #[codec(index = 2)] - receive_messages_proof { - /// Account id of relayer at the **bridged** chain. - relayer_id_at_bridged_chain: AccountId, - /// Messages proof. - proof: MessagesProof, - /// A number of messages in the proof. - messages_count: u32, - /// Total dispatch weight of messages in the proof. - dispatch_weight: Weight, - }, - /// `pallet-bridge-messages::Call::receive_messages_delivery_proof` - #[codec(index = 3)] - receive_messages_delivery_proof { - /// Messages delivery proof. - proof: MessagesDeliveryProof, - /// "Digest" of unrewarded relayers state at the bridged chain. - relayers_state: UnrewardedRelayersState, - }, -} - /// Error that happens during message verification. #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] pub enum VerificationError { diff --git a/bridges/primitives/parachains/src/call_info.rs b/bridges/primitives/parachains/src/call_info.rs new file mode 100644 index 000000000000..fd7cd45a72c8 --- /dev/null +++ b/bridges/primitives/parachains/src/call_info.rs @@ -0,0 +1,59 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-parachains` pallet. + +use crate::{ParaHash, ParaId, RelayBlockHash, RelayBlockNumber}; + +use bp_polkadot_core::parachains::ParaHeadsProof; +use bp_runtime::HeaderId; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; +use sp_std::vec::Vec; + +/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeParachainCall { + /// `pallet-bridge-parachains::Call::submit_parachain_heads` + #[codec(index = 0)] + submit_parachain_heads { + /// Relay chain block, for which we have submitted the `parachain_heads_proof`. + at_relay_block: (RelayBlockNumber, RelayBlockHash), + /// Parachain identifiers and their head hashes. + parachains: Vec<(ParaId, ParaHash)>, + /// Parachain heads proof. + parachain_heads_proof: ParaHeadsProof, + }, +} + +/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. +/// +/// The pallet supports updating multiple parachain heads at once, +#[derive(PartialEq, RuntimeDebug)] +pub struct SubmitParachainHeadsInfo { + /// Number and hash of the finalized relay block that has been used to prove parachain + /// finality. + pub at_relay_block: HeaderId, + /// Parachain identifier. + pub para_id: ParaId, + /// Hash of the bundled parachain head. + pub para_head_hash: ParaHash, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, +} diff --git a/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs index 142c6e9b0892..9717fee8597c 100644 --- a/bridges/primitives/parachains/src/lib.rs +++ b/bridges/primitives/parachains/src/lib.rs @@ -22,7 +22,7 @@ pub use bp_header_chain::StoredHeaderData; use bp_polkadot_core::{ - parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}, + parachains::{ParaHash, ParaHead, ParaId}, BlockNumber as RelayBlockNumber, Hash as RelayBlockHash, }; use bp_runtime::{ @@ -36,6 +36,10 @@ use sp_core::storage::StorageKey; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*}; +pub use call_info::{BridgeParachainCall, SubmitParachainHeadsInfo}; + +mod call_info; + /// Best known parachain head hash. #[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] pub struct BestParaHeadHash { @@ -185,19 +189,3 @@ impl ParaStoredHeaderDataBuilder for C { None } } - -/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeParachainCall { - /// `pallet-bridge-parachains::Call::submit_parachain_heads` - #[codec(index = 0)] - submit_parachain_heads { - /// Relay chain block, for which we have submitted the `parachain_heads_proof`. - at_relay_block: (RelayBlockNumber, RelayBlockHash), - /// Parachain identifiers and their head hashes. - parachains: Vec<(ParaId, ParaHash)>, - /// Parachain heads proof. - parachain_heads_proof: ParaHeadsProof, - }, -} From b22c01e0b3e8ec30e74db9a60d463311c9d6401a Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 28 Sep 2023 09:40:36 +0300 Subject: [PATCH 20/95] Move refund extension to relayers pallet (#2584) * moved all call-related definitions to primitives * moving refund extension to relayers pallet * cleaning up * fix compilation + spelling fix compilation remove priority_calculator.rs fix extensions --- Cargo.lock | 13 + ...ck_obsolete_extension.rs => extensions.rs} | 200 +- .../bin/runtime-common/src/extensions/mod.rs | 21 - bridges/bin/runtime-common/src/lib.rs | 1 - bridges/bin/runtime-common/src/mock.rs | 1 + .../src/parachains_benchmarking.rs | 5 +- bridges/modules/grandpa/src/call_ext.rs | 3 +- bridges/modules/parachains/src/lib.rs | 12 +- bridges/modules/relayers/Cargo.toml | 28 +- .../relayers/src/extension/grandpa_adapter.rs | 177 ++ .../src/extension/messages_adapter.rs | 94 + .../relayers/src/extension/mod.rs} | 1682 ++++++----------- .../src/extension/parachain_adapter.rs | 182 ++ .../relayers/src/extension/priority.rs} | 33 +- bridges/modules/relayers/src/lib.rs | 21 +- bridges/modules/relayers/src/mock.rs | 286 ++- .../modules/relayers/src/payment_adapter.rs | 8 +- bridges/modules/relayers/src/stake_adapter.rs | 2 +- .../primitives/header-chain/src/call_info.rs | 15 +- bridges/primitives/messages/src/call_info.rs | 8 + bridges/primitives/parachains/src/lib.rs | 13 +- bridges/primitives/relayers/Cargo.toml | 12 +- bridges/primitives/relayers/src/extension.rs | 191 ++ bridges/primitives/relayers/src/lib.rs | 5 + .../lib-substrate-relay/src/cli/bridge.rs | 2 +- .../parachain_to_parachain.rs | 2 +- .../relay_to_parachain.rs | 2 +- .../src/on_demand/parachains.rs | 2 +- .../lib-substrate-relay/src/parachains/mod.rs | 6 +- 29 files changed, 1729 insertions(+), 1298 deletions(-) rename bridges/bin/runtime-common/src/{extensions/check_obsolete_extension.rs => extensions.rs} (77%) delete mode 100644 bridges/bin/runtime-common/src/extensions/mod.rs create mode 100644 bridges/modules/relayers/src/extension/grandpa_adapter.rs create mode 100644 bridges/modules/relayers/src/extension/messages_adapter.rs rename bridges/{bin/runtime-common/src/extensions/refund_relayer_extension.rs => modules/relayers/src/extension/mod.rs} (55%) create mode 100644 bridges/modules/relayers/src/extension/parachain_adapter.rs rename bridges/{bin/runtime-common/src/extensions/priority_calculator.rs => modules/relayers/src/extension/priority.rs} (96%) create mode 100644 bridges/primitives/relayers/src/extension.rs diff --git a/Cargo.lock b/Cargo.lock index ed3a7a678aa5..f1c8f8045b82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1926,11 +1926,15 @@ dependencies = [ name = "bp-relayers" version = "0.7.0" dependencies = [ + "bp-header-chain", "bp-messages", + "bp-parachains", "bp-runtime", "frame-support", + "frame-system", "hex", "hex-literal", + "pallet-utility", "parity-scale-codec", "scale-info", "sp-runtime", @@ -10201,18 +10205,27 @@ dependencies = [ name = "pallet-bridge-relayers" version = "0.7.0" dependencies = [ + "bp-header-chain", "bp-messages", + "bp-parachains", + "bp-polkadot-core", "bp-relayers", "bp-runtime", + "bp-test-utils", "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-balances", + "pallet-bridge-grandpa", "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-transaction-payment", + "pallet-utility", "parity-scale-codec", "scale-info", "sp-arithmetic", + "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", diff --git a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs b/bridges/bin/runtime-common/src/extensions.rs similarity index 77% rename from bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs rename to bridges/bin/runtime-common/src/extensions.rs index 433ab7916892..dc7e14de28f3 100644 --- a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs +++ b/bridges/bin/runtime-common/src/extensions.rs @@ -18,7 +18,6 @@ //! obsolete (duplicated) data or do not pass some additional pallet-specific //! checks. -use crate::extensions::refund_relayer_extension::RefundableParachainId; use bp_parachains::SubmitParachainHeadsInfo; use bp_relayers::ExplicitOrAccountParams; use bp_runtime::Parachain; @@ -29,9 +28,10 @@ use pallet_bridge_messages::CallSubType as MessagesCallSubType; use pallet_bridge_parachains::{CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper}; use pallet_bridge_relayers::Pallet as RelayersPallet; use sp_runtime::{ - traits::{Get, PhantomData, UniqueSaturatedInto}, + traits::{Get, UniqueSaturatedInto}, transaction_validity::{TransactionPriority, TransactionValidity, ValidTransactionBuilder}, }; +use sp_std::marker::PhantomData; // Re-export to avoid include tuplex dependency everywhere. #[doc(hidden)] @@ -123,17 +123,27 @@ where /// `(BundledHeaderNumber - 1 - BestKnownHeaderNumber) * Priority::get()`. /// The boost is only applied if submitter has active registration in the relayers /// pallet. -pub struct CheckAndBoostBridgeParachainsTransactions( - PhantomData<(T, RefPara, Priority, SlashAccount)>, -); - -impl, SlashAccount: Get> - BridgeRuntimeFilterCall - for CheckAndBoostBridgeParachainsTransactions +pub struct CheckAndBoostBridgeParachainsTransactions< + T, + ParachainsInstance, + Para, + Priority, + SlashAccount, +>(PhantomData<(T, ParachainsInstance, Para, Priority, SlashAccount)>); + +impl< + T, + ParachainsInstance, + Para, + Priority: Get, + SlashAccount: Get, + > BridgeRuntimeFilterCall + for CheckAndBoostBridgeParachainsTransactions where - T: pallet_bridge_relayers::Config + pallet_bridge_parachains::Config, - RefPara: RefundableParachainId, - T::RuntimeCall: ParachainsCallSubtype, + T: pallet_bridge_relayers::Config + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, + T::RuntimeCall: ParachainsCallSubtype, { // bridged header number, bundled in transaction type ToPostDispatch = Option; @@ -142,10 +152,10 @@ where who: &T::AccountId, call: &T::RuntimeCall, ) -> (Self::ToPostDispatch, TransactionValidity) { - match ParachainsCallSubtype::::check_obsolete_submit_parachain_heads( + match ParachainsCallSubtype::::check_obsolete_submit_parachain_heads( call, ) { - Ok(Some(our_tx)) if our_tx.base.para_id.0 == RefPara::BridgedChain::PARACHAIN_ID => { + Ok(Some(our_tx)) if our_tx.base.para_id.0 == Para::PARACHAIN_ID => { let to_post_dispatch = Some(our_tx.base); let total_priority_boost = compute_priority_boost::(&who, our_tx.improved_by); @@ -164,7 +174,7 @@ where let Some(update) = maybe_update else { return }; // we are only interested in failed or unneeded transactions let has_failed = has_failed || - !SubmitParachainHeadsHelper::::was_successful(&update); + !SubmitParachainHeadsHelper::::was_successful(&update); if !has_failed { return @@ -272,7 +282,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { type Pre = ( $account_id, ( $( - <$filter_call as $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + <$filter_call as $crate::extensions::BridgeRuntimeFilterCall< $account_id, $call, >>::ToPostDispatch, @@ -299,7 +309,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { $( let (from_validate, call_filter_validity) = < $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $crate::extensions::BridgeRuntimeFilterCall< Self::AccountId, $call, >>::validate(&who, call); @@ -316,12 +326,13 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { info: &sp_runtime::traits::DispatchInfoOf, len: usize, ) -> Result { - use $crate::extensions::check_obsolete_extension::__private::tuplex::PushBack; + use $crate::extensions::__private::tuplex::PushBack; + let to_post_dispatch = (); $( let (from_validate, call_filter_validity) = < $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $crate::extensions::BridgeRuntimeFilterCall< $account_id, $call, >>::validate(&relayer, call); @@ -339,14 +350,15 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { len: usize, result: &sp_runtime::DispatchResult, ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { - use $crate::extensions::check_obsolete_extension::__private::tuplex::PopFront; + use $crate::extensions::__private::tuplex::PopFront; + let Some((relayer, to_post_dispatch)) = to_post_dispatch else { return Ok(()) }; let has_failed = result.is_err(); $( let (item, to_post_dispatch) = to_post_dispatch.pop_front(); < $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $crate::extensions::BridgeRuntimeFilterCall< $account_id, $call, >>::post_dispatch(&relayer, has_failed, item); @@ -360,25 +372,37 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use super::*; - use crate::{ - extensions::refund_relayer_extension::{ - tests::{ - initialize_environment, relayer_account_at_this_chain, - submit_parachain_head_call_ex, submit_relay_header_call_ex, - }, - RefundableParachain, - }, - mock::*, - }; - use bp_polkadot_core::parachains::ParaId; + use crate::mock::*; + use bp_header_chain::StoredHeaderDataBuilder; + use bp_messages::{InboundLaneData, LaneId, MessageNonce, OutboundLaneData}; + use bp_parachains::{BestParaHeadHash, ParaInfo}; + use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; + use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::HeaderId; - use frame_support::{assert_err, assert_ok}; + use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; + use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; + use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet}; + use pallet_bridge_parachains::Call as ParachainsCall; use sp_runtime::{ - traits::{ConstU64, SignedExtension}, + traits::{parameter_types, ConstU64, Header as _, SignedExtension}, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, DispatchError, }; + parameter_types! { + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::ThisChain, + ); + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::BridgedChain, + ); + pub TestLaneId: LaneId = test_lane_id(); + } + pub struct MockCall { data: u32, } @@ -452,6 +476,103 @@ mod tests { } } + fn test_lane_id() -> LaneId { + LaneId::new(1, 2) + } + + fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { + let test_stake: ThisChainBalance = TestStake::get(); + ExistentialDeposit::get().saturating_add(test_stake * 100) + } + + // in tests, the following accounts are equal (because of how `into_sub_account_truncating` + // works) + + fn delivery_rewards_account() -> ThisChainAccountId { + TestPaymentProcedure::rewards_account(MsgProofsRewardsAccount::get()) + } + + fn confirmation_rewards_account() -> ThisChainAccountId { + TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get()) + } + + fn relayer_account_at_this_chain() -> ThisChainAccountId { + 0 + } + + fn initialize_environment( + best_relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, + best_message: MessageNonce, + ) { + let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); + let best_relay_header = HeaderId(best_relay_header_number, BridgedChainHash::default()); + pallet_bridge_grandpa::CurrentAuthoritySet::::put( + StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(), + ); + pallet_bridge_grandpa::BestFinalized::::put(best_relay_header); + pallet_bridge_grandpa::ImportedHeaders::::insert( + best_relay_header.hash(), + bp_test_utils::test_header::(0).build(), + ); + + let para_id = ParaId(BridgedUnderlyingParachain::PARACHAIN_ID); + let para_info = ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: parachain_head_at_relay_header_number, + head_hash: [parachain_head_at_relay_header_number as u8; 32].into(), + }, + next_imported_hash_position: 0, + }; + pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); + + let lane_id = test_lane_id(); + let in_lane_data = + InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + let out_lane_data = + OutboundLaneData { latest_received_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::OutboundLanes::::insert(lane_id, out_lane_data); + + Balances::mint_into(&delivery_rewards_account(), ExistentialDeposit::get()).unwrap(); + Balances::mint_into(&confirmation_rewards_account(), ExistentialDeposit::get()).unwrap(); + Balances::mint_into( + &relayer_account_at_this_chain(), + initial_balance_of_relayer_account_at_this_chain(), + ) + .unwrap(); + } + + fn submit_relay_header_call(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { + let relay_header = BridgedChainHeader::new( + relay_header_number, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ); + let relay_justification = make_default_justification(&relay_header); + + RuntimeCall::BridgeGrandpa(GrandpaCall::submit_finality_proof { + finality_target: Box::new(relay_header), + justification: relay_justification, + }) + } + + fn submit_parachain_head_call( + parachain_head_at_relay_header_number: BridgedChainBlockNumber, + ) -> RuntimeCall { + RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), + parachains: vec![( + ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + [parachain_head_at_relay_header_number as u8; 32].into(), + )], + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, + }) + } + #[test] fn test_generated_obsolete_extension() { generate_bridge_reject_obsolete_headers_and_messages!( @@ -543,7 +664,7 @@ mod tests { let priority_boost = BridgeGrandpaWrapper::validate( &relayer_account_at_this_chain(), - &submit_relay_header_call_ex(200), + &submit_relay_header_call(200), ) .1 .unwrap() @@ -561,7 +682,7 @@ mod tests { let priority_boost = BridgeGrandpaWrapper::validate( &relayer_account_at_this_chain(), - &submit_relay_header_call_ex(200), + &submit_relay_header_call(200), ) .1 .unwrap() @@ -598,7 +719,8 @@ mod tests { type BridgeParachainsWrapper = CheckAndBoostBridgeParachainsTransactions< TestRuntime, - RefundableParachain<(), BridgedUnderlyingParachain>, + (), + BridgedUnderlyingParachain, ConstU64<1_000>, SlashDestination, >; @@ -610,7 +732,7 @@ mod tests { let priority_boost = BridgeParachainsWrapper::validate( &relayer_account_at_this_chain(), - &submit_parachain_head_call_ex(200), + &submit_parachain_head_call(200), ) .1 .unwrap() @@ -628,7 +750,7 @@ mod tests { let priority_boost = BridgeParachainsWrapper::validate( &relayer_account_at_this_chain(), - &submit_parachain_head_call_ex(200), + &submit_parachain_head_call(200), ) .1 .unwrap() diff --git a/bridges/bin/runtime-common/src/extensions/mod.rs b/bridges/bin/runtime-common/src/extensions/mod.rs deleted file mode 100644 index 3f1b506aaae3..000000000000 --- a/bridges/bin/runtime-common/src/extensions/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! Bridge-specific transaction extensions. - -pub mod check_obsolete_extension; -pub mod priority_calculator; -pub mod refund_relayer_extension; diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index de9ee1b0bbbc..ac8b013086b1 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -20,7 +20,6 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod extensions; - pub mod messages_api; pub mod messages_benchmarking; pub mod parachains_benchmarking; diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 917b529be834..fed0d15cc080 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -84,6 +84,7 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< >; /// Message lane used in tests. +#[allow(unused)] pub fn test_lane_id() -> LaneId { LaneId::new(1, 2) } diff --git a/bridges/bin/runtime-common/src/parachains_benchmarking.rs b/bridges/bin/runtime-common/src/parachains_benchmarking.rs index bcbd779b44de..e48a5664e31a 100644 --- a/bridges/bin/runtime-common/src/parachains_benchmarking.rs +++ b/bridges/bin/runtime-common/src/parachains_benchmarking.rs @@ -20,12 +20,13 @@ use crate::messages_benchmarking::insert_header_to_grandpa_pallet; -use bp_parachains::parachain_head_storage_key_at_source; +use bp_parachains::{ + parachain_head_storage_key_at_source, RelayBlockHash, RelayBlockHasher, RelayBlockNumber, +}; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; use bp_runtime::{grow_storage_value, record_all_trie_keys, Chain, UnverifiedStorageProofParams}; use codec::Encode; use frame_support::traits::Get; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use sp_std::prelude::*; use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index 5690b8b4b18c..d964901ba4bc 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -34,10 +34,11 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, RuntimeDebug, SaturatedConversion, }; +use sp_std::fmt::Debug; /// Verified `SubmitFinalityProofInfo`. #[derive(Copy, Clone, PartialEq, RuntimeDebug)] -pub struct VerifiedSubmitFinalityProofInfo { +pub struct VerifiedSubmitFinalityProofInfo { /// Base call information. pub base: SubmitFinalityProofInfo, /// A difference between bundled bridged header and best bridged header known to us diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 9d8ced5e1b3f..f30af9c482c5 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -28,7 +28,10 @@ pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; use bp_header_chain::{HeaderChain, HeaderChainError}; -use bp_parachains::{ParaInfo, ParaStoredHeaderData, SubmitParachainHeadsInfo}; +use bp_parachains::{ + ParaInfo, ParaStoredHeaderData, RelayBlockHash, RelayBlockHasher, RelayBlockNumber, + SubmitParachainHeadsInfo, +}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain}; use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound}; @@ -61,13 +64,6 @@ mod proofs; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-parachains"; -/// Block hash of the bridged relay chain. -pub type RelayBlockHash = bp_polkadot_core::Hash; -/// Block number of the bridged relay chain. -pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; -/// Hasher of the bridged relay chain. -pub type RelayBlockHasher = bp_polkadot_core::Hasher; - /// Artifacts of the parachains head update. struct UpdateParachainHeadArtifacts { /// New best head of the parachain. diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 27a28546afb4..9a4a680e135f 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -16,30 +16,38 @@ log = { workspace = true } scale-info = { features = ["derive"], workspace = true } # Bridge dependencies - +bp-header-chain = { workspace = true } bp-messages = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } +pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } # Substrate Dependencies - frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +pallet-transaction-payment = { workspace = true } sp-arithmetic = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } [dev-dependencies] -bp-runtime = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } +bp-runtime = { workspace = true } +pallet-balances = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-test-utils = { workspace = true } +pallet-utility = { workspace = true } +sp-core = { workspace = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", "bp-relayers/std", "bp-runtime/std", @@ -48,7 +56,10 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", + "pallet-transaction-payment/std", "scale-info/std", "sp-arithmetic/std", "sp-runtime/std", @@ -59,13 +70,18 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-bridge-grandpa/try-runtime", "pallet-bridge-messages/try-runtime", + "pallet-bridge-parachains/try-runtime", "sp-runtime/try-runtime", ] +integrity-test = [] diff --git a/bridges/modules/relayers/src/extension/grandpa_adapter.rs b/bridges/modules/relayers/src/extension/grandpa_adapter.rs new file mode 100644 index 000000000000..6c9ae1c2968c --- /dev/null +++ b/bridges/modules/relayers/src/extension/grandpa_adapter.rs @@ -0,0 +1,177 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with remote GRANDPA chain. + +use crate::{ + extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig, LOG_TARGET, +}; + +use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::{Chain, StaticStrProvider}; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::Config as SystemConfig; +use pallet_bridge_grandpa::{ + CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig, + SubmitFinalityProofHelper, +}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, + Saturating, +}; +use sp_std::marker::PhantomData; + +/// Adapter to be used in signed extension configuration, when bridging with remote +/// chains that are using GRANDPA finality. +pub struct WithGrandpaChainExtensionConfig< + // signed extension identifier + IdProvider, + // runtime that implements `BridgeMessagesConfig`, which + // uses `BridgeGrandpaConfig` to receive messages and + // confirmations from the remote chain. + Runtime, + // batch call unpacker + BatchCallUnpacker, + // instance of the `pallet-bridge-grandpa`, tracked by this extension + BridgeGrandpaPalletInstance, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, +>( + PhantomData<( + IdProvider, + Runtime, + BatchCallUnpacker, + BridgeGrandpaPalletInstance, + BridgeMessagesPalletInstance, + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig + for WithGrandpaChainExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + + BridgeMessagesConfig> + + BridgeGrandpaConfig, + BCU: BatchCallUnpacker, + GI: 'static, + MI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeGrandpaCallSubtype + + BridgeMessagesCallSubType, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type PriorityBoostPerMessage = P; + type Reward = R::Reward; + type RemoteGrandpaChainBlockNumber = pallet_bridge_grandpa::BridgedBlockNumber; + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let calls = BCU::unpack(call, 2); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info()); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + Ok(match (total_calls, relay_finality_call, msgs_call) { + (2, Some(relay_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)), + (1, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_submit_finality_proof_succeeded::(call_info, call_data, relayer) && + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} + +/// If the batch call contains the GRANDPA chain state update call, verify that it +/// has been successful. +/// +/// Only returns false when GRANDPA chain state update call has failed. +pub(crate) fn verify_submit_finality_proof_succeeded( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool +where + C: ExtensionConfig, + GI: 'static, + C::Runtime: BridgeGrandpaConfig, + >::BridgedChain: + Chain, +{ + let Some(finality_proof_info) = call_info.submit_finality_proof_info() else { return true }; + + if !SubmitFinalityProofHelper::::was_successful( + finality_proof_info.block_number, + ) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid GRANDPA chain finality proof", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false + } + + // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` + // transaction. If relay chain header is mandatory, the GRANDPA pallet returns + // `Pays::No`, because such transaction is mandatory for operating the bridge. But + // `utility.batchAll` transaction always requires payment. But in both cases we'll + // refund relayer - either explicitly here, or using `Pays::No` if he's choosing + // to submit dedicated transaction. + + // submitter has means to include extra weight/bytes in the `submit_finality_proof` + // call, so let's subtract extra weight/size to avoid refunding for this extra stuff + call_data.extra_weight.saturating_accrue(finality_proof_info.extra_weight); + call_data.extra_size.saturating_accrue(finality_proof_info.extra_size); + + true +} diff --git a/bridges/modules/relayers/src/extension/messages_adapter.rs b/bridges/modules/relayers/src/extension/messages_adapter.rs new file mode 100644 index 000000000000..f84e25ba5aa1 --- /dev/null +++ b/bridges/modules/relayers/src/extension/messages_adapter.rs @@ -0,0 +1,94 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with any remote chain. This adapter does not refund any finality transactions. + +use crate::{extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig}; + +use bp_relayers::{ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::StaticStrProvider; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, +}; +use sp_std::marker::PhantomData; + +/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation +/// transactions. Finality transactions are not refunded. +pub struct MessagesExtensionConfig< + IdProvider, + Runtime, + BridgeMessagesPalletInstance, + PriorityBoostPerMessage, +>( + PhantomData<( + // signed extension identifier + IdProvider, + // runtime with `pallet-bridge-messages` pallet deployed + Runtime, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig for MessagesExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + BridgeMessagesConfig, + MI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeMessagesCallSubType, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type PriorityBoostPerMessage = P; + type Reward = R::Reward; + type RemoteGrandpaChainBlockNumber = (); + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let call = Self::check_obsolete_parsed_call(call)?; + Ok(call.call_info().map(ExtensionCallInfo::Msgs)) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/modules/relayers/src/extension/mod.rs similarity index 55% rename from bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs rename to bridges/modules/relayers/src/extension/mod.rs index 1418c8aea3a9..fb170965afa9 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -14,208 +14,76 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Signed extension that refunds relayer if he has delivered some new messages. -//! It also refunds transaction cost if the transaction is an `utility.batchAll()` -//! with calls that are: delivering new message and all necessary underlying headers -//! (parachain or relay chain). - -use bp_header_chain::SubmitFinalityProofInfo; -use bp_messages::{ChainWithMessages, LaneId, MessageNonce, MessagesCallInfo}; -use bp_parachains::SubmitParachainHeadsInfo; -use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{Chain, Parachain, RangeInclusiveExt, StaticStrProvider}; -use codec::{Codec, Decode, Encode}; +//! Signed extension, built around `pallet-bridge-relayers`. It is able to: +//! +//! - refund the cost of successful message delivery and confirmation transactions to the submitter +//! by registering corresponding reward in the pallet; +//! +//! - bump priority of messages delivery and confirmation transactions, signed by the registered +//! relayers. + +use crate::{Config as RelayersConfig, Pallet as RelayersPallet, WeightInfoExt, LOG_TARGET}; + +use bp_messages::{ChainWithMessages, MessageNonce}; +use bp_relayers::{ + ExplicitOrAccountParams, ExtensionCallData, ExtensionCallInfo, ExtensionConfig, + RewardsAccountOwner, RewardsAccountParams, +}; +use bp_runtime::{Chain, RangeInclusiveExt, StaticStrProvider}; +use codec::{Decode, Encode}; use frame_support::{ - dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, - traits::IsSubType, - weights::Weight, + dispatch::{DispatchInfo, PostDispatchInfo}, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; -use pallet_bridge_grandpa::{CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper}; -use pallet_bridge_messages::{ - CallHelper as MessagesCallHelper, CallSubType as MessagesCallSubType, Config as MessagesConfig, -}; -use pallet_bridge_parachains::{ - BoundedBridgeGrandpaConfig, CallSubType as ParachainsCallSubType, Config as ParachainsConfig, - RelayBlockNumber, SubmitParachainHeadsHelper, +use frame_system::Config as SystemConfig; +use pallet_bridge_messages::{CallHelper as MessagesCallHelper, Config as BridgeMessagesConfig}; +use pallet_transaction_payment::{ + Config as TransactionPaymentConfig, OnChargeTransaction, Pallet as TransactionPaymentPallet, }; -use pallet_bridge_relayers::{ - Config as RelayersConfig, Pallet as RelayersPallet, WeightInfoExt as _, -}; -use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTransaction}; -use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + TransactionValidity, TransactionValidityError, ValidTransactionBuilder, }, - DispatchResult, FixedPointOperand, RuntimeDebug, + DispatchResult, RuntimeDebug, }; -use sp_std::{marker::PhantomData, vec, vec::Vec}; - -type AccountIdOf = ::AccountId; -// without this typedef rustfmt fails with internal err -type BalanceOf = - <::OnChargeTransaction as OnChargeTransaction>::Balance; -type CallOf = ::RuntimeCall; - -/// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages -/// coming from this parachain. -pub trait RefundableParachainId { - /// The instance of the bridge parachains pallet. - type Instance: 'static; - /// The parachain Id. - type BridgedChain: Parachain; -} - -/// Implementation of `RefundableParachainId` for `trait Parachain`. -pub struct RefundableParachain(PhantomData<(Instance, Para)>); - -impl RefundableParachainId for RefundableParachain -where - Instance: 'static, - Para: Parachain, -{ - type Instance = Instance; - type BridgedChain = Para; -} - -/// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages -/// coming from this lane. -pub trait RefundableMessagesLaneId { - /// The instance of the bridge messages pallet. - type Instance: 'static; - /// The messages lane id. - type Id: Get; -} +use sp_std::{fmt::Debug, marker::PhantomData}; -/// Default implementation of `RefundableMessagesLaneId`. -pub struct RefundableMessagesLane(PhantomData<(Runtime, Instance, Lane)>); +pub use grandpa_adapter::WithGrandpaChainExtensionConfig; +pub use messages_adapter::MessagesExtensionConfig; +pub use parachain_adapter::WithParachainExtensionConfig; +pub use priority::*; -impl RefundableMessagesLaneId - for RefundableMessagesLane -where - Runtime: MessagesConfig, - Instance: 'static, - Lane: Get, -{ - type Instance = Instance; - type Id = Lane; -} - -/// Refund calculator. -pub trait RefundCalculator { - /// The underlying integer type in which the refund is calculated. - type Balance; - - /// Compute refund for given transaction. - fn compute_refund( - info: &DispatchInfo, - post_info: &PostDispatchInfo, - len: usize, - tip: Self::Balance, - ) -> Self::Balance; -} - -/// `RefundCalculator` implementation which refunds the actual transaction fee. -pub struct ActualFeeRefund(PhantomData); - -impl RefundCalculator for ActualFeeRefund -where - R: TransactionPaymentConfig, - CallOf: Dispatchable, - BalanceOf: FixedPointOperand, -{ - type Balance = BalanceOf; - - fn compute_refund( - info: &DispatchInfo, - post_info: &PostDispatchInfo, - len: usize, - tip: BalanceOf, - ) -> BalanceOf { - pallet_transaction_payment::Pallet::::compute_actual_fee(len as _, info, post_info, tip) - } -} +mod grandpa_adapter; +mod messages_adapter; +mod parachain_adapter; +mod priority; /// Data that is crafted in `pre_dispatch` method and used at `post_dispatch`. #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct PreDispatchData { +pub struct PreDispatchData { /// Transaction submitter (relayer) account. relayer: AccountId, /// Type of the call. - call_info: CallInfo, -} - -/// Type of the call that the extension recognizes. -#[derive(RuntimeDebugNoBound, PartialEq)] -pub enum CallInfo { - /// Relay chain finality + parachain finality + message delivery/confirmation calls. - AllFinalityAndMsgs( - SubmitFinalityProofInfo, - SubmitParachainHeadsInfo, - MessagesCallInfo, - ), - /// Relay chain finality + message delivery/confirmation calls. - RelayFinalityAndMsgs(SubmitFinalityProofInfo, MessagesCallInfo), - /// Parachain finality + message delivery/confirmation calls. - /// - /// This variant is used only when bridging with parachain. - ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), - /// Standalone message delivery/confirmation call. - Msgs(MessagesCallInfo), + call_info: ExtensionCallInfo, } -impl CallInfo { - /// Returns true if call is a message delivery call (with optional finality calls). - fn is_receive_messages_proof_call(&self) -> bool { - match self.messages_call_info() { - MessagesCallInfo::ReceiveMessagesProof(_) => true, - MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => false, - } - } - - /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. - fn submit_finality_proof_info(&self) -> Option> { - match *self { - Self::AllFinalityAndMsgs(info, _, _) => Some(info), - Self::RelayFinalityAndMsgs(info, _) => Some(info), - _ => None, - } - } - +impl + PreDispatchData +{ /// Returns mutable reference to pre-dispatch `finality_target` sent to the /// `SubmitFinalityProof` call. #[cfg(test)] - fn submit_finality_proof_info_mut( + pub fn submit_finality_proof_info_mut( &mut self, - ) -> Option<&mut SubmitFinalityProofInfo> { - match *self { - Self::AllFinalityAndMsgs(ref mut info, _, _) => Some(info), - Self::RelayFinalityAndMsgs(ref mut info, _) => Some(info), + ) -> Option<&mut bp_header_chain::SubmitFinalityProofInfo> { + match self.call_info { + ExtensionCallInfo::AllFinalityAndMsgs(ref mut info, _, _) => Some(info), + ExtensionCallInfo::RelayFinalityAndMsgs(ref mut info, _) => Some(info), _ => None, } } - - /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. - fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { - match self { - Self::AllFinalityAndMsgs(_, info, _) => Some(info), - Self::ParachainFinalityAndMsgs(info, _) => Some(info), - _ => None, - } - } - - /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. - fn messages_call_info(&self) -> &MessagesCallInfo { - match self { - Self::AllFinalityAndMsgs(_, _, info) => info, - Self::RelayFinalityAndMsgs(_, info) => info, - Self::ParachainFinalityAndMsgs(_, info) => info, - Self::Msgs(info) => info, - } - } } /// The actions on relayer account that need to be performed because of his actions. @@ -229,78 +97,93 @@ pub enum RelayerAccountAction { Slash(AccountId, RewardsAccountParams), } -/// Everything common among our refund signed extensions. -pub trait RefundSignedExtension: - 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo +/// A signed extension, built around `pallet-bridge-relayers`. +/// +/// It may be incorporated into runtime to refund relayers for submitting correct +/// message delivery and confirmation transactions, optionally batched with required +/// finality proofs. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[scale_info(skip_type_params(Runtime, Config))] +pub struct BridgeRelayersSignedExtension(PhantomData<(Runtime, Config)>); + +impl BridgeRelayersSignedExtension +where + Self: 'static + Send + Sync, + R: RelayersConfig + + BridgeMessagesConfig + + TransactionPaymentConfig, + C: ExtensionConfig, + R::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, { - /// This chain runtime. - type Runtime: MessagesConfig<::Instance> - + RelayersConfig; - /// Messages pallet and lane reference. - type Msgs: RefundableMessagesLaneId; - /// Refund amount calculator. - type Refund: RefundCalculator::Reward>; - /// Priority boost calculator. - type Priority: Get; - /// Signed extension unique identifier. - type Id: StaticStrProvider; - - /// Unpack batch runtime call. - fn expand_call(call: &CallOf) -> Vec<&CallOf>; - - /// Given runtime call, check if it has supported format. Additionally, check if any of - /// (optionally batched) calls are obsolete and we shall reject the transaction. - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError>; - - /// Check if parsed call is already obsolete. - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError>; - - /// Called from post-dispatch and shall perform additional checks (apart from messages - /// transaction success) of given call result. - fn additional_call_result_check( - relayer: &AccountIdOf, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool; + /// Returns number of bundled messages `Some(_)`, if the given call info is a: + /// + /// - message delivery transaction; + /// + /// - with reasonable bundled messages that may be accepted by the messages pallet. + /// + /// This function is used to check whether the transaction priority should be + /// virtually boosted. The relayer registration (we only boost priority for registered + /// relayer transactions) must be checked outside. + fn bundled_messages_for_priority_boost( + call_info: Option<&ExtensionCallInfo>, + ) -> Option { + // we only boost priority of message delivery transactions + let parsed_call = match call_info { + Some(parsed_call) if parsed_call.is_receive_messages_proof_call() => parsed_call, + _ => return None, + }; + + // compute total number of messages in transaction + let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); + + // a quick check to avoid invalid high-priority transactions + let max_unconfirmed_messages_in_confirmation_tx = >::BridgedChain + ::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { + return None + } + + Some(bundled_messages) + } /// Given post-dispatch information, analyze the outcome of relayer call and return /// actions that need to be performed on relayer account. fn analyze_call_result( - pre: Option>>>, + pre: Option>>, info: &DispatchInfo, post_info: &PostDispatchInfo, len: usize, result: &DispatchResult, - ) -> RelayerAccountAction, ::Reward> - { - let mut extra_weight = Weight::zero(); - let mut extra_size = 0; - + ) -> RelayerAccountAction { // We don't refund anything for transactions that we don't support. let (relayer, call_info) = match pre { Some(Some(pre)) => (pre.relayer, pre.call_info), _ => return RelayerAccountAction::None, }; - // now we know that the relayer either needs to be rewarded, or slashed + // now we know that the call is supported and we may need to reward or slash relayer // => let's prepare the correspondent account that pays reward/receives slashed amount - let reward_account_params = - RewardsAccountParams::new( - ::Id::get(), - ::Instance, - >>::BridgedChain::ID, - if call_info.is_receive_messages_proof_call() { - RewardsAccountOwner::ThisChain - } else { - RewardsAccountOwner::BridgedChain - }, - ); + let lane_id = call_info.messages_call_info().lane_id(); + let reward_account_params = RewardsAccountParams::new( + lane_id, + >::BridgedChain::ID, + if call_info.is_receive_messages_proof_call() { + RewardsAccountOwner::ThisChain + } else { + RewardsAccountOwner::BridgedChain + }, + ); // prepare return value for the case if the call has failed or it has not caused // expected side effects (e.g. not all messages have been accepted) @@ -323,37 +206,19 @@ pub trait RefundSignedExtension: // We don't refund anything if the transaction has failed. if let Err(e) = result { log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid messages transaction: {:?}", - Self::Id::STR, - ::Id::get(), + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid messages transaction: {:?}", + Self::IDENTIFIER, + lane_id, relayer, e, ); return slash_relayer_if_delivery_result } - // Check if the `ReceiveMessagesProof` call delivered at least some of the messages that - // it contained. If this happens, we consider the transaction "helpful" and refund it. - let msgs_call_info = call_info.messages_call_info(); - if !MessagesCallHelper::::Instance>::was_successful(msgs_call_info) { - log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid messages call", - Self::Id::STR, - ::Id::get(), - relayer, - ); - return slash_relayer_if_delivery_result - } - - // do additional checks - if !Self::additional_call_result_check( - &relayer, - &call_info, - &mut extra_weight, - &mut extra_size, - ) { + // check whether the call has succeeded + let mut call_data = ExtensionCallData::default(); + if !C::check_call_result(&call_info, &mut call_data, &relayer) { return slash_relayer_if_delivery_result } @@ -365,81 +230,55 @@ pub trait RefundSignedExtension: let tip = Zero::zero(); // decrease post-dispatch weight/size using extra weight/size that we know now - let post_info_len = len.saturating_sub(extra_size as usize); - let mut post_info_weight = - post_info.actual_weight.unwrap_or(info.weight).saturating_sub(extra_weight); + let post_info_len = len.saturating_sub(call_data.extra_size as usize); + let mut post_info_weight = post_info + .actual_weight + .unwrap_or(info.weight) + .saturating_sub(call_data.extra_weight); // let's also replace the weight of slashing relayer with the weight of rewarding relayer if call_info.is_receive_messages_proof_call() { post_info_weight = post_info_weight.saturating_sub( - ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), + ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), ); } // compute the relayer refund let mut post_info = *post_info; post_info.actual_weight = Some(post_info_weight); - let refund = Self::Refund::compute_refund(info, &post_info, post_info_len, tip); + let refund = Self::compute_refund(info, &post_info, post_info_len, tip); // we can finally reward relayer RelayerAccountAction::Reward(relayer, reward_account_params, refund) } - /// Returns number of bundled messages `Some(_)`, if the given call info is a: - /// - /// - message delivery transaction; - /// - /// - with reasonable bundled messages that may be accepted by the messages pallet. - /// - /// This function is used to check whether the transaction priority should be - /// virtually boosted. The relayer registration (we only boost priority for registered - /// relayer transactions) must be checked outside. - fn bundled_messages_for_priority_boost(call_info: Option<&CallInfo>) -> Option { - // we only boost priority of message delivery transactions - let parsed_call = match call_info { - Some(parsed_call) if parsed_call.is_receive_messages_proof_call() => parsed_call, - _ => return None, - }; - - // compute total number of messages in transaction - let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); - - // a quick check to avoid invalid high-priority transactions - let max_unconfirmed_messages_in_confirmation_tx = ::Instance, - >>::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { - return None - } - - Some(bundled_messages) + /// Compute refund for the successful relayer transaction + fn compute_refund( + info: &DispatchInfo, + post_info: &PostDispatchInfo, + len: usize, + tip: R::Reward, + ) -> R::Reward { + TransactionPaymentPallet::::compute_actual_fee(len as _, info, post_info, tip) } } -/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any -/// `RefundSignedExtension`. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -pub struct RefundSignedExtensionAdapter(T); - -impl SignedExtension for RefundSignedExtensionAdapter +impl SignedExtension for BridgeRelayersSignedExtension where - CallOf: Dispatchable - + MessagesCallSubType::Instance>, + Self: 'static + Send + Sync, + R: RelayersConfig + + BridgeMessagesConfig + + TransactionPaymentConfig, + C: ExtensionConfig, + R::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, { - const IDENTIFIER: &'static str = T::Id::STR; - type AccountId = AccountIdOf; - type Call = CallOf; + const IDENTIFIER: &'static str = C::IdProvider::STR; + type AccountId = R::AccountId; + type Call = R::RuntimeCall; type AdditionalSigned = (); - type Pre = Option>>; + type Pre = Option>; fn additional_signed(&self) -> Result<(), TransactionValidityError> { Ok(()) @@ -457,33 +296,33 @@ where // we're not calling `validate` from `pre_dispatch` directly because of performance // reasons, so if you're adding some code that may fail here, please check if it needs // to be added to the `pre_dispatch` as well - let parsed_call = T::parse_and_check_for_obsolete_call(call)?; + let parsed_call = C::parse_and_check_for_obsolete_call(call)?; // the following code just plays with transaction priority and never returns an error // we only boost priority of presumably correct message delivery transactions - let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { + let bundled_messages = match Self::bundled_messages_for_priority_boost(parsed_call.as_ref()) + { Some(bundled_messages) => bundled_messages, None => return Ok(Default::default()), }; // we only boost priority if relayer has staked required balance - if !RelayersPallet::::is_registration_active(who) { + if !RelayersPallet::::is_registration_active(who) { return Ok(Default::default()) } // compute priority boost - let priority_boost = crate::extensions::priority_calculator::compute_priority_boost::< - T::Priority, - >(bundled_messages); + let priority_boost = + priority::compute_priority_boost::(bundled_messages); let valid_transaction = ValidTransactionBuilder::default().priority(priority_boost); log::trace!( - target: "runtime::bridge", - "{} via {:?} has boosted priority of message delivery transaction \ + target: LOG_TARGET, + "{}.{:?}: has boosted priority of message delivery transaction \ of relayer {:?}: {} messages -> {} priority", Self::IDENTIFIER, - ::Id::get(), + parsed_call.as_ref().map(|p| p.messages_call_info().lane_id()), who, bundled_messages, priority_boost, @@ -500,14 +339,14 @@ where _len: usize, ) -> Result { // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) - let parsed_call = T::parse_and_check_for_obsolete_call(call)?; + let parsed_call = C::parse_and_check_for_obsolete_call(call)?; Ok(parsed_call.map(|call_info| { log::trace!( - target: "runtime::bridge", - "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", + target: LOG_TARGET, + "{}.{:?}: parsed bridge transaction in pre-dispatch: {:?}", Self::IDENTIFIER, - ::Id::get(), + call_info.messages_call_info().lane_id(), call_info, ); PreDispatchData { relayer: who.clone(), call_info } @@ -521,28 +360,28 @@ where len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let call_result = T::analyze_call_result(pre, info, post_info, len, result); + let lane_id = pre + .as_ref() + .and_then(|p| p.as_ref()) + .map(|p| p.call_info.messages_call_info().lane_id()); + let call_result = Self::analyze_call_result(pre, info, post_info, len, result); match call_result { RelayerAccountAction::None => (), RelayerAccountAction::Reward(relayer, reward_account, reward) => { - RelayersPallet::::register_relayer_reward( - reward_account, - &relayer, - reward, - ); + RelayersPallet::::register_relayer_reward(reward_account, &relayer, reward); log::trace!( - target: "runtime::bridge", - "{} via {:?} has registered reward: {:?} for {:?}", + target: LOG_TARGET, + "{}.{:?}: has registered reward: {:?} for {:?}", Self::IDENTIFIER, - ::Id::get(), + lane_id, reward, relayer, ); }, RelayerAccountAction::Slash(relayer, slash_account) => - RelayersPallet::::slash_and_deregister( + RelayersPallet::::slash_and_deregister( &relayer, ExplicitOrAccountParams::Params(slash_account), ), @@ -552,411 +391,61 @@ where } } -/// Signed extension that refunds a relayer for new messages coming from a parachain. -/// -/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) -/// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. -/// -/// Extension does not refund transaction tip due to security reasons. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedParachainMessages( - PhantomData<( - // runtime with `frame-utility`, `pallet-bridge-grandpa`, `pallet-bridge-parachains`, - // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // implementation of `RefundableParachainId` trait, which specifies the instance of - // the used `pallet-bridge-parachains` pallet and the bridged parachain id - Para, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedParachainMessages -where - Self: 'static + Send + Sync, - RefundBridgedGrandpaMessages< - Runtime, - Runtime::BridgesGrandpaPalletInstance, - Msgs, - Refund, - Priority, - Id, - >: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + ParachainsConfig - + MessagesConfig - + RelayersConfig, - Para: RefundableParachainId, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + ParachainsCallSubType - + MessagesCallSubType, -{ - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 3 => - calls.iter().collect(), - Some(_) => vec![], - None => vec![call], - } - } - - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let calls = Self::expand_call(call); - let total_calls = calls.len(); - let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); - - let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); - let para_finality_call = calls - .next() - .transpose()? - .and_then(|c| c.submit_parachain_heads_info_for(Para::BridgedChain::PARACHAIN_ID)); - let relay_finality_call = - calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); - - Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { - (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => Some( - CallInfo::AllFinalityAndMsgs(relay_finality_call, para_finality_call, msgs_call), - ), - (2, None, Some(para_finality_call), Some(msgs_call)) => - Some(CallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), - (1, None, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), - _ => None, - }) - } - - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_submit_finality_proof()?; - call.check_obsolete_submit_parachain_heads()?; - call.check_obsolete_call()?; - Ok(call) - } - - fn additional_call_result_check( - relayer: &Runtime::AccountId, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool { - // check if relay chain state has been updated - let is_grandpa_call_successful = - RefundBridgedGrandpaMessages::< - Runtime, - Runtime::BridgesGrandpaPalletInstance, - Msgs, - Refund, - Priority, - Id, - >::additional_call_result_check(relayer, call_info, extra_weight, extra_size); - if !is_grandpa_call_successful { - return false - } - - // check if parachain state has been updated - if let Some(para_proof_info) = call_info.submit_parachain_heads_info() { - if !SubmitParachainHeadsHelper::::was_successful( - para_proof_info, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid parachain finality proof", - Id::STR, - Para::BridgedChain::PARACHAIN_ID, - Msgs::Id::get(), - relayer, - ); - return false - } - } - - true - } -} - -/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) -/// chain. -/// -/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) -/// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. -/// -/// Extension does not refund transaction tip due to security reasons. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedGrandpaMessages( - PhantomData<( - // runtime with `frame-utility`, `pallet-bridge-grandpa`, - // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // bridge GRANDPA pallet instance, used to track bridged chain state - GrandpaInstance, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedGrandpaMessages -where - Self: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + MessagesConfig - + RelayersConfig, - GrandpaInstance: 'static, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + MessagesCallSubType, -{ - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 2 => - calls.iter().collect(), - Some(_) => vec![], - None => vec![call], - } - } - - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let calls = Self::expand_call(call); - let total_calls = calls.len(); - let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); - - let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); - let relay_finality_call = - calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); - - Ok(match (total_calls, relay_finality_call, msgs_call) { - (2, Some(relay_finality_call), Some(msgs_call)) => - Some(CallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)), - (1, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), - _ => None, - }) - } - - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_submit_finality_proof()?; - call.check_obsolete_call()?; - Ok(call) - } - - fn additional_call_result_check( - relayer: &Runtime::AccountId, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool { - // check if relay chain state has been updated - if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { - if !SubmitFinalityProofHelper::::was_successful( - finality_proof_info.block_number, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", - Self::Id::STR, - ::Id::get(), - relayer, - ); - return false - } - - // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` - // transaction. If relay chain header is mandatory, the GRANDPA pallet returns - // `Pays::No`, because such transaction is mandatory for operating the bridge. But - // `utility.batchAll` transaction always requires payment. But in both cases we'll - // refund relayer - either explicitly here, or using `Pays::No` if he's choosing - // to submit dedicated transaction. - - // submitter has means to include extra weight/bytes in the `submit_finality_proof` - // call, so let's subtract extra weight/size to avoid refunding for this extra stuff - *extra_weight = (*extra_weight).saturating_add(finality_proof_info.extra_weight); - *extra_size = (*extra_size).saturating_add(finality_proof_info.extra_size); - } - - true - } -} - -/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation -/// transactions. Finality transactions are not refunded. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedMessages( - PhantomData<( - // runtime with `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedMessages +/// Verify that the messages pallet call, supported by extension has succeeded. +pub(crate) fn verify_messages_call_succeeded( + call_info: &ExtensionCallInfo, + _call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool where - Self: 'static + Send + Sync, - Runtime: MessagesConfig + RelayersConfig, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + MessagesCallSubType, + C: ExtensionConfig, + MI: 'static, + C::Runtime: BridgeMessagesConfig, { - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - vec![call] - } + let messages_call = call_info.messages_call_info(); - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let call = Self::check_obsolete_parsed_call(call)?; - Ok(call.call_info_for(Msgs::Id::get()).map(CallInfo::Msgs)) - } - - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_call()?; - Ok(call) + if !MessagesCallHelper::::was_successful(messages_call) { + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid messages call", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false } - fn additional_call_result_check( - _relayer: &Runtime::AccountId, - _call_info: &CallInfo, - _extra_weight: &mut Weight, - _extra_size: &mut u32, - ) -> bool { - // everything is checked by the `RefundTransactionExtension` - true - } + true } #[cfg(test)] -pub(crate) mod tests { +mod tests { use super::*; use crate::mock::*; - use bp_header_chain::StoredHeaderDataBuilder; + + use bp_header_chain::{StoredHeaderDataBuilder, SubmitFinalityProofInfo}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, DeliveredMessages, - InboundLaneData, LaneState, MessageNonce, MessagesOperatingMode, OutboundLaneData, - ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayer, - UnrewardedRelayerOccupation, UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, InboundLaneData, + LaneId, MessageNonce, MessagesCallInfo, MessagesOperatingMode, OutboundLaneData, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, + UnrewardedRelayersState, }; - use bp_parachains::{BestParaHeadHash, ParaInfo}; + use bp_parachains::{BestParaHeadHash, ParaInfo, SubmitParachainHeadsInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; - use bp_runtime::{BasicOperatingMode, HeaderId}; + use bp_relayers::RuntimeWithUtilityPallet; + use bp_runtime::{BasicOperatingMode, HeaderId, Parachain}; use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; use frame_support::{ + __private::sp_tracing, assert_storage_noop, parameter_types, traits::{fungible::Mutate, ReservableCurrency}, weights::Weight, }; use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet}; use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet}; - use pallet_bridge_parachains::{ - Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, - }; + use pallet_bridge_parachains::{Call as ParachainsCall, Pallet as ParachainsPallet}; + use pallet_utility::Call as UtilityCall; use sp_runtime::{ traits::{ConstU64, Header as HeaderT}, transaction_validity::{InvalidTransaction, ValidTransaction}, @@ -964,7 +453,7 @@ pub(crate) mod tests { }; parameter_types! { - TestParachain: u32 = 1000; + TestParachain: u32 = BridgedUnderlyingParachain::PARACHAIN_ID; pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( test_lane_id(), TEST_BRIDGED_CHAIN_ID, @@ -980,35 +469,32 @@ pub(crate) mod tests { bp_runtime::generate_static_str_provider!(TestExtension); - type TestMessagesExtensionProvider = RefundBridgedMessages< - TestRuntime, - RefundableMessagesLane, - ActualFeeRefund, - ConstU64<1>, - StrTestExtension, - >; - type TestMessagesExtension = RefundSignedExtensionAdapter; - type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< + type TestGrandpaExtensionConfig = grandpa_adapter::WithGrandpaChainExtensionConfig< + StrTestId, TestRuntime, + RuntimeWithUtilityPallet, + (), (), - RefundableMessagesLane, - ActualFeeRefund, ConstU64<1>, - StrTestExtension, >; - type TestGrandpaExtension = RefundSignedExtensionAdapter; - type TestExtensionProvider = RefundBridgedParachainMessages< + type TestGrandpaExtension = + BridgeRelayersSignedExtension; + type TestExtensionConfig = parachain_adapter::WithParachainExtensionConfig< + StrTestId, TestRuntime, - RefundableParachain<(), BridgedUnderlyingParachain>, - RefundableMessagesLane, - ActualFeeRefund, + RuntimeWithUtilityPallet, + (), + (), ConstU64<1>, - StrTestExtension, >; - type TestExtension = RefundSignedExtensionAdapter; + type TestExtension = BridgeRelayersSignedExtension; + + fn test_lane_id() -> LaneId { + LaneId::new(1, 2) + } fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { - let test_stake: ThisChainBalance = TestStake::get(); + let test_stake: ThisChainBalance = Stake::get(); ExistentialDeposit::get().saturating_add(test_stake * 100) } @@ -1023,7 +509,7 @@ pub(crate) mod tests { TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get()) } - pub fn relayer_account_at_this_chain() -> ThisChainAccountId { + fn relayer_account_at_this_chain() -> ThisChainAccountId { 0 } @@ -1031,13 +517,13 @@ pub(crate) mod tests { 0 } - pub fn initialize_environment( - best_relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + fn initialize_environment( + best_relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) { let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); - let best_relay_header = HeaderId(best_relay_header_number, RelayBlockHash::default()); + let best_relay_header = HeaderId(best_relay_header_number, BridgedChainHash::default()); pallet_bridge_grandpa::CurrentAuthoritySet::::put( StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(), ); @@ -1047,7 +533,7 @@ pub(crate) mod tests { bp_test_utils::test_header::(0).build(), ); - let para_id = ParaId(BridgedUnderlyingParachain::PARACHAIN_ID); + let para_id = ParaId(TestParachain::get()); let para_info = ParaInfo { best_head_hash: BestParaHeadHash { at_relay_block_number: parachain_head_at_relay_header_number, @@ -1075,7 +561,7 @@ pub(crate) mod tests { .unwrap(); } - fn submit_relay_header_call(relay_header_number: RelayBlockNumber) -> RuntimeCall { + fn submit_relay_header_call(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { let relay_header = BridgedChainHeader::new( relay_header_number, Default::default(), @@ -1091,7 +577,7 @@ pub(crate) mod tests { }) } - pub fn submit_relay_header_call_ex(relay_header_number: RelayBlockNumber) -> RuntimeCall { + fn submit_relay_header_call_ex(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { let relay_header = BridgedChainHeader::new( relay_header_number, Default::default(), @@ -1110,12 +596,12 @@ pub(crate) mod tests { } fn submit_parachain_head_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, ) -> RuntimeCall { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { - at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), parachains: vec![( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + ParaId(TestParachain::get()), [parachain_head_at_relay_header_number as u8; 32].into(), )], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, @@ -1123,12 +609,12 @@ pub(crate) mod tests { } pub fn submit_parachain_head_call_ex( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, ) -> RuntimeCall { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads_ex { - at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), parachains: vec![( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + ParaId(TestParachain::get()), [parachain_head_at_relay_header_number as u8; 32].into(), )], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, @@ -1171,7 +657,7 @@ pub(crate) mod tests { } fn parachain_finality_and_delivery_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1183,7 +669,7 @@ pub(crate) mod tests { } fn parachain_finality_and_confirmation_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1195,7 +681,7 @@ pub(crate) mod tests { } fn relay_finality_and_delivery_batch_call( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1207,7 +693,7 @@ pub(crate) mod tests { } fn relay_finality_and_delivery_batch_call_ex( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1219,7 +705,7 @@ pub(crate) mod tests { } fn relay_finality_and_confirmation_batch_call( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1231,7 +717,7 @@ pub(crate) mod tests { } fn relay_finality_and_confirmation_batch_call_ex( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1243,8 +729,8 @@ pub(crate) mod tests { } fn all_finality_and_delivery_batch_call( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1257,8 +743,8 @@ pub(crate) mod tests { } fn all_finality_and_delivery_batch_call_ex( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1271,8 +757,8 @@ pub(crate) mod tests { } fn all_finality_and_confirmation_batch_call( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1285,8 +771,8 @@ pub(crate) mod tests { } fn all_finality_and_confirmation_batch_call_ex( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1298,10 +784,11 @@ pub(crate) mod tests { }) } - fn all_finality_pre_dispatch_data() -> PreDispatchData { + fn all_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::AllFinalityAndMsgs( + call_info: ExtensionCallInfo::AllFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1312,7 +799,7 @@ pub(crate) mod tests { }, SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, @@ -1324,26 +811,28 @@ pub(crate) mod tests { }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn all_finality_pre_dispatch_data_ex() -> PreDispatchData { + #[cfg(test)] + fn all_finality_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = all_finality_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn all_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn all_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::AllFinalityAndMsgs( + call_info: ExtensionCallInfo::AllFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1354,7 +843,7 @@ pub(crate) mod tests { }, SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, @@ -1369,17 +858,18 @@ pub(crate) mod tests { } } - fn all_finality_confirmation_pre_dispatch_data_ex() -> PreDispatchData { + fn all_finality_confirmation_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = all_finality_confirmation_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn relay_finality_pre_dispatch_data() -> PreDispatchData { + fn relay_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::RelayFinalityAndMsgs( + call_info: ExtensionCallInfo::RelayFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1396,26 +886,27 @@ pub(crate) mod tests { }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn relay_finality_pre_dispatch_data_ex() -> PreDispatchData { + fn relay_finality_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = relay_finality_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn relay_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn relay_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::RelayFinalityAndMsgs( + call_info: ExtensionCallInfo::RelayFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1435,20 +926,21 @@ pub(crate) mod tests { } } - fn relay_finality_confirmation_pre_dispatch_data_ex() -> PreDispatchData { + fn relay_finality_confirmation_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = relay_finality_confirmation_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn parachain_finality_pre_dispatch_data() -> PreDispatchData { + fn parachain_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::ParachainFinalityAndMsgs( + call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, @@ -1460,22 +952,23 @@ pub(crate) mod tests { }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn parachain_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn parachain_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::ParachainFinalityAndMsgs( + call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, @@ -1490,10 +983,11 @@ pub(crate) mod tests { } } - fn delivery_pre_dispatch_data() -> PreDispatchData { + fn delivery_pre_dispatch_data() -> PreDispatchData + { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( + call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { lane_id: test_lane_id(), @@ -1502,19 +996,20 @@ pub(crate) mod tests { }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }, )), } } - fn confirmation_pre_dispatch_data() -> PreDispatchData { + fn confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( + call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: test_lane_id(), bundled_range: 101..=200, @@ -1525,14 +1020,14 @@ pub(crate) mod tests { } fn set_bundled_range_end( - mut pre_dispatch_data: PreDispatchData, + mut pre_dispatch_data: PreDispatchData, end: MessageNonce, - ) -> PreDispatchData { + ) -> PreDispatchData { let msg_info = match pre_dispatch_data.call_info { - CallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, - CallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, - CallInfo::ParachainFinalityAndMsgs(_, ref mut info) => info, - CallInfo::Msgs(ref mut info) => info, + ExtensionCallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, + ExtensionCallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, + ExtensionCallInfo::ParachainFinalityAndMsgs(_, ref mut info) => info, + ExtensionCallInfo::Msgs(ref mut info) => info, }; if let MessagesCallInfo::ReceiveMessagesProof(ref mut msg_info) = msg_info { @@ -1543,22 +1038,21 @@ pub(crate) mod tests { } fn run_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + let extension: TestExtension = BridgeRelayersSignedExtension(PhantomData); extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + let extension: TestGrandpaExtension = BridgeRelayersSignedExtension(PhantomData); extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } - fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestMessagesExtension = - RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) - } + // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 + // fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { + // let extension: TestMessagesExtension = + // RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); + // extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + // } fn ignore_priority(tx: TransactionValidity) -> TransactionValidity { tx.map(|mut tx| { @@ -1569,27 +1063,33 @@ pub(crate) mod tests { fn run_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + ) -> Result< + Option>, + TransactionValidityError, + > { + sp_tracing::try_init_simple(); + let extension: TestExtension = BridgeRelayersSignedExtension(PhantomData); extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + ) -> Result< + Option>, + TransactionValidityError, + > { + let extension: TestGrandpaExtension = BridgeRelayersSignedExtension(PhantomData); extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } - fn run_messages_pre_dispatch( - call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestMessagesExtension = - RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) - } + // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 + // fn run_messages_pre_dispatch( + // call: RuntimeCall, + // ) -> Result>, TransactionValidityError> { + // let extension: TestMessagesExtension = + // RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); + // extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + // } fn dispatch_info() -> DispatchInfo { DispatchInfo { @@ -1607,7 +1107,7 @@ pub(crate) mod tests { } fn run_post_dispatch( - pre_dispatch_data: Option>, + pre_dispatch_data: Option>, dispatch_result: DispatchResult, ) { let post_dispatch_result = TestExtension::post_dispatch( @@ -1649,46 +1149,28 @@ pub(crate) mod tests { Balances::set_balance(&relayer_account_at_this_chain(), ExistentialDeposit::get()); // message delivery is failing - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - assert_eq!(f(message_delivery_call(200)), Ok(Default::default()),); - assert_eq!( - f(parachain_finality_and_delivery_batch_call(200, 200)), - Ok(Default::default()), - ); - assert_eq!( - f(all_finality_and_delivery_batch_call(200, 200, 200)), - Ok(Default::default()), - ); - assert_eq!( - f(all_finality_and_delivery_batch_call_ex(200, 200, 200)), - Ok(Default::default()), - ); - } - - // message confirmation validation is passing + assert_eq!(run_validate(message_delivery_call(200)), Ok(Default::default()),); assert_eq!( - ignore_priority(run_validate(message_confirmation_call(200))), + run_validate(parachain_finality_and_delivery_batch_call(200, 200)), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_messages_validate(message_confirmation_call(200))), + run_validate(all_finality_and_delivery_batch_call(200, 200, 200)), Ok(Default::default()), ); + // message confirmation validation is passing assert_eq!( - ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( - 200, 200 - ))), + ignore_priority(run_validate(message_confirmation_call(200))), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call( - 200, 200, 200 + ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( + 200, 200 ))), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 ))), Ok(Default::default()), @@ -1704,28 +1186,25 @@ pub(crate) mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - let priority_of_100_messages_delivery = - f(message_delivery_call(200)).unwrap().priority; - let priority_of_200_messages_delivery = - f(message_delivery_call(300)).unwrap().priority; - assert!( - priority_of_200_messages_delivery > priority_of_100_messages_delivery, - "Invalid priorities: {} for 200 messages vs {} for 100 messages", - priority_of_200_messages_delivery, - priority_of_100_messages_delivery, - ); + let priority_of_100_messages_delivery = + run_validate(message_delivery_call(200)).unwrap().priority; + let priority_of_200_messages_delivery = + run_validate(message_delivery_call(300)).unwrap().priority; + assert!( + priority_of_200_messages_delivery > priority_of_100_messages_delivery, + "Invalid priorities: {} for 200 messages vs {} for 100 messages", + priority_of_200_messages_delivery, + priority_of_100_messages_delivery, + ); - let priority_of_100_messages_confirmation = - f(message_confirmation_call(200)).unwrap().priority; - let priority_of_200_messages_confirmation = - f(message_confirmation_call(300)).unwrap().priority; - assert_eq!( - priority_of_100_messages_confirmation, - priority_of_200_messages_confirmation - ); - } + let priority_of_100_messages_confirmation = + run_validate(message_confirmation_call(200)).unwrap().priority; + let priority_of_200_messages_confirmation = + run_validate(message_confirmation_call(300)).unwrap().priority; + assert_eq!( + priority_of_100_messages_confirmation, + priority_of_200_messages_confirmation + ); }); } @@ -1737,26 +1216,23 @@ pub(crate) mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - let priority_of_max_messages_delivery = f(message_delivery_call( - 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - )) - .unwrap() - .priority; - let priority_of_more_than_max_messages_delivery = f(message_delivery_call( - 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1, - )) - .unwrap() - .priority; + let priority_of_max_messages_delivery = run_validate(message_delivery_call( + 100 + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + )) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = run_validate(message_delivery_call( + 100 + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1, + )) + .unwrap() + .priority; - assert!( - priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, - "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", - priority_of_max_messages_delivery, - priority_of_more_than_max_messages_delivery, - ); - } + assert!( + priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, + "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", + priority_of_max_messages_delivery, + priority_of_more_than_max_messages_delivery, + ); }); } @@ -1773,15 +1249,11 @@ pub(crate) mod tests { ignore_priority(run_validate(message_confirmation_call(200))), Ok(ValidTransaction::default()), ); - - assert_eq!( - ignore_priority(run_messages_validate(message_delivery_call(200))), - Ok(ValidTransaction::default()), - ); - assert_eq!( - ignore_priority(run_messages_validate(message_confirmation_call(200))), - Ok(ValidTransaction::default()), - ); + // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 + // assert_eq!( + // ignore_priority(run_messages_validate(message_delivery_call(200))), + // Ok(ValidTransaction::default()), + // ); assert_eq!( ignore_priority(run_validate(parachain_finality_and_delivery_batch_call(200, 200))), @@ -1798,24 +1270,12 @@ pub(crate) mod tests { ignore_priority(run_validate(all_finality_and_delivery_batch_call(200, 200, 200))), Ok(ValidTransaction::default()), ); - assert_eq!( - ignore_priority(run_validate(all_finality_and_delivery_batch_call_ex( - 200, 200, 200 - ))), - Ok(ValidTransaction::default()), - ); assert_eq!( ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 ))), Ok(ValidTransaction::default()), ); - assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( - 200, 200, 200 - ))), - Ok(ValidTransaction::default()), - ); }); } @@ -2101,13 +1561,10 @@ pub(crate) mod tests { let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { - at_relay_block: (100, RelayBlockHash::default()), + at_relay_block: (100, BridgedChainHash::default()), parachains: vec![ - (ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [1u8; 32].into()), - ( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID + 1), - [1u8; 32].into(), - ), + (ParaId(TestParachain::get()), [1u8; 32].into()), + (ParaId(TestParachain::get() + 1), [1u8; 32].into()), ], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, }), @@ -2248,7 +1705,7 @@ pub(crate) mod tests { // now repeat the same with size+weight refund: we expect smaller reward let mut pre_dispatch_data = all_finality_pre_dispatch_data(); match pre_dispatch_data.call_info { - CallInfo::AllFinalityAndMsgs(ref mut info, ..) => { + ExtensionCallInfo::AllFinalityAndMsgs(ref mut info, ..) => { info.extra_weight.set_ref_time( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, ); @@ -2354,7 +1811,7 @@ pub(crate) mod tests { let delivery_rewards_account_balance = Balances::free_balance(delivery_rewards_account()); - let test_stake: ThisChainBalance = TestStake::get(); + let test_stake: ThisChainBalance = Stake::get(); Balances::set_balance( &relayer_account_at_this_chain(), ExistentialDeposit::get() + test_stake * 10, @@ -2424,10 +1881,10 @@ pub(crate) mod tests { } fn run_analyze_call_result( - pre_dispatch_data: PreDispatchData, + pre_dispatch_data: PreDispatchData, dispatch_result: DispatchResult, ) -> RelayerAccountAction { - TestExtensionProvider::analyze_call_result( + TestExtension::analyze_call_result( Some(Some(pre_dispatch_data)), &dispatch_info(), &post_dispatch_info(), @@ -2491,148 +1948,6 @@ pub(crate) mod tests { }); } - #[test] - fn messages_ext_only_parses_standalone_transactions() { - run_test(|| { - initialize_environment(100, 100, 100); - - // relay + parachain + message delivery calls batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_delivery_batch_call(200, 200, 200) - ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_delivery_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); - - // relay + parachain + message confirmation calls batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_confirmation_batch_call(200, 200, 200) - ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_confirmation_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); - - // parachain + message delivery call batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - ¶chain_finality_and_delivery_batch_call(200, 200) - ), - Ok(None), - ); - - // parachain + message confirmation call batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - ¶chain_finality_and_confirmation_batch_call(200, 200) - ), - Ok(None), - ); - - // relay + message delivery call batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_delivery_batch_call(200, 200) - ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_delivery_batch_call_ex(200, 200) - ), - Ok(None), - ); - - // relay + message confirmation call batch is ignored - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_confirmation_batch_call(200, 200) - ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_confirmation_batch_call_ex(200, 200) - ), - Ok(None), - ); - - // message delivery call batch is accepted - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &message_delivery_call(200) - ), - Ok(Some(delivery_pre_dispatch_data().call_info)), - ); - - // message confirmation call batch is accepted - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &message_confirmation_call(200) - ), - Ok(Some(confirmation_pre_dispatch_data().call_info)), - ); - }); - } - - #[test] - fn messages_ext_rejects_calls_with_obsolete_messages() { - run_test(|| { - initialize_environment(100, 100, 100); - - assert_eq!( - run_messages_pre_dispatch(message_delivery_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - assert_eq!( - run_messages_pre_dispatch(message_confirmation_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - - assert_eq!( - run_messages_validate(message_delivery_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - assert_eq!( - run_messages_validate(message_confirmation_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - }); - } - - #[test] - fn messages_ext_accepts_calls_with_new_messages() { - run_test(|| { - initialize_environment(100, 100, 100); - - assert_eq!( - run_messages_pre_dispatch(message_delivery_call(200)), - Ok(Some(delivery_pre_dispatch_data())), - ); - assert_eq!( - run_messages_pre_dispatch(message_confirmation_call(200)), - Ok(Some(confirmation_pre_dispatch_data())), - ); - - assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); - assert_eq!( - run_messages_validate(message_confirmation_call(200)), - Ok(Default::default()), - ); - }); - } - #[test] fn grandpa_ext_only_parses_valid_batches() { run_test(|| { @@ -2640,35 +1955,23 @@ pub(crate) mod tests { // relay + parachain + message delivery calls batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_delivery_batch_call(200, 200, 200) ), Ok(None), ); - assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_delivery_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); // relay + parachain + message confirmation calls batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_confirmation_batch_call(200, 200, 200) ), Ok(None), ); - assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_confirmation_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); // parachain + message delivery call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_delivery_batch_call(200, 200) ), Ok(None), @@ -2676,7 +1979,7 @@ pub(crate) mod tests { // parachain + message confirmation call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_confirmation_batch_call(200, 200) ), Ok(None), @@ -2684,35 +1987,23 @@ pub(crate) mod tests { // relay + message delivery call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_delivery_batch_call(200, 200) ), Ok(Some(relay_finality_pre_dispatch_data().call_info)), ); - assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_delivery_batch_call_ex(200, 200) - ), - Ok(Some(relay_finality_pre_dispatch_data_ex().call_info)), - ); // relay + message confirmation call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_confirmation_batch_call(200, 200) ), Ok(Some(relay_finality_confirmation_pre_dispatch_data().call_info)), ); - assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_confirmation_batch_call_ex(200, 200) - ), - Ok(Some(relay_finality_confirmation_pre_dispatch_data_ex().call_info)), - ); // message delivery call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &message_delivery_call(200) ), Ok(Some(delivery_pre_dispatch_data().call_info)), @@ -2720,7 +2011,7 @@ pub(crate) mod tests { // message confirmation call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &message_confirmation_call(200) ), Ok(Some(confirmation_pre_dispatch_data().call_info)), @@ -2728,6 +2019,149 @@ pub(crate) mod tests { }); } + // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 + // #[test] + // fn messages_ext_only_parses_standalone_transactions() { + // run_test(|| { + // initialize_environment(100, 100, 100); + // + // // relay + parachain + message delivery calls batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &all_finality_and_delivery_batch_call(200, 200, 200) + // ), + // Ok(None), + // ); + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &all_finality_and_delivery_batch_call_ex(200, 200, 200) + // ), + // Ok(None), + // ); + // + // // relay + parachain + message confirmation calls batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &all_finality_and_confirmation_batch_call(200, 200, 200) + // ), + // Ok(None), + // ); + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &all_finality_and_confirmation_batch_call_ex(200, 200, 200) + // ), + // Ok(None), + // ); + // + // // parachain + message delivery call batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // ¶chain_finality_and_delivery_batch_call(200, 200) + // ), + // Ok(None), + // ); + // + // // parachain + message confirmation call batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // ¶chain_finality_and_confirmation_batch_call(200, 200) + // ), + // Ok(None), + // ); + // + // // relay + message delivery call batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &relay_finality_and_delivery_batch_call(200, 200) + // ), + // Ok(None), + // ); + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &relay_finality_and_delivery_batch_call_ex(200, 200) + // ), + // Ok(None), + // ); + // + // // relay + message confirmation call batch is ignored + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &relay_finality_and_confirmation_batch_call(200, 200) + // ), + // Ok(None), + // ); + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &relay_finality_and_confirmation_batch_call_ex(200, 200) + // ), + // Ok(None), + // ); + // + // // message delivery call batch is accepted + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &message_delivery_call(200) + // ), + // Ok(Some(delivery_pre_dispatch_data().call_info)), + // ); + // + // // message confirmation call batch is accepted + // assert_eq!( + // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + // &message_confirmation_call(200) + // ), + // Ok(Some(confirmation_pre_dispatch_data().call_info)), + // ); + // }); + // } + // + // #[test] + // fn messages_ext_rejects_calls_with_obsolete_messages() { + // run_test(|| { + // initialize_environment(100, 100, 100); + // + // assert_eq!( + // run_messages_pre_dispatch(message_delivery_call(100)), + // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + // ); + // assert_eq!( + // run_messages_pre_dispatch(message_confirmation_call(100)), + // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + // ); + // + // assert_eq!( + // run_messages_validate(message_delivery_call(100)), + // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + // ); + // assert_eq!( + // run_messages_validate(message_confirmation_call(100)), + // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + // ); + // }); + // } + // + // #[test] + // fn messages_ext_accepts_calls_with_new_messages() { + // run_test(|| { + // initialize_environment(100, 100, 100); + // + // assert_eq!( + // run_messages_pre_dispatch(message_delivery_call(200)), + // Ok(Some(delivery_pre_dispatch_data())), + // ); + // assert_eq!( + // run_messages_pre_dispatch(message_confirmation_call(200)), + // Ok(Some(confirmation_pre_dispatch_data())), + // ); + // + // assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); + // assert_eq!( + // run_messages_validate(message_confirmation_call(200)), + // Ok(Default::default()), + // ); + // }); + // } + #[test] fn grandpa_ext_rejects_batch_with_obsolete_relay_chain_header() { run_test(|| { @@ -2867,40 +2301,4 @@ pub(crate) mod tests { ); }); } - - #[test] - fn does_not_panic_on_boosting_priority_of_empty_message_delivery_transaction() { - run_test(|| { - let best_delivered_message = - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - initialize_environment(100, 100, best_delivered_message); - - // register relayer so it gets priority boost - BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) - .unwrap(); - - // allow empty message delivery transactions - let lane_id = test_lane_id(); - let in_lane_data = InboundLaneData { - state: LaneState::Opened, - last_confirmed_nonce: 0, - relayers: vec![UnrewardedRelayer { - relayer: relayer_account_at_bridged_chain(), - messages: DeliveredMessages { begin: 1, end: best_delivered_message }, - }] - .into(), - }; - pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); - - // now check that the priority of empty tx is the same as priority of 1-message tx - let priority_of_zero_messages_delivery = - run_validate(message_delivery_call(best_delivered_message)).unwrap().priority; - let priority_of_one_messages_delivery = - run_validate(message_delivery_call(best_delivered_message + 1)) - .unwrap() - .priority; - - assert_eq!(priority_of_zero_messages_delivery, priority_of_one_messages_delivery); - }); - } } diff --git a/bridges/modules/relayers/src/extension/parachain_adapter.rs b/bridges/modules/relayers/src/extension/parachain_adapter.rs new file mode 100644 index 000000000000..b6f57cebc309 --- /dev/null +++ b/bridges/modules/relayers/src/extension/parachain_adapter.rs @@ -0,0 +1,182 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with remote parachain. + +use crate::{ + extension::{ + grandpa_adapter::verify_submit_finality_proof_succeeded, verify_messages_call_succeeded, + }, + Config as BridgeRelayersConfig, LOG_TARGET, +}; + +use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::{Parachain, StaticStrProvider}; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::Config as SystemConfig; +use pallet_bridge_grandpa::{ + CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig, +}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, +}; +use pallet_bridge_parachains::{ + CallSubType as BridgeParachainsCallSubtype, Config as BridgeParachainsConfig, + SubmitParachainHeadsHelper, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, +}; +use sp_std::marker::PhantomData; + +/// Adapter to be used in signed extension configuration, when bridging with remote parachains. +pub struct WithParachainExtensionConfig< + // signed extension identifier + IdProvider, + // runtime that implements `BridgeMessagesConfig`, which + // uses `BridgeParachainsConfig` to receive messages and + // confirmations from the remote chain. + Runtime, + // batch call unpacker + BatchCallUnpacker, + // instance of the `pallet-bridge-parachains`, tracked by this extension + BridgeParachainsPalletInstance, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, +>( + PhantomData<( + IdProvider, + Runtime, + BatchCallUnpacker, + BridgeParachainsPalletInstance, + BridgeMessagesPalletInstance, + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig for WithParachainExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + + BridgeMessagesConfig + + BridgeParachainsConfig + + BridgeGrandpaConfig, + BCU: BatchCallUnpacker, + PI: 'static, + MI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeGrandpaCallSubtype + + BridgeParachainsCallSubtype + + BridgeMessagesCallSubType, + >::BridgedChain: Parachain, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type PriorityBoostPerMessage = P; + type Reward = R::Reward; + type RemoteGrandpaChainBlockNumber = + pallet_bridge_grandpa::BridgedBlockNumber; + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let calls = BCU::unpack(call, 3); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info()); + let para_finality_call = calls.next().transpose()?.and_then(|c| { + let r = c.submit_parachain_heads_info_for( + >::BridgedChain::PARACHAIN_ID, + ); + r + }); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { + (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::AllFinalityAndMsgs( + relay_finality_call, + para_finality_call, + msgs_call, + )), + (2, None, Some(para_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), + (1, None, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_submit_parachain_heads()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_submit_finality_proof_succeeded::( + call_info, call_data, relayer, + ) && verify_submit_parachain_head_succeeded::(call_info, call_data, relayer) && + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} + +/// If the batch call contains the parachain state update call, verify that it +/// has been successful. +/// +/// Only returns false when parachain state update call has failed. +pub(crate) fn verify_submit_parachain_head_succeeded( + call_info: &ExtensionCallInfo, + _call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool +where + C: ExtensionConfig, + PI: 'static, + C::Runtime: BridgeParachainsConfig, +{ + let Some(para_proof_info) = call_info.submit_parachain_heads_info() else { return true }; + + if !SubmitParachainHeadsHelper::::was_successful(para_proof_info) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid parachain finality proof", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false + } + + true +} diff --git a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs b/bridges/modules/relayers/src/extension/priority.rs similarity index 96% rename from bridges/bin/runtime-common/src/extensions/priority_calculator.rs rename to bridges/modules/relayers/src/extension/priority.rs index 9f559dc13b64..da188eaf5bdd 100644 --- a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs +++ b/bridges/modules/relayers/src/extension/priority.rs @@ -50,7 +50,6 @@ mod integrity_tests {} #[cfg(feature = "integrity-test")] mod integrity_tests { use super::{compute_priority_boost, ItemCount}; - use crate::extensions::refund_relayer_extension::RefundableParachainId; use bp_messages::MessageNonce; use bp_runtime::PreComputedSize; @@ -239,12 +238,18 @@ mod integrity_tests { /// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want /// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority /// will be close to `TX2` as well. - pub fn ensure_priority_boost_is_sane( + pub fn ensure_priority_boost_is_sane< + Runtime, + ParachainsInstance, + Para, + PriorityBoostPerHeader, + >( tip_boost_per_header: BalanceOf, ) where Runtime: pallet_transaction_payment::Config - + pallet_bridge_parachains::Config, - RefundableParachain: RefundableParachainId, + + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, PriorityBoostPerHeader: Get, Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, @@ -263,7 +268,8 @@ mod integrity_tests { |_n_headers, tip| { estimate_parachain_header_submit_transaction_priority::< Runtime, - RefundableParachain, + ParachainsInstance, + Para, >(tip) }, ); @@ -271,13 +277,18 @@ mod integrity_tests { /// Estimate parachain header delivery transaction priority. #[cfg(feature = "integrity-test")] - fn estimate_parachain_header_submit_transaction_priority( + fn estimate_parachain_header_submit_transaction_priority< + Runtime, + ParachainsInstance, + Para, + >( tip: BalanceOf, ) -> TransactionPriority where Runtime: pallet_transaction_payment::Config - + pallet_bridge_parachains::Config, - RefundableParachain: RefundableParachainId, + + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { @@ -287,14 +298,14 @@ mod integrity_tests { let base_tx_size = 512; // let's say we are relaying largest parachain headers and proof takes some more bytes let tx_call_size = >::WeightInfo::expected_extra_storage_proof_size() - .saturating_add(RefundableParachain::BridgedChain::MAX_HEADER_SIZE); + .saturating_add(Para::MAX_HEADER_SIZE); // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(tx_call_size); let transaction_weight = >::WeightInfo::submit_parachain_heads_weight( Runtime::DbWeight::get(), &PreComputedSize(transaction_size as _), diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index 114f8ca3fb1c..b9627774db1e 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -36,13 +36,13 @@ pub use stake_adapter::StakeAndSlashNamed; pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; -pub mod benchmarking; - mod mock; mod payment_adapter; mod stake_adapter; mod weights_ext; +pub mod benchmarking; +pub mod extension; pub mod weights; /// The target that will be used when publishing logs related to this pallet. @@ -502,7 +502,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(RewardRegistered { + event: TestEvent::BridgeRelayers(RewardRegistered { relayer: REGULAR_RELAYER, rewards_account_params: test_reward_account_param(), reward: 100 @@ -581,7 +581,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(RewardPaid { + event: TestEvent::BridgeRelayers(RewardPaid { relayer: REGULAR_RELAYER, rewards_account_params: test_reward_account_param(), reward: 100 @@ -595,7 +595,8 @@ mod tests { #[test] fn pay_reward_from_account_actually_pays_reward() { type Balances = pallet_balances::Pallet; - type PayLaneRewardFromAccount = bp_relayers::PayRewardFromAccount; + type PayLaneRewardFromAccount = + bp_relayers::PayRewardFromAccount; run_test(|| { let in_lane_0 = RewardsAccountParams::new( @@ -676,7 +677,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() }, }), @@ -744,7 +745,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() } }), @@ -808,7 +809,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() } }), @@ -870,7 +871,9 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::Deregistered { relayer: REGISTER_RELAYER }), + event: TestEvent::BridgeRelayers(Event::Deregistered { + relayer: REGISTER_RELAYER + }), topics: vec![], }), ); diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 81993589de61..43aeec8bfc3b 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -18,51 +18,187 @@ use crate as pallet_bridge_relayers; -use bp_messages::LaneId; +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ + target_chain::{DispatchMessage, MessageDispatch}, + ChainWithMessages, LaneId, MessageNonce, +}; +use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::{ PayRewardFromAccount, PaymentProcedure, RewardsAccountOwner, RewardsAccountParams, }; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Parachain}; +use codec::Encode; use frame_support::{ - derive_impl, parameter_types, traits::fungible::Mutate, weights::RuntimeDbWeight, + derive_impl, parameter_types, + traits::fungible::Mutate, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, +}; +use pallet_transaction_payment::Multiplier; +use sp_core::{ConstU64, ConstU8, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, ConstU32}, + BuildStorage, FixedPointNumber, Perquintill, StateVersion, }; -use sp_runtime::BuildStorage; -pub type AccountId = u64; -pub type Balance = u64; -pub type BlockNumber = u64; +// generate identifier of the signed extension +bp_runtime::generate_static_str_provider!(TestId); + +/// Account identifier at `ThisChain`. +pub type ThisChainAccountId = u64; +/// Balance at `ThisChain`. +pub type ThisChainBalance = u64; +/// Block number at `ThisChain`. +pub type ThisChainBlockNumber = u32; +/// Hash at `ThisChain`. +pub type ThisChainHash = H256; +/// Hasher at `ThisChain`. +pub type ThisChainHasher = BlakeTwo256; +/// Header of `ThisChain`. +pub type ThisChainHeader = sp_runtime::generic::Header; +/// Block of `ThisChain`. +pub type ThisChainBlock = frame_system::mocking::MockBlockU32; + +/// Account identifier at the `BridgedChain`. +pub type BridgedChainAccountId = u128; +/// Balance at the `BridgedChain`. +pub type BridgedChainBalance = u128; +/// Block number at the `BridgedChain`. +pub type BridgedChainBlockNumber = u32; +/// Hash at the `BridgedChain`. +pub type BridgedChainHash = H256; +/// Hasher at the `BridgedChain`. +pub type BridgedChainHasher = BlakeTwo256; +/// Header of the `BridgedChain`. +pub type BridgedChainHeader = + sp_runtime::generic::Header; + +/// Bridged chain id used in tests. +pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; +/// Maximal extrinsic size at the `BridgedChain`. +pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; + +/// Underlying chain of `ThisChain`. +pub struct ThisUnderlyingChain; + +impl Chain for ThisUnderlyingChain { + const ID: ChainId = *b"tuch"; + + type BlockNumber = ThisChainBlockNumber; + type Hash = ThisChainHash; + type Hasher = ThisChainHasher; + type Header = ThisChainHeader; + type AccountId = ThisChainAccountId; + type Balance = ThisChainBalance; + type Nonce = u32; + type Signature = sp_runtime::MultiSignature; + + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl ChainWithMessages for ThisUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + +/// Underlying chain of `BridgedChain`. +pub struct BridgedUnderlyingParachain; + +impl Chain for BridgedUnderlyingParachain { + const ID: ChainId = TEST_BRIDGED_CHAIN_ID; + + type BlockNumber = BridgedChainBlockNumber; + type Hash = BridgedChainHash; + type Hasher = BridgedChainHasher; + type Header = BridgedChainHeader; + type AccountId = BridgedChainAccountId; + type Balance = BridgedChainBalance; + type Nonce = u32; + type Signature = sp_runtime::MultiSignature; + + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl ChainWithGrandpa for BridgedUnderlyingParachain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; +} + +impl ChainWithMessages for BridgedUnderlyingParachain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + +impl Parachain for BridgedUnderlyingParachain { + const PARACHAIN_ID: u32 = 42; + const MAX_HEADER_SIZE: u32 = 1_024; +} pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< - AccountId, - BlockNumber, + ThisChainAccountId, + ThisChainBlockNumber, Balances, ReserveId, Stake, Lease, >; -type Block = frame_system::mocking::MockBlock; - frame_support::construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Event}, - Relayers: pallet_bridge_relayers::{Pallet, Call, Event}, + Utility: pallet_utility, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, + BridgeMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, } } parameter_types! { + pub const BridgedParasPalletName: &'static str = "Paras"; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; - pub const ExistentialDeposit: Balance = 1; + pub const ExistentialDeposit: ThisChainBalance = 1; pub const ReserveId: [u8; 8] = *b"brdgrlrs"; - pub const Stake: Balance = 1_000; - pub const Lease: BlockNumber = 8; + pub const Stake: ThisChainBalance = 1_000; + pub const Lease: ThisChainBlockNumber = 8; + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); + pub const TransactionBaseFee: ThisChainBalance = 0; + pub const TransactionByteFee: ThisChainBalance = 1; + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { - type Block = Block; - type AccountData = pallet_balances::AccountData; + type Block = ThisChainBlock; + // TODO: remove when https://github.com/paritytech/polkadot-sdk/pull/4543 merged + type BlockHashCount = ConstU32<10>; + type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } @@ -72,9 +208,74 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } +impl pallet_utility::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] +impl pallet_transaction_payment::Config for TestRuntime { + type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< + TestRuntime, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = BridgedUnderlyingParachain; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<1_024>; + type HeadersToKeep = ConstU32<8>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +impl pallet_bridge_parachains::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgesGrandpaPalletInstance = (); + type ParasPalletName = BridgedParasPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ConstU32<8>; + type MaxParaHeadDataSize = ConstU32<1024>; + type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; +} + +impl pallet_bridge_messages::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + + type OutboundPayload = Vec; + + type InboundPayload = Vec; + type DeliveryPayments = (); + + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + TestRuntime, + (), + ConstU64<100_000>, + >; + type OnMessagesDelivered = (); + + type MessageDispatch = DummyMessageDispatch; + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingParachain; + type BridgedHeaderChain = BridgeGrandpa; +} + impl pallet_bridge_relayers::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; - type Reward = Balance; + type Reward = ThisChainBalance; type PaymentProcedure = TestPaymentProcedure; type StakeAndSlash = TestStakeAndSlash; type WeightInfo = (); @@ -82,9 +283,9 @@ impl pallet_bridge_relayers::Config for TestRuntime { #[cfg(feature = "runtime-benchmarks")] impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { - fn prepare_rewards_account(account_params: RewardsAccountParams, reward: Balance) { + fn prepare_rewards_account(account_params: RewardsAccountParams, reward: ThisChainBalance) { let rewards_account = - bp_relayers::PayRewardFromAccount::::rewards_account( + bp_relayers::PayRewardFromAccount::::rewards_account( account_params, ); Self::deposit_account(rewards_account, reward); @@ -96,30 +297,30 @@ impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { } /// Regular relayer that may receive rewards. -pub const REGULAR_RELAYER: AccountId = 1; +pub const REGULAR_RELAYER: ThisChainAccountId = 1; /// Relayer that can't receive rewards. -pub const FAILING_RELAYER: AccountId = 2; +pub const FAILING_RELAYER: ThisChainAccountId = 2; /// Relayer that is able to register. -pub const REGISTER_RELAYER: AccountId = 42; +pub const REGISTER_RELAYER: ThisChainAccountId = 42; /// Payment procedure that rejects payments to the `FAILING_RELAYER`. pub struct TestPaymentProcedure; impl TestPaymentProcedure { - pub fn rewards_account(params: RewardsAccountParams) -> AccountId { - PayRewardFromAccount::<(), AccountId>::rewards_account(params) + pub fn rewards_account(params: RewardsAccountParams) -> ThisChainAccountId { + PayRewardFromAccount::<(), ThisChainAccountId>::rewards_account(params) } } -impl PaymentProcedure for TestPaymentProcedure { +impl PaymentProcedure for TestPaymentProcedure { type Error = (); fn pay_reward( - relayer: &AccountId, + relayer: &ThisChainAccountId, _lane_id: RewardsAccountParams, - _reward: Balance, + _reward: ThisChainBalance, ) -> Result<(), Self::Error> { match *relayer { FAILING_RELAYER => Err(()), @@ -128,6 +329,35 @@ impl PaymentProcedure for TestPaymentProcedure { } } +/// Dummy message dispatcher. +pub struct DummyMessageDispatch; + +impl DummyMessageDispatch { + pub fn deactivate(lane: LaneId) { + frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); + } +} + +impl MessageDispatch for DummyMessageDispatch { + type DispatchPayload = Vec; + type DispatchLevelResult = (); + + fn is_active(lane: LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) + } + + fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + Weight::zero() + } + + fn dispatch( + _: DispatchMessage, + ) -> MessageDispatchResult { + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } + } +} + /// Reward account params that we are using in tests. pub fn test_reward_account_param() -> RewardsAccountParams { RewardsAccountParams::new(LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain) diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index beec412c1203..3693793a3e5c 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -103,11 +103,11 @@ mod tests { use super::*; use crate::{mock::*, RelayerRewards}; - const RELAYER_1: AccountId = 1; - const RELAYER_2: AccountId = 2; - const RELAYER_3: AccountId = 3; + const RELAYER_1: ThisChainAccountId = 1; + const RELAYER_2: ThisChainAccountId = 2; + const RELAYER_3: ThisChainAccountId = 3; - fn relayers_rewards() -> RelayersRewards { + fn relayers_rewards() -> RelayersRewards { vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect() } diff --git a/bridges/modules/relayers/src/stake_adapter.rs b/bridges/modules/relayers/src/stake_adapter.rs index ce097344d56b..0c965e9e6bff 100644 --- a/bridges/modules/relayers/src/stake_adapter.rs +++ b/bridges/modules/relayers/src/stake_adapter.rs @@ -80,7 +80,7 @@ mod tests { use frame_support::traits::fungible::Mutate; - fn test_stake() -> Balance { + fn test_stake() -> ThisChainBalance { Stake::get() } diff --git a/bridges/primitives/header-chain/src/call_info.rs b/bridges/primitives/header-chain/src/call_info.rs index 6f880e939414..acf7447adabc 100644 --- a/bridges/primitives/header-chain/src/call_info.rs +++ b/bridges/primitives/header-chain/src/call_info.rs @@ -20,14 +20,11 @@ use crate::{justification, InitializationData}; use bp_runtime::HeaderOf; use codec::{Decode, Encode}; -use frame_support::weights::Weight; +use frame_support::{weights::Weight, RuntimeDebugNoBound}; use scale_info::TypeInfo; use sp_consensus_grandpa::SetId; -use sp_runtime::{ - traits::{Header as HeaderT, Zero}, - RuntimeDebug, -}; -use sp_std::boxed::Box; +use sp_runtime::traits::{Header as HeaderT, Zero}; +use sp_std::{boxed::Box, fmt::Debug}; /// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] @@ -63,8 +60,8 @@ pub enum BridgeGrandpaCall { pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; /// A digest information on the `BridgeGrandpaCall::submit_finality_proof` call. -#[derive(Copy, Clone, PartialEq, RuntimeDebug)] -pub struct SubmitFinalityProofInfo { +#[derive(Copy, Clone, PartialEq, RuntimeDebugNoBound)] +pub struct SubmitFinalityProofInfo { /// Number of the finality target. pub block_number: N, /// An identifier of the validators set that has signed the submitted justification. @@ -89,7 +86,7 @@ pub struct SubmitFinalityProofInfo { pub extra_size: u32, } -impl SubmitFinalityProofInfo { +impl SubmitFinalityProofInfo { /// Returns `true` if call size/weight is below our estimations for regular calls. pub fn fits_limits(&self) -> bool { self.extra_weight.is_zero() && self.extra_size.is_zero() diff --git a/bridges/primitives/messages/src/call_info.rs b/bridges/primitives/messages/src/call_info.rs index 4cc3b9d4afea..c8f06ed8cb7c 100644 --- a/bridges/primitives/messages/src/call_info.rs +++ b/bridges/primitives/messages/src/call_info.rs @@ -154,6 +154,14 @@ pub enum MessagesCallInfo { } impl MessagesCallInfo { + /// Returns lane, used by the call. + pub fn lane_id(&self) -> LaneId { + match *self { + Self::ReceiveMessagesProof(ref info) => info.base.lane_id, + Self::ReceiveMessagesDeliveryProof(ref info) => info.0.lane_id, + } + } + /// Returns range of messages, bundled with the call. pub fn bundled_messages(&self) -> RangeInclusive { match *self { diff --git a/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs index 9717fee8597c..ec3bf9ca3a0a 100644 --- a/bridges/primitives/parachains/src/lib.rs +++ b/bridges/primitives/parachains/src/lib.rs @@ -20,11 +20,9 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use bp_header_chain::StoredHeaderData; +pub use call_info::{BridgeParachainCall, SubmitParachainHeadsInfo}; -use bp_polkadot_core::{ - parachains::{ParaHash, ParaHead, ParaId}, - BlockNumber as RelayBlockNumber, Hash as RelayBlockHash, -}; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaId}; use bp_runtime::{ BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider, StorageMapKeyProvider, @@ -36,7 +34,12 @@ use sp_core::storage::StorageKey; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*}; -pub use call_info::{BridgeParachainCall, SubmitParachainHeadsInfo}; +/// Block hash of the bridged relay chain. +pub type RelayBlockHash = bp_polkadot_core::Hash; +/// Block number of the bridged relay chain. +pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; +/// Hasher of the bridged relay chain. +pub type RelayBlockHasher = bp_polkadot_core::Hasher; mod call_info; diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 3448e8a40963..2019b7196573 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -15,13 +15,15 @@ codec = { features = ["bit-vec", "derive"], workspace = true } scale-info = { features = ["bit-vec", "derive"], workspace = true } # Bridge Dependencies - +bp-header-chain = { workspace = true } bp-messages = { workspace = true } -bp-runtime = { workspace = true } +bp-parachains = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } # Substrate Dependencies - +frame-system = { workspace = true } frame-support = { workspace = true } +pallet-utility = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -32,10 +34,14 @@ hex-literal = { workspace = true, default-features = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", "bp-runtime/std", "codec/std", "frame-support/std", + "frame-system/std", + "pallet-utility/std", "scale-info/std", "sp-runtime/std", "sp-std/std", diff --git a/bridges/primitives/relayers/src/extension.rs b/bridges/primitives/relayers/src/extension.rs new file mode 100644 index 000000000000..5ab8e6cde96b --- /dev/null +++ b/bridges/primitives/relayers/src/extension.rs @@ -0,0 +1,191 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! All runtime calls, supported by `pallet-bridge-relayers` when it acts as a signed +//! extension. + +use bp_header_chain::SubmitFinalityProofInfo; +use bp_messages::MessagesCallInfo; +use bp_parachains::SubmitParachainHeadsInfo; +use bp_runtime::StaticStrProvider; +use frame_support::{ + dispatch::CallableCallFor, traits::IsSubType, weights::Weight, RuntimeDebugNoBound, +}; +use frame_system::Config as SystemConfig; +use pallet_utility::{Call as UtilityCall, Pallet as UtilityPallet}; +use sp_runtime::{ + traits::Get, + transaction_validity::{TransactionPriority, TransactionValidityError}, + RuntimeDebug, +}; +use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec}; + +/// Type of the call that the signed extension recognizes. +#[derive(PartialEq, RuntimeDebugNoBound)] +pub enum ExtensionCallInfo { + /// Relay chain finality + parachain finality + message delivery/confirmation calls. + AllFinalityAndMsgs( + SubmitFinalityProofInfo, + SubmitParachainHeadsInfo, + MessagesCallInfo, + ), + /// Relay chain finality + message delivery/confirmation calls. + RelayFinalityAndMsgs(SubmitFinalityProofInfo, MessagesCallInfo), + /// Parachain finality + message delivery/confirmation calls. + /// + /// This variant is used only when bridging with parachain. + ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), + /// Standalone message delivery/confirmation call. + Msgs(MessagesCallInfo), +} + +impl + ExtensionCallInfo +{ + /// Returns true if call is a message delivery call (with optional finality calls). + pub fn is_receive_messages_proof_call(&self) -> bool { + match self.messages_call_info() { + MessagesCallInfo::ReceiveMessagesProof(_) => true, + MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => false, + } + } + + /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. + pub fn submit_finality_proof_info( + &self, + ) -> Option> { + match *self { + Self::AllFinalityAndMsgs(info, _, _) => Some(info), + Self::RelayFinalityAndMsgs(info, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. + pub fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { + match self { + Self::AllFinalityAndMsgs(_, info, _) => Some(info), + Self::ParachainFinalityAndMsgs(info, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. + pub fn messages_call_info(&self) -> &MessagesCallInfo { + match self { + Self::AllFinalityAndMsgs(_, _, info) => info, + Self::RelayFinalityAndMsgs(_, info) => info, + Self::ParachainFinalityAndMsgs(_, info) => info, + Self::Msgs(info) => info, + } + } +} + +/// Extra post-dispatch data, associated with the supported runtime call. +#[derive(Default, RuntimeDebug)] +pub struct ExtensionCallData { + /// Extra weight, consumed by the call. We have some assumptions about normal weight + /// that may be consumed by expected calls. If the actual weight is larger than that, + /// we do not refund relayer for this extra weight. + pub extra_weight: Weight, + /// Extra size, consumed by the call. We have some assumptions about normal size + /// of the encoded call. If the actual size is larger than that, we do not refund relayer + /// for this extra size. + pub extra_size: u32, +} + +/// Signed extension configuration. +/// +/// The single `pallet-bridge-relayers` instance may be shared by multiple messages +/// pallet instances, bridging with different remote networks. We expect every instance +/// of the messages pallet to add a separate signed extension to runtime. So it must +/// have a separate configuration. +pub trait ExtensionConfig { + /// Unique identifier of the signed extension that will use this configuration. + type IdProvider: StaticStrProvider; + /// Runtime that optionally supports batched calls. We assume that batched call + /// succeeds if and only if all of its nested calls succeed. + type Runtime: frame_system::Config; + /// Messages pallet instance. + type BridgeMessagesPalletInstance: 'static; + /// Additional priority that is added to base message delivery transaction priority + /// for every additional bundled message. + type PriorityBoostPerMessage: Get; + /// Type of reward, that the `pallet-bridge-relayers` is using. + type Reward; + /// Block number for the remote **GRANDPA chain**. Mind that this chain is not + /// necessarily the chain that we are bridging with. If we are bridging with + /// parachain, it must be its parent relay chain. If we are bridging with the + /// GRANDPA chain, it must be it. + type RemoteGrandpaChainBlockNumber: Clone + Copy + Debug; + + /// Given runtime call, check if it is supported by the signed extension. Additionally, + /// check if call (or any of batched calls) are obsolete. + fn parse_and_check_for_obsolete_call( + call: &::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + >; + + /// Check if runtime call is already obsolete. + fn check_obsolete_parsed_call( + call: &::RuntimeCall, + ) -> Result<&::RuntimeCall, TransactionValidityError>; + + /// Given runtime call info, check that this call has been successful and has updated + /// runtime storage accordingly. + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &::AccountId, + ) -> bool; +} + +/// Something that can unpack batch calls (all-or-nothing flavor) of given size. +pub trait BatchCallUnpacker { + /// Unpack batch call with no more than `max_packed_calls` calls. + fn unpack(call: &Runtime::RuntimeCall, max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall>; +} + +/// An `BatchCallUnpacker` adapter for runtimes with utility pallet. +pub struct RuntimeWithUtilityPallet(PhantomData); + +impl BatchCallUnpacker for RuntimeWithUtilityPallet +where + Runtime: pallet_utility::Config::RuntimeCall>, + ::RuntimeCall: + IsSubType, Runtime>>, +{ + fn unpack( + call: &::RuntimeCall, + max_packed_calls: u32, + ) -> Vec<&::RuntimeCall> { + match call.is_sub_type() { + Some(UtilityCall::::batch_all { ref calls }) + if calls.len() <= max_packed_calls as usize => + calls.iter().collect(), + Some(_) => vec![], + None => vec![call], + } + } +} + +impl BatchCallUnpacker for () { + fn unpack(call: &Runtime::RuntimeCall, _max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall> { + vec![call] + } +} diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index 704fef7c8e6b..1e63c89ecd70 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -19,6 +19,10 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +pub use extension::{ + BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig, + RuntimeWithUtilityPallet, +}; pub use registration::{ExplicitOrAccountParams, Registration, StakeAndSlash}; use bp_messages::LaneId; @@ -32,6 +36,7 @@ use sp_runtime::{ }; use sp_std::{fmt::Debug, marker::PhantomData}; +mod extension; mod registration; /// The owner of the sovereign account that should pay the rewards. diff --git a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs index 5631285b3c54..28b0eb0ad526 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs @@ -22,7 +22,7 @@ use crate::{ messages::{MessagesRelayLimits, SubstrateMessageLane}, parachains::SubstrateParachainsPipeline, }; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ Chain, ChainWithRuntimeVersion, ChainWithTransactions, Parachain, RelayChain, }; diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs index 8104be7af807..e8b797f84fa5 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs @@ -30,8 +30,8 @@ use crate::{ headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, }, }; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::ParaHash; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client, Parachain, diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs index 6c078973fedc..f9884ee197b4 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -33,8 +33,8 @@ use crate::{ headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, }, }; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::ParaHash; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client, Parachain, diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index 4579222a2c68..2ef86f48ecbe 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -31,11 +31,11 @@ use async_std::{ sync::{Arc, Mutex}, }; use async_trait::async_trait; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_runtime::HeaderIdProvider; use futures::{select, FutureExt}; use num_traits::Zero; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; use relay_substrate_client::{ is_ancient_block, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, diff --git a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs index 8b128bb770dd..08d8e5e2a4f5 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs @@ -18,11 +18,9 @@ //! parachain finality proofs synchronization pipelines. use async_trait::async_trait; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; -use pallet_bridge_parachains::{ - Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, - RelayBlockHasher, RelayBlockNumber, -}; +use pallet_bridge_parachains::{Call as BridgeParachainsCall, Config as BridgeParachainsConfig}; use parachains_relay::ParachainsPipeline; use relay_substrate_client::{ CallOf, Chain, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain, From 542e0a75e60720ddef81148c54de09ebe9ae7604 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 28 Sep 2023 15:22:45 +0300 Subject: [PATCH 21/95] Backport recent changes from polkadot staging (#2590) * fiox overflow when computing priority boost (#2587) * Backport changes from polkadot-sdk (#2588) * backport https://github.com/paritytech/polkadot-sdk/pull/1543 * another backport * https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/3833103 --- bridges/modules/relayers/src/extension/mod.rs | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index fb170965afa9..33ffa15b80cd 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -426,10 +426,10 @@ mod tests { use bp_header_chain::{StoredHeaderDataBuilder, SubmitFinalityProofInfo}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, InboundLaneData, - LaneId, MessageNonce, MessagesCallInfo, MessagesOperatingMode, OutboundLaneData, - ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, DeliveredMessages, + InboundLaneData, LaneId, MessageNonce, MessagesCallInfo, MessagesOperatingMode, + OutboundLaneData, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + UnrewardedRelayer, UnrewardedRelayerOccupation, UnrewardedRelayersState, }; use bp_parachains::{BestParaHeadHash, ParaInfo, SubmitParachainHeadsInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; @@ -2301,4 +2301,40 @@ mod tests { ); }); } + + #[test] + fn does_not_panic_on_boosting_priority_of_empty_message_delivery_transaction() { + run_test(|| { + let best_delivered_message = + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + initialize_environment(100, 100, best_delivered_message); + + // register relayer so it gets priority boost + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + // allow empty message delivery transactions + let lane_id = TestLaneId::get(); + let in_lane_data = InboundLaneData { + last_confirmed_nonce: 0, + relayers: vec![UnrewardedRelayer { + relayer: relayer_account_at_bridged_chain(), + messages: DeliveredMessages { begin: 1, end: best_delivered_message }, + }] + .into(), + ..Default::default() + }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + // now check that the priority of empty tx is the same as priority of 1-message tx + let priority_of_zero_messages_delivery = + run_validate(message_delivery_call(best_delivered_message)).unwrap().priority; + let priority_of_one_messages_delivery = + run_validate(message_delivery_call(best_delivered_message + 1)) + .unwrap() + .priority; + + assert_eq!(priority_of_zero_messages_delivery, priority_of_one_messages_delivery); + }); + } } From 9352d45d2938471698eb04ad2a2225b0799d46ca Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 16 Jul 2024 13:27:08 +0200 Subject: [PATCH 22/95] Fixed "TODO:(bridges-v2) - most of that stuff was introduced with free header execution" --- bridges/modules/relayers/Cargo.toml | 2 +- .../src/extension/messages_adapter.rs | 4 +- bridges/modules/relayers/src/extension/mod.rs | 330 +++++++++--------- 3 files changed, 167 insertions(+), 169 deletions(-) diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 9a4a680e135f..d98edb7dca08 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -35,7 +35,7 @@ sp-std = { workspace = true } [dev-dependencies] bp-runtime = { workspace = true } -pallet-balances = { workspace = true } +pallet-balances = { workspace = true, default-features = true } sp-io = { workspace = true } sp-runtime = { workspace = true } bp-parachains = { workspace = true } diff --git a/bridges/modules/relayers/src/extension/messages_adapter.rs b/bridges/modules/relayers/src/extension/messages_adapter.rs index f84e25ba5aa1..ecb575524bb0 100644 --- a/bridges/modules/relayers/src/extension/messages_adapter.rs +++ b/bridges/modules/relayers/src/extension/messages_adapter.rs @@ -33,7 +33,7 @@ use sp_std::marker::PhantomData; /// Transaction extension that refunds a relayer for standalone messages delivery and confirmation /// transactions. Finality transactions are not refunded. -pub struct MessagesExtensionConfig< +pub struct WithMessagesExtensionConfig< IdProvider, Runtime, BridgeMessagesPalletInstance, @@ -51,7 +51,7 @@ pub struct MessagesExtensionConfig< )>, ); -impl ExtensionConfig for MessagesExtensionConfig +impl ExtensionConfig for WithMessagesExtensionConfig where ID: StaticStrProvider, R: BridgeRelayersConfig + BridgeMessagesConfig, diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 33ffa15b80cd..a31ea8ff43ff 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -51,7 +51,7 @@ use sp_runtime::{ use sp_std::{fmt::Debug, marker::PhantomData}; pub use grandpa_adapter::WithGrandpaChainExtensionConfig; -pub use messages_adapter::MessagesExtensionConfig; +pub use messages_adapter::WithMessagesExtensionConfig; pub use parachain_adapter::WithParachainExtensionConfig; pub use priority::*; @@ -488,6 +488,10 @@ mod tests { ConstU64<1>, >; type TestExtension = BridgeRelayersSignedExtension; + type TestMessagesExtensionConfig = + messages_adapter::WithMessagesExtensionConfig>; + type TestMessagesExtension = + BridgeRelayersSignedExtension; fn test_lane_id() -> LaneId { LaneId::new(1, 2) @@ -983,8 +987,8 @@ mod tests { } } - fn delivery_pre_dispatch_data() -> PreDispatchData - { + fn delivery_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( @@ -1005,8 +1009,8 @@ mod tests { } } - fn confirmation_pre_dispatch_data( - ) -> PreDispatchData { + fn confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( @@ -1047,12 +1051,10 @@ mod tests { extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } - // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 - // fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { - // let extension: TestMessagesExtension = - // RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - // extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) - // } + fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { + let extension: TestMessagesExtension = BridgeRelayersSignedExtension(PhantomData); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } fn ignore_priority(tx: TransactionValidity) -> TransactionValidity { tx.map(|mut tx| { @@ -1082,14 +1084,12 @@ mod tests { extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } - // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 - // fn run_messages_pre_dispatch( - // call: RuntimeCall, - // ) -> Result>, TransactionValidityError> { - // let extension: TestMessagesExtension = - // RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - // extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) - // } + fn run_messages_pre_dispatch( + call: RuntimeCall, + ) -> Result>, TransactionValidityError> { + let extension: TestMessagesExtension = BridgeRelayersSignedExtension(PhantomData); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } fn dispatch_info() -> DispatchInfo { DispatchInfo { @@ -1249,11 +1249,10 @@ mod tests { ignore_priority(run_validate(message_confirmation_call(200))), Ok(ValidTransaction::default()), ); - // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 - // assert_eq!( - // ignore_priority(run_messages_validate(message_delivery_call(200))), - // Ok(ValidTransaction::default()), - // ); + assert_eq!( + ignore_priority(run_messages_validate(message_delivery_call(200))), + Ok(ValidTransaction::default()), + ); assert_eq!( ignore_priority(run_validate(parachain_finality_and_delivery_batch_call(200, 200))), @@ -2019,148 +2018,147 @@ mod tests { }); } - // TODO:(bridges-v2) - most of that stuff was introduced with free header execution: https://github.com/paritytech/polkadot-sdk/pull/4102 - // #[test] - // fn messages_ext_only_parses_standalone_transactions() { - // run_test(|| { - // initialize_environment(100, 100, 100); - // - // // relay + parachain + message delivery calls batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &all_finality_and_delivery_batch_call(200, 200, 200) - // ), - // Ok(None), - // ); - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &all_finality_and_delivery_batch_call_ex(200, 200, 200) - // ), - // Ok(None), - // ); - // - // // relay + parachain + message confirmation calls batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &all_finality_and_confirmation_batch_call(200, 200, 200) - // ), - // Ok(None), - // ); - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &all_finality_and_confirmation_batch_call_ex(200, 200, 200) - // ), - // Ok(None), - // ); - // - // // parachain + message delivery call batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // ¶chain_finality_and_delivery_batch_call(200, 200) - // ), - // Ok(None), - // ); - // - // // parachain + message confirmation call batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // ¶chain_finality_and_confirmation_batch_call(200, 200) - // ), - // Ok(None), - // ); - // - // // relay + message delivery call batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &relay_finality_and_delivery_batch_call(200, 200) - // ), - // Ok(None), - // ); - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &relay_finality_and_delivery_batch_call_ex(200, 200) - // ), - // Ok(None), - // ); - // - // // relay + message confirmation call batch is ignored - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &relay_finality_and_confirmation_batch_call(200, 200) - // ), - // Ok(None), - // ); - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &relay_finality_and_confirmation_batch_call_ex(200, 200) - // ), - // Ok(None), - // ); - // - // // message delivery call batch is accepted - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &message_delivery_call(200) - // ), - // Ok(Some(delivery_pre_dispatch_data().call_info)), - // ); - // - // // message confirmation call batch is accepted - // assert_eq!( - // TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - // &message_confirmation_call(200) - // ), - // Ok(Some(confirmation_pre_dispatch_data().call_info)), - // ); - // }); - // } - // - // #[test] - // fn messages_ext_rejects_calls_with_obsolete_messages() { - // run_test(|| { - // initialize_environment(100, 100, 100); - // - // assert_eq!( - // run_messages_pre_dispatch(message_delivery_call(100)), - // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - // ); - // assert_eq!( - // run_messages_pre_dispatch(message_confirmation_call(100)), - // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - // ); - // - // assert_eq!( - // run_messages_validate(message_delivery_call(100)), - // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - // ); - // assert_eq!( - // run_messages_validate(message_confirmation_call(100)), - // Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - // ); - // }); - // } - // - // #[test] - // fn messages_ext_accepts_calls_with_new_messages() { - // run_test(|| { - // initialize_environment(100, 100, 100); - // - // assert_eq!( - // run_messages_pre_dispatch(message_delivery_call(200)), - // Ok(Some(delivery_pre_dispatch_data())), - // ); - // assert_eq!( - // run_messages_pre_dispatch(message_confirmation_call(200)), - // Ok(Some(confirmation_pre_dispatch_data())), - // ); - // - // assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); - // assert_eq!( - // run_messages_validate(message_confirmation_call(200)), - // Ok(Default::default()), - // ); - // }); - // } + #[test] + fn messages_ext_only_parses_standalone_transactions() { + run_test(|| { + initialize_environment(100, 100, 100); + + // relay + parachain + message delivery calls batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &all_finality_and_delivery_batch_call(200, 200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &all_finality_and_delivery_batch_call_ex(200, 200, 200) + ), + Ok(None), + ); + + // relay + parachain + message confirmation calls batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &all_finality_and_confirmation_batch_call(200, 200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &all_finality_and_confirmation_batch_call_ex(200, 200, 200) + ), + Ok(None), + ); + + // parachain + message delivery call batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + ¶chain_finality_and_delivery_batch_call(200, 200) + ), + Ok(None), + ); + + // parachain + message confirmation call batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + ¶chain_finality_and_confirmation_batch_call(200, 200) + ), + Ok(None), + ); + + // relay + message delivery call batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &relay_finality_and_delivery_batch_call(200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &relay_finality_and_delivery_batch_call_ex(200, 200) + ), + Ok(None), + ); + + // relay + message confirmation call batch is ignored + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &relay_finality_and_confirmation_batch_call(200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &relay_finality_and_confirmation_batch_call_ex(200, 200) + ), + Ok(None), + ); + + // message delivery call batch is accepted + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &message_delivery_call(200) + ), + Ok(Some(delivery_pre_dispatch_data().call_info)), + ); + + // message confirmation call batch is accepted + assert_eq!( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( + &message_confirmation_call(200) + ), + Ok(Some(confirmation_pre_dispatch_data().call_info)), + ); + }); + } + + #[test] + fn messages_ext_rejects_calls_with_obsolete_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_messages_validate(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_validate(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn messages_ext_accepts_calls_with_new_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(200)), + Ok(Some(delivery_pre_dispatch_data())), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); + + assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); + assert_eq!( + run_messages_validate(message_confirmation_call(200)), + Ok(Default::default()), + ); + }); + } #[test] fn grandpa_ext_rejects_batch_with_obsolete_relay_chain_header() { From 8936da7f395673f9e8cc319c3cd75a20914dc367 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 16 Jul 2024 16:19:33 +0200 Subject: [PATCH 23/95] Rename `BridgeReserve` to `BridgeDeposit` --- bridges/modules/xcm-bridge-hub/src/lib.rs | 16 ++++++++-------- bridges/modules/xcm-bridge-hub/src/mock.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 949c01733f32..f1f7b3c409d9 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -26,10 +26,10 @@ //! 1) the sibling parachain opens a XCMP channel with this bridge hub; //! //! 2) the sibling parachain funds its sovereign parachain account at this bridge hub. It shall hold -//! enough funds to pay for the bridge (see `BridgeReserve`); +//! enough funds to pay for the bridge (see `BridgeDeposit`); //! //! 3) the sibling parachain opens the bridge by sending XCM `Transact` instruction with the -//! `open_bridge` call. The `BridgeReserve` amount is reserved on the sovereign account of +//! `open_bridge` call. The `BridgeDeposit` amount is reserved on the sovereign account of //! sibling parachain; //! //! 4) at the other side of the bridge, the same thing (1, 2, 3) happens. Parachains that need to @@ -127,7 +127,7 @@ pub mod pallet { /// Amount of this chain native tokens that is reserved on the sibling parachain account /// when bridge open request is registered. #[pallet::constant] - type BridgeReserve: Get>>; + type BridgeDeposit: Get>>; /// Currency used to pay for bridge registration. type NativeCurrency: ReservableCurrency; @@ -172,7 +172,7 @@ pub mod pallet { /// parachain or a parent relay chain). The `bridge_destination_universal_location` must be /// a destination within the consensus of the `T::BridgedNetwork` network. /// - /// The `BridgeReserve` amount is reserved on the caller account. This reserve + /// The `BridgeDeposit` amount is reserved on the caller account. This deposit /// is unreserved after bridge is closed. /// /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane @@ -188,13 +188,13 @@ pub mod pallet { Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; // reserve balance on the parachain sovereign account - let reserve = T::BridgeReserve::get(); + let reserve = T::BridgeDeposit::get(); let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( &locations.bridge_origin_relative_location, ) .ok_or(Error::::InvalidBridgeOriginAccount)?; T::NativeCurrency::reserve(&bridge_owner_account, reserve) - .map_err(|_| Error::::FailedToReserveBridgeReserve)?; + .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; // save bridge metadata Bridges::::try_mutate(locations.bridge_id, |bridge| match bridge { @@ -513,7 +513,7 @@ pub mod pallet { /// Trying to access unknown bridge. UnknownBridge, /// The bridge origin can't pay the required amount for opening the bridge. - FailedToReserveBridgeReserve, + FailedToReserveBridgeDeposit, /// The version of XCM location argument is unsupported. UnsupportedXcmVersion, } @@ -674,7 +674,7 @@ mod tests { OpenBridgeOrigin::parent_relay_chain_origin(), Box::new(bridged_asset_hub_location().into()), ), - Error::::FailedToReserveBridgeReserve, + Error::::FailedToReserveBridgeDeposit, ); }); } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index c8f5fdb6668a..f864c26d222e 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -190,7 +190,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type OpenBridgeOrigin = OpenBridgeOrigin; type BridgeOriginAccountIdConverter = LocationToAccountId; - type BridgeReserve = BridgeDeposit; + type BridgeDeposit = BridgeDeposit; type NativeCurrency = Balances; type LocalXcmChannelManager = TestLocalXcmChannelManager; From 53cf059a451700edc1ce2fc21a8a04b5ac5ccf91 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 16 Jul 2024 17:13:30 +0200 Subject: [PATCH 24/95] use `fungible` for `pallet-xcm-bridge-hub` plus other nits --- bridges/modules/xcm-bridge-hub/src/lib.rs | 66 +++++++++++++------- bridges/modules/xcm-bridge-hub/src/mock.rs | 5 +- bridges/primitives/xcm-bridge-hub/src/lib.rs | 2 +- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index f1f7b3c409d9..cd6475bb665f 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -57,10 +57,7 @@ use bp_xcm_bridge_hub::{ bridge_locations, Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, LocalXcmChannelManager, }; -use frame_support::{ - traits::{Currency, ReservableCurrency}, - DefaultNoBound, -}; +use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; use sp_runtime::traits::Zero; @@ -83,9 +80,17 @@ pub const LOG_TARGET: &str = "runtime::bridge-xcm"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::tokens::Precision}; use frame_system::pallet_prelude::{BlockNumberFor, *}; + /// The reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The funds are held as a deposit for opened bridge. + #[codec(index = 0)] + BridgeDeposit, + } + #[pallet::config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: @@ -122,14 +127,20 @@ pub mod pallet { Success = Location, >; /// A converter between a multi-location and a sovereign account. - type BridgeOriginAccountIdConverter: ConvertLocation; + type BridgeOriginAccountIdConverter: ConvertLocation>>; /// Amount of this chain native tokens that is reserved on the sibling parachain account /// when bridge open request is registered. #[pallet::constant] type BridgeDeposit: Get>>; /// Currency used to pay for bridge registration. - type NativeCurrency: ReservableCurrency; + type Currency: MutateHold< + AccountIdOf>, + Balance = BalanceOf>, + Reason = Self::RuntimeHoldReason, + >; + /// The overarching runtime hold reason. + type RuntimeHoldReason: From; /// Local XCM channel manager. type LocalXcmChannelManager: LocalXcmChannelManager; @@ -161,11 +172,7 @@ pub mod pallet { } #[pallet::call] - impl, I: 'static> Pallet - where - T: frame_system::Config>>, - T::NativeCurrency: Currency>>, - { + impl, I: 'static> Pallet { /// Open a bridge between two locations. /// /// The caller must be within the `T::OpenBridgeOrigin` filter (presumably: a sibling @@ -193,7 +200,7 @@ pub mod pallet { &locations.bridge_origin_relative_location, ) .ok_or(Error::::InvalidBridgeOriginAccount)?; - T::NativeCurrency::reserve(&bridge_owner_account, reserve) + T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, reserve) .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; // save bridge metadata @@ -233,6 +240,7 @@ pub mod pallet { // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { bridge_id: locations.bridge_id, + bridge_deposit: Some(reserve), local_endpoint: Box::new(locations.bridge_origin_universal_location), remote_endpoint: Box::new(locations.bridge_destination_universal_location), }); @@ -333,24 +341,29 @@ pub mod pallet { outbound_lane.purge(); Bridges::::remove(locations.bridge_id); - // unreserve remaining amount - let failed_to_unreserve = - T::NativeCurrency::unreserve(&bridge.bridge_owner_account, bridge.reserve); - if !failed_to_unreserve.is_zero() { + // return deposit + let released_deposit = T::Currency::release( + &HoldReason::BridgeDeposit.into(), + &bridge.bridge_owner_account, + bridge.reserve, + Precision::BestEffort, + ) + .map_err(|e| { // we can't do anything here - looks like funds have been (partially) unreserved // before by someone else. Let's not fail, though - it'll be worse for the caller - log::trace!( + log::error!( target: LOG_TARGET, - "Failed to unreserve {:?} during ridge {:?} closure", - failed_to_unreserve, + "Failed to unreserve during the bridge {:?} closure with error: {e:?}", locations.bridge_id, ); - } + e + }) + .ok(); // write something to log log::trace!( target: LOG_TARGET, - "Bridge {:?} between {:?} and {:?} has been closed", + "Bridge {:?} between {:?} and {:?} has been closed, the bridge deposit {released_deposit:?} was returned", locations.bridge_id, locations.bridge_origin_universal_location, locations.bridge_destination_universal_location, @@ -359,6 +372,7 @@ pub mod pallet { // deposit the `BridgePruned` event Self::deposit_event(Event::::BridgePruned { bridge_id: locations.bridge_id, + bridge_deposit: released_deposit, pruned_messages, }); @@ -476,6 +490,8 @@ pub mod pallet { remote_endpoint: Box, /// Bridge identifier. bridge_id: BridgeId, + /// Amount of deposit held. + bridge_deposit: Option>>, }, /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. ClosingBridge { @@ -491,6 +507,8 @@ pub mod pallet { BridgePruned { /// Bridge identifier. bridge_id: BridgeId, + /// Amount of deposit released. + bridge_deposit: Option>>, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, }, @@ -545,7 +563,7 @@ mod tests { XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); let bridge_owner_account = fund_origin_sovereign_account(&locations, reserve + ExistentialDeposit::get()); - Balances::reserve(&bridge_owner_account, reserve).unwrap(); + Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, reserve).unwrap(); let bridge = Bridge { bridge_origin_relative_location: Box::new( @@ -839,6 +857,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { bridge_id: locations.bridge_id, + bridge_deposit: Some(BridgeDeposit::get()), local_endpoint: Box::new(locations.bridge_origin_universal_location), remote_endpoint: Box::new( locations.bridge_destination_universal_location @@ -1077,6 +1096,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { bridge_id: locations.bridge_id, + bridge_deposit: Some(BridgeDeposit::get()), pruned_messages: 8, }), topics: vec![], diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index f864c26d222e..fdb461d1d6dc 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -62,7 +62,7 @@ frame_support::construct_runtime! { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, - XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, Event}, + XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, HoldReason, Event}, XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, } } @@ -191,7 +191,8 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type BridgeOriginAccountIdConverter = LocationToAccountId; type BridgeDeposit = BridgeDeposit; - type NativeCurrency = Balances; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; type LocalXcmChannelManager = TestLocalXcmChannelManager; diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 3aabe2201530..0d203189c68d 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -59,7 +59,7 @@ impl BridgeId { /// /// The fact that we are using versioned locations here means that XCM version upgrades must /// be coordinated at all involved chains (at source and target chains + at bridge hubs). - /// Otherwise messages may simply be dropped anywhere on its path to the target chain. + /// Otherwise, messages may simply be dropped anywhere on its path to the target chain. pub fn new( universal_location1: &VersionedInteriorLocation, universal_location2: &VersionedInteriorLocation, From d6d8b2c75531d9a954433b7f322fd4ba2cac6544 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 17 Jul 2024 13:06:48 +0200 Subject: [PATCH 25/95] Adjusted BH runtimes to the latest vogue WIP: some TODOs WIP: Adjusted BH runtimes to the latest vogue for `MessageDispatch` and `Origin`s nits WIP: fix signed extensions and refund WIP: add empty migration and TODO (at least runtimes compile) WIP: more compile reexport static_assertions for macro WIP: more compile --- Cargo.lock | 4 + bridges/bin/runtime-common/src/integrity.rs | 2 +- bridges/modules/messages/src/lib.rs | 2 +- bridges/modules/relayers/src/extension/mod.rs | 14 +- bridges/modules/relayers/src/mock.rs | 3 - .../modules/xcm-bridge-hub/src/dispatcher.rs | 14 +- .../modules/xcm-bridge-hub/src/exporter.rs | 2 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 41 +++- bridges/modules/xcm-bridge-hub/src/mock.rs | 1 + bridges/primitives/xcm-bridge-hub/src/lib.rs | 6 +- .../relays/parachains/src/parachains_loop.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 5 +- .../src/bridge_to_bulletin_config.rs | 171 +++++++++------- .../src/bridge_to_westend_config.rs | 187 ++++++++++-------- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 11 +- .../bridge-hub-rococo/src/xcm_config.rs | 25 ++- .../bridge-hub-rococo/tests/tests.rs | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 1 + .../src/bridge_to_rococo_config.rs | 187 ++++++++++-------- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 12 +- .../bridge-hub-westend/src/xcm_config.rs | 4 +- .../bridge-hub-westend/tests/tests.rs | 2 +- .../runtimes/bridge-hubs/common/Cargo.toml | 2 + .../runtimes/bridge-hubs/common/src/lib.rs | 1 + .../bridge-hubs/common/src/xcm_version.rs | 44 +++++ .../bridge-hubs/test-utils/Cargo.toml | 6 + .../src/test_cases/from_grandpa_chain.rs | 2 +- .../src/test_cases/from_parachain.rs | 2 +- .../test-utils/src/test_cases/helpers.rs | 4 +- .../test-utils/src/test_cases/mod.rs | 12 +- .../src/test_data/from_grandpa_chain.rs | 7 +- .../src/test_data/from_parachain.rs | 7 +- 32 files changed, 478 insertions(+), 307 deletions(-) create mode 100644 cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs diff --git a/Cargo.lock b/Cargo.lock index f1c8f8045b82..03474117d254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2043,6 +2043,7 @@ dependencies = [ "snowbridge-core", "sp-core", "sp-runtime", + "sp-std 14.0.0", "staging-xcm", ] @@ -2196,10 +2197,12 @@ dependencies = [ "asset-test-utils", "bp-header-chain", "bp-messages", + "bp-parachains", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", + "bp-xcm-bridge-hub", "bridge-runtime-common", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -2214,6 +2217,7 @@ dependencies = [ "pallet-bridge-relayers", "pallet-timestamp", "pallet-utility", + "pallet-xcm-bridge-hub", "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index 6757191995a6..c2c5b4e94ab2 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -68,7 +68,7 @@ macro_rules! assert_bridge_messages_pallet_types( bridged_chain: $bridged:path, ) => { { - use $crate::messages_xcm_extension::XcmAsPlainPayload; + use $crate::integrity::__private::bp_xcm_bridge_hub::XcmAsPlainPayload; use $crate::integrity::__private::static_assertions::assert_type_eq_all; use bp_messages::ChainWithMessages; use bp_runtime::Chain; diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 3d89494f7463..b03fa14637a4 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -519,7 +519,7 @@ pub mod pallet { QueryKind = OptionQuery, >; - // TODO:(bridges-v2) - do we still need this? + // TODO:(bridges-v2) - do we still need this? FAIL-CI /// Map of lane id => is congested signal sent. It is managed by the /// `bridge_runtime_common::LocalXcmQueueManager`. /// diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index a31ea8ff43ff..e1a7abd0ad1c 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -467,10 +467,12 @@ mod tests { pub TestLaneId: LaneId = test_lane_id(); } + bp_runtime::generate_static_str_provider!(TestGrandpaExtension); bp_runtime::generate_static_str_provider!(TestExtension); + bp_runtime::generate_static_str_provider!(TestMessagesExtension); type TestGrandpaExtensionConfig = grandpa_adapter::WithGrandpaChainExtensionConfig< - StrTestId, + StrTestGrandpaExtension, TestRuntime, RuntimeWithUtilityPallet, (), @@ -480,7 +482,7 @@ mod tests { type TestGrandpaExtension = BridgeRelayersSignedExtension; type TestExtensionConfig = parachain_adapter::WithParachainExtensionConfig< - StrTestId, + StrTestExtension, TestRuntime, RuntimeWithUtilityPallet, (), @@ -488,8 +490,12 @@ mod tests { ConstU64<1>, >; type TestExtension = BridgeRelayersSignedExtension; - type TestMessagesExtensionConfig = - messages_adapter::WithMessagesExtensionConfig>; + type TestMessagesExtensionConfig = messages_adapter::WithMessagesExtensionConfig< + StrTestMessagesExtension, + TestRuntime, + (), + ConstU64<1>, + >; type TestMessagesExtension = BridgeRelayersSignedExtension; diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 43aeec8bfc3b..de1d292b7c0f 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -41,9 +41,6 @@ use sp_runtime::{ BuildStorage, FixedPointNumber, Perquintill, StateVersion, }; -// generate identifier of the signed extension -bp_runtime::generate_static_str_provider!(TestId); - /// Account identifier at `ThisChain`. pub type ThisChainAccountId = u64; /// Balance at `ThisChain`. diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index f88a825e41bb..e08a21bc9af8 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -54,7 +54,7 @@ type MessagesPalletWeights = impl, I: 'static> MessageDispatch for Pallet where - T: BridgeMessagesConfig, + T: BridgeMessagesConfig, { type DispatchPayload = XcmAsPlainPayload; type DispatchLevelResult = XcmBlobMessageDispatchResult; @@ -85,8 +85,8 @@ where Err(e) => { log::error!( target: LOG_TARGET, - "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", - e, + "dispatch - payload error: {e:?} for lane_id: {} and message_nonce: {:?}", + message.key.lane_id, message.key.nonce ); return MessageDispatchResult { @@ -99,7 +99,8 @@ where Ok(_) => { log::debug!( target: LOG_TARGET, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", + "dispatch - `DispatchBlob::dispatch_blob` was ok for lane_id: {} and message_nonce: {:?}", + message.key.lane_id, message.key.nonce ); XcmBlobMessageDispatchResult::Dispatched @@ -107,8 +108,9 @@ where Err(e) => { log::error!( target: LOG_TARGET, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", - e, message.key.nonce + "dispatch - `DispatchBlob::dispatch_blob` failed with error: {e:?} for lane_id: {} and message_nonce: {:?}", + message.key.lane_id, + message.key.nonce ); XcmBlobMessageDispatchResult::NotDispatched(Some(e)) }, diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 7848bafe2ed2..bf83523f01b4 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -107,7 +107,7 @@ where let bridge_message = MessagesPallet::::validate_message(locations.bridge_id.lane_id(), &blob) .map_err(|e| { - // TODO:(bridges-v2) - add test/std feature gate? + // TODO:(bridges-v2) - add test/std feature gate? FAIL-CI match e { Error::LanesManager(ref ei) => log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index cd6475bb665f..3f7fb4012c7a 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -66,6 +66,7 @@ use xcm::prelude::*; use xcm_builder::DispatchBlob; use xcm_executor::traits::ConvertLocation; +pub use bp_xcm_bridge_hub::XcmAsPlainPayload; pub use dispatcher::XcmBlobMessageDispatchResult; pub use exporter::PalletAsHaulBlobExporter; pub use pallet::*; @@ -85,7 +86,7 @@ pub mod pallet { /// The reason for this pallet placing a hold on funds. #[pallet::composite_enum] - pub enum HoldReason { + pub enum HoldReason { /// The funds are held as a deposit for opened bridge. #[codec(index = 0)] BridgeDeposit, @@ -117,11 +118,12 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; + /// The origin that is allowed to call privileged operations on the pallet, e.g. open/close + /// bridge for location that coresponds to `Self::BridgeOriginAccountIdConverter` and + /// `Self::BridgedNetwork`. + type AdminOrigin: EnsureOrigin<::RuntimeOrigin>; /// A set of XCM locations within local consensus system that are allowed to open /// bridges with remote destinations. - // TODO: there's only one impl of `EnsureOrigin` - - // `EnsureXcmOrigin`, but it doesn't do what we need. Is there some other way to check - // `Origin` and get matching `Location`??? type OpenBridgeOrigin: EnsureOrigin< ::RuntimeOrigin, Success = Location, @@ -140,7 +142,7 @@ pub mod pallet { Reason = Self::RuntimeHoldReason, >; /// The overarching runtime hold reason. - type RuntimeHoldReason: From; + type RuntimeHoldReason: From>; /// Local XCM channel manager. type LocalXcmChannelManager: LocalXcmChannelManager; @@ -185,7 +187,7 @@ pub mod pallet { /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane /// is `Opened`. #[pallet::call_index(0)] - #[pallet::weight(Weight::zero())] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - weights + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI pub fn open_bridge( origin: OriginFor, bridge_destination_universal_location: Box, @@ -266,7 +268,7 @@ pub mod pallet { /// The states after this call: everything is either `Closed`, or purged from the /// runtime storage. #[pallet::call_index(1)] - #[pallet::weight(Weight::zero())] // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - weights + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI pub fn close_bridge( origin: OriginFor, bridge_destination_universal_location: Box, @@ -378,6 +380,31 @@ pub mod pallet { Ok(()) } + + /// TODO:(bridges-v2) - FAIL-CI - add docs/tests/benchmarks + #[pallet::call_index(2)] + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI + pub fn force_open_bridge( + origin: OriginFor, + _bridge_origin_universal_location: Box, + _bridge_destination_universal_location: Box, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + todo!() + } + + /// TODO:(bridges-v2) - FAIL-CI - add docs/tests/benchmarks + #[pallet::call_index(3)] + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI + pub fn force_close_bridge( + origin: OriginFor, + _bridge_origin_universal_location: Box, + _bridge_destination_universal_location: Box, + _may_prune_messages: MessageNonce, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + todo!() + } } impl, I: 'static> Pallet { diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index fdb461d1d6dc..a3132d3e8141 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -187,6 +187,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; + type AdminOrigin = frame_system::EnsureNever<()>; type OpenBridgeOrigin = OpenBridgeOrigin; type BridgeOriginAccountIdConverter = LocationToAccountId; diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 0d203189c68d..5752140a2a28 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -104,19 +104,19 @@ pub trait LocalXcmChannelManager { /// Returns true if the channel with given location is currently congested. /// /// The `with` is guaranteed to be in the same consensus. However, it may point to something - /// below the chain level - like the constract or pallet instance, for example. + /// below the chain level - like the contract or pallet instance, for example. fn is_congested(with: &Location) -> bool; /// Suspend the bridge, opened by given origin. /// /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to - /// something below the chain level - like the constract or pallet instance, for example. + /// something below the chain level - like the contract or pallet instance, for example. fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; /// Resume the previously suspended bridge, opened by given origin. /// /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to - /// something below the chain level - like the constract or pallet instance, for example. + /// something below the chain level - like the contract or pallet instance, for example. fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; } diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index 0fd1d72c7075..59ca458e6667 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -496,7 +496,7 @@ where }, (AvailableHeader::Missing, Some(_)) => { // parachain/parathread has been offboarded removed from the system. It needs to - // be propageted to the target client + // be propagated to the target client true }, (AvailableHeader::Missing, None) => { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 7a60a3f64840..03ae2e1724de 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -122,9 +122,8 @@ bridge-hub-common = { workspace = true } [dev-dependencies] bridge-hub-test-utils = { workspace = true, default-features = true } -bridge-runtime-common = { features = [ - "integrity-test", -], workspace = true, default-features = true } +bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } +pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } sp-keyring = { workspace = true, default-features = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 83b92918dc4f..672b2c847899 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -20,31 +20,31 @@ //! are reusing Polkadot Bulletin chain primitives everywhere here. use crate::{ - weights, xcm_config::UniversalLocation, BridgeRococoBulletinGrandpa, - BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverRococoBulletin, - XcmRouter, + weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, + BridgeRococoBulletinGrandpa, BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverRococoBulletin, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, LaneId, -}; -use bridge_runtime_common::{ - extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, + target_chain::FromBridgedChainMessagesProof, }; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; use frame_support::{parameter_types, traits::PalletInfoAccess}; +use frame_system::EnsureRoot; +use pallet_bridge_relayers::extension::{ + BridgeRelayersSignedExtension, WithMessagesExtensionConfig, +}; +use pallet_xcm::EnsureXcm; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; +use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; parameter_types! { /// Interior location (relative to this runtime) of the with-RococoBulletin messages pallet. @@ -58,12 +58,6 @@ parameter_types! { 2, [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())] ); - /// All active lanes that the current bridge supports. - pub ActiveOutboundLanesToRococoBulletin: &'static [bp_messages::LaneId] - = &[XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN]; - /// Lane identifier, used to connect Rococo People and Rococo Bulletin chain. - pub const RococoPeopleToRococoBulletinMessagesLane: bp_messages::LaneId - = XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN; // see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value pub PriorityBoostPerRelayHeader: u64 = 58_014_163_614_163; @@ -75,26 +69,8 @@ parameter_types! { /// meaning of this value. pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - /// Identifier of the sibling Rococo People parachain. - pub RococoPeopleParaId: cumulus_primitives_core::ParaId = rococo_runtime_constants::system_parachain::PEOPLE_ID.into(); - /// A route (XCM location and bridge lane) that the Rococo People Chain -> Rococo Bulletin Chain - /// message is following. - pub FromRococoPeopleToRococoBulletinRoute: SenderAndLane = SenderAndLane::new( - ParentThen(Parachain(RococoPeopleParaId::get().into()).into()).into(), - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - ); - /// All active routes and their destinations. - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromRococoPeopleToRococoBulletinRoute::get(), - (RococoBulletinGlobalConsensusNetwork::get(), Here) - ) - ]; - - /// XCM message that is never sent. - pub NeverSentMessage: Option> = None; + pub storage BridgeDeposit: Balance = 5 * ROC; } -pub const XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN: LaneId = LaneId([0, 0, 0, 0]); /// Proof of messages, coming from Rococo Bulletin chain. pub type FromRococoBulletinMessagesProof = @@ -110,34 +86,15 @@ type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< BridgeRococoToRococoBulletinMessagesPalletInstance, >; -/// Export XCM messages to be relayed to the other side -pub type ToRococoBulletinHaulBlobExporter = XcmOverRococoBulletin; - -pub struct ToRococoBulletinXcmBlobHauler; -impl XcmBlobHauler for ToRococoBulletinXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithRococoBulletinMessagesInstance; - type ToSourceChainSender = XcmRouter; - type CongestedMessage = NeverSentMessage; - type UncongestedMessage = NeverSentMessage; -} - -/// On messages delivered callback. -type OnMessagesDeliveredFromRococoBulletin = - XcmBlobHaulerAdapter; - /// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin /// chain. -pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersSignedExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubRococoRefundRococoBulletinMessages, Runtime, - RefundableMessagesLane< - WithRococoBulletinMessagesInstance, - RococoPeopleToRococoBulletinMessagesLane, - >, - ActualFeeRefund, + WithRococoBulletinMessagesInstance, PriorityBoostPerMessage, - StrOnBridgeHubRococoRefundRococoBulletinMessages, >, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundRococoBulletinMessages); @@ -153,8 +110,6 @@ impl pallet_bridge_messages::Config for Runt type BridgedChain = bp_polkadot_bulletin::PolkadotBulletin; type BridgedHeaderChain = BridgeRococoBulletinGrandpa; - type ActiveOutboundLanes = ActiveOutboundLanesToRococoBulletin; - type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; @@ -162,22 +117,36 @@ impl pallet_bridge_messages::Config for Runt type DeliveryConfirmationPayments = (); - type MessageDispatch = - XcmBlobMessageDispatch; - type OnMessagesDelivered = OnMessagesDeliveredFromRococoBulletin; + type MessageDispatch = XcmOverRococoBulletin; + type OnMessagesDelivered = XcmOverRococoBulletin; } /// Add support for the export and dispatch of XCM programs. pub type XcmOverPolkadotBulletinInstance = pallet_xcm_bridge_hub::Instance2; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoBulletinGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithRococoBulletinMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToRococoBulletinXcmBlobHauler; + + type AdminOrigin = EnsureRoot; + // Only allow calls from relay chains and sibling parachains to directly open the bridge. + type OpenBridgeOrigin = EnsureXcm; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + + type LocalXcmChannelManager = (); + type BlobDispatcher = FromRococoBulletinMessageBlobDispatcher; } #[cfg(test)] @@ -232,13 +201,13 @@ mod tests { // Bulletin chain - it has the same (almost) runtime for Polkadot Bulletin and Rococo // Bulletin, so we have to adhere Polkadot names here - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaRococoBulletinInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithRococoBulletinMessagesInstance, PriorityBoostPerMessage, @@ -252,3 +221,59 @@ mod tests { assert_eq!(BridgeRococoToRococoBulletinMessagesPalletInstance::get(), expected,); } } + +// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI +pub mod migration_for_bridges_v2 { + use super::*; + + // /// A pair of sending chain location and message lane, used by this chain to send messages + // /// over the bridge. + // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] + // pub struct SenderAndLane { + // /// Sending chain relative location. + // pub location: Location, + // /// Message lane, used by the sending chain. + // pub lane: LaneId, + // } + // + // impl SenderAndLane { + // /// Create new object using provided location and lane. + // pub fn new(location: Location, lane: LaneId) -> Self { + // SenderAndLane { location, lane } + // } + // } + // + // pub const XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN: LaneId = LaneId([0, 0, 0, 0]); + // + // parameter_types! { + // pub RococoPeopleParaId: cumulus_primitives_core::ParaId = + // rococo_runtime_constants::system_parachain::PEOPLE_ID.into(); // Lanes + // /// All active lanes that the current bridge supports. + // pub ActiveOutboundLanesToRococoBulletin: &'static [bp_messages::LaneId] + // = &[XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN]; + // /// Lane identifier, used to connect Rococo People and Rococo Bulletin chain. + // pub const RococoPeopleToRococoBulletinMessagesLane: bp_messages::LaneId + // = XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN; + // /// Identifier of the sibling Rococo People parachain. + // /// A route (XCM location and bridge lane) that the Rococo People Chain -> Rococo Bulletin + // Chain /// message is following. + // pub FromRococoPeopleToRococoBulletinRoute: SenderAndLane = SenderAndLane::new( + // ParentThen(Parachain(RococoPeopleParaId::get().into()).into()).into(), + // XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + // ); + // /// All active routes and their destinations. + // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = + // alloc::vec![ ( + // FromRococoPeopleToRococoBulletinRoute::get(), + // (RococoBulletinGlobalConsensusNetwork::get(), Here) + // ) + // ]; + // } + + pub struct StaticToDynamicLanes; + impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { + fn on_runtime_upgrade() -> Weight { + todo!() + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 9880e8a17c2b..42ba288b788c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -20,30 +20,31 @@ use crate::{ bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, weights, xcm_config::UniversalLocation, - BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubWestend, XcmRouter, + AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, LaneId, -}; -use bridge_runtime_common::{ - extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, + target_chain::FromBridgedChainMessagesProof, }; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; +use frame_system::EnsureRoot; +use pallet_bridge_relayers::extension::{ + BridgeRelayersSignedExtension, WithMessagesExtensionConfig, +}; +use pallet_xcm::EnsureXcm; +use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; parameter_types! { pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); @@ -59,24 +60,9 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); - - // Lanes - pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; - pub const AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; - pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( - ParentThen([Parachain(AssetHubRococoParaId::get().into())].into()).into(), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - ); - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromAssetHubRococoToAssetHubWestendRoute::get(), - (WestendGlobalConsensusNetwork::get(), [Parachain(AssetHubWestendParaId::get().into())].into()) - ) - ]; - + // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); pub BridgeHubWestendLocation: Location = Location::new( @@ -86,9 +72,11 @@ parameter_types! { Parachain(::PARACHAIN_ID) ] ); + + pub storage BridgeDeposit: Balance = 5 * ROC; } -pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); +// TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { alloc::vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, @@ -119,33 +107,14 @@ pub type ToWestendBridgeHubMessagesDeliveryProof = type FromWestendMessageBlobDispatcher = BridgeBlobDispatcher; -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubWestendHaulBlobExporter = XcmOverBridgeHubWestend; - -pub struct ToBridgeHubWestendXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubWestendMessagesInstance; - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDeliveredFromWestend = - XcmBlobHaulerAdapter; - /// Signed extension that refunds relayers that are delivering messages from the Westend parachain. -pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersSignedExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubRococoRefundBridgeHubWestendMessages, Runtime, - RefundableMessagesLane< - WithBridgeHubWestendMessagesInstance, - AssetHubRococoToAssetHubWestendMessagesLane, - >, - ActualFeeRefund, + WithBridgeHubWestendMessagesInstance, PriorityBoostPerMessage, - StrOnBridgeHubRococoRefundBridgeHubWestendMessages, >, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWestendMessages); @@ -164,8 +133,6 @@ impl pallet_bridge_messages::Config for Ru bp_bridge_hub_westend::BridgeHubWestend, >; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWestend; - type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; @@ -177,28 +144,41 @@ impl pallet_bridge_messages::Config for Ru DeliveryRewardInBalance, >; - type MessageDispatch = XcmBlobMessageDispatch< - FromWestendMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubRococoParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDeliveredFromWestend; + type MessageDispatch = XcmOverBridgeHubWestend; + type OnMessagesDelivered = XcmOverBridgeHubWestend; } /// Add support for the export and dispatch of XCM programs. pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = WestendGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToBridgeHubWestendXcmBlobHauler; + + type AdminOrigin = EnsureRoot; + // Only allow calls from relay chains and sibling parachains to directly open the bridge. + type OpenBridgeOrigin = EnsureXcm; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: + // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + // AssetHubRococoParaId, + // Runtime, + // >, + type LocalXcmChannelManager = (); + type BlobDispatcher = FromWestendMessageBlobDispatcher; } #[cfg(test)] @@ -207,14 +187,11 @@ mod tests { use crate::bridge_common_config::BridgeGrandpaWestendInstance; use bridge_runtime_common::{ assert_complete_bridge_types, - extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_with_parachain_bridge_constants, check_message_lane_weights, AssertChainConstants, AssertCompleteBridgeConstants, }, }; - use parachains_common::Balance; - use testnet_parachains_constants::rococo; /// Every additional message in the message delivery transaction boosts its priority. /// So the priority of transaction with `N+1` messages is larger than priority of @@ -225,12 +202,12 @@ mod tests { /// /// We want this tip to be large enough (delivery transactions with more messages = less /// operational costs and a faster bridge), so this value should be significant. - const FEE_BOOST_PER_MESSAGE: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_MESSAGE: Balance = 2 * ROC; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * ROC; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * ROC; #[test] fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() { @@ -268,19 +245,20 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaWestendInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + WithBridgeHubWestendMessagesInstance, + bp_bridge_hub_westend::BridgeHubWestend, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubWestendMessagesInstance, PriorityBoostPerMessage, @@ -294,3 +272,56 @@ mod tests { assert_eq!(BridgeRococoToWestendMessagesPalletInstance::get(), expected,); } } + +// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI +pub mod migration_for_bridges_v2 { + use super::*; + + // /// A pair of sending chain location and message lane, used by this chain to send messages + // /// over the bridge. + // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] + // pub struct SenderAndLane { + // /// Sending chain relative location. + // pub location: Location, + // /// Message lane, used by the sending chain. + // pub lane: LaneId, + // } + // + // impl SenderAndLane { + // /// Create new object using provided location and lane. + // pub fn new(location: Location, lane: LaneId) -> Self { + // SenderAndLane { location, lane } + // } + // } + // + // pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); + // parameter_types! { + // pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = + // bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); pub AssetHubWestendParaId: + // cumulus_primitives_core::ParaId = + // bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); + // + // // Lanes + // pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = + // &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; pub const + // AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = + // XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; + // pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( + // ParentThen([Parachain(AssetHubRococoParaId::get().into())].into()).into(), + // XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + // ); + // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = + // alloc::vec![ ( + // FromAssetHubRococoToAssetHubWestendRoute::get(), + // (WestendGlobalConsensusNetwork::get(), + // [Parachain(AssetHubWestendParaId::get().into())].into()) ) + // ]; + // } + + pub struct StaticToDynamicLanes; + impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { + fn on_runtime_upgrade() -> Weight { + todo!() + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 02ef0b9c0c72..3305c6a5cf5c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -39,10 +39,7 @@ extern crate alloc; use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ - check_obsolete_extension::{ - CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, - }, - refund_relayer_extension::RefundableParachain, + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use snowbridge_beacon_primitives::{Fork, ForkVersions}; @@ -164,6 +161,8 @@ pub type Migrations = ( ConstU32, ConstU32, >, + bridge_to_westend_config::migration_for_bridges_v2::StaticToDynamicLanes, + bridge_to_bulletin_config::migration_for_bridges_v2::StaticToDynamicLanes, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -779,10 +778,8 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { // Parachains CheckAndBoostBridgeParachainsTransactions< Runtime, - RefundableParachain< bridge_common_config::BridgeParachainWestendInstance, - bp_bridge_hub_westend::BridgeHubWestend, - >, + bp_bridge_hub_westend::BridgeHubWestend, bridge_to_westend_config::PriorityBoostPerParachainHeader, xcm_config::TreasuryAccount, >, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 8c077470ba1a..185af32ee5c8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -17,10 +17,11 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, + TransactionByteFee, WeightToFee, XcmOverBridgeHubWestend, XcmOverRococoBulletin, XcmpQueue, }; use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; + use core::marker::PhantomData; use frame_support::{ parameter_types, @@ -39,22 +40,20 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use snowbridge_runtime_common::XcmExportFeeToSibling; -use sp_core::Get; use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; use xcm_builder::{ - deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, - AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, - AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, - FrameTransactionalProcessor, FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, + FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{ - traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset}, + traits::{FeeManager, FeeReason, FeeReason::Export}, XcmExecutor, }; @@ -226,8 +225,8 @@ impl xcm_executor::Config for XcmConfig { ), >; type MessageExporter = ( - crate::bridge_to_westend_config::ToBridgeHubWestendHaulBlobExporter, - crate::bridge_to_bulletin_config::ToRococoBulletinHaulBlobExporter, + XcmOverBridgeHubWestend, + XcmOverRococoBulletin, crate::bridge_to_ethereum_config::SnowbridgeExporter, ); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index ca0d89f038cb..9adfc821d83b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -148,7 +148,7 @@ mod bridge_hub_westend_tests { use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ BridgeHubWestendLocation, WestendGlobalConsensusNetwork, - WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + WithBridgeHubWestendMessagesInstance, }; // Para id of sibling chain used in tests. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 4326cbf926d6..40f49f605d0b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -103,6 +103,7 @@ bridge-hub-common = { workspace = true } [dev-dependencies] bridge-hub-test-utils = { workspace = true, default-features = true } bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } +pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } sp-keyring = { workspace = true, default-features = true } [features] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index be4d40c2275f..2f211f8f38c1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -18,33 +18,35 @@ use crate::{ bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, - BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubRococo, XcmRouter, + AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, LaneId, + target_chain::FromBridgedChainMessagesProof, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; -use bridge_runtime_common::{ - extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, -}; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; + use codec::Encode; use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, }; +use frame_system::EnsureRoot; +use pallet_bridge_relayers::extension::{ + BridgeRelayersSignedExtension, WithMessagesExtensionConfig, +}; +use pallet_xcm::EnsureXcm; +use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; parameter_types! { pub const RelayChainHeadersToKeep: u32 = 1024; @@ -66,24 +68,9 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); - pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - - // Lanes - pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; - pub const AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; - pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen([Parachain(AssetHubWestendParaId::get().into())].into()).into(), - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - ); - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromAssetHubWestendToAssetHubRococoRoute::get(), - (RococoGlobalConsensusNetwork::get(), [Parachain(AssetHubRococoParaId::get().into())].into()) - ) - ]; - + // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); + // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); pub BridgeHubRococoLocation: Location = Location::new( @@ -93,9 +80,11 @@ parameter_types! { Parachain(::PARACHAIN_ID) ] ); + + pub storage BridgeDeposit: Balance = 10 * WND; } -pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); +// TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { alloc::vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, @@ -126,33 +115,14 @@ pub type ToRococoBridgeHubMessagesDeliveryProof = type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher; -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubRococoHaulBlobExporter = XcmOverBridgeHubRococo; - -pub struct ToBridgeHubRococoXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubRococoMessagesInstance; - - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDelivered = XcmBlobHaulerAdapter; - /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersSignedExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubWestendRefundBridgeHubRococoMessages, Runtime, - RefundableMessagesLane< - WithBridgeHubRococoMessagesInstance, - AssetHubWestendToAssetHubRococoMessagesLane, - >, - ActualFeeRefund, + WithBridgeHubRococoMessagesInstance, PriorityBoostPerMessage, - StrOnBridgeHubWestendRefundBridgeHubRococoMessages, >, >; bp_runtime::generate_static_str_provider!(OnBridgeHubWestendRefundBridgeHubRococoMessages); @@ -195,8 +165,6 @@ impl pallet_bridge_messages::Config for Run bp_bridge_hub_rococo::BridgeHubRococo, >; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; - type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; @@ -208,27 +176,40 @@ impl pallet_bridge_messages::Config for Run DeliveryRewardInBalance, >; - type MessageDispatch = XcmBlobMessageDispatch< - FromRococoMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubWestendParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDelivered; + type MessageDispatch = XcmOverBridgeHubRococo; + type OnMessagesDelivered = XcmOverBridgeHubRococo; } /// Add support for the export and dispatch of XCM programs. pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToBridgeHubRococoXcmBlobHauler; + + type AdminOrigin = EnsureRoot; + // Only allow calls from relay chains and sibling parachains to directly open the bridge. + type OpenBridgeOrigin = EnsureXcm; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: + // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< + // AssetHubWestendParaId, + // Runtime, + // > + type LocalXcmChannelManager = (); + type BlobDispatcher = FromRococoMessageBlobDispatcher; } #[cfg(test)] @@ -236,14 +217,11 @@ mod tests { use super::*; use bridge_runtime_common::{ assert_complete_bridge_types, - extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_with_parachain_bridge_constants, check_message_lane_weights, AssertChainConstants, AssertCompleteBridgeConstants, }, }; - use parachains_common::Balance; - use testnet_parachains_constants::westend; /// Every additional message in the message delivery transaction boosts its priority. /// So the priority of transaction with `N+1` messages is larger than priority of @@ -254,12 +232,12 @@ mod tests { /// /// We want this tip to be large enough (delivery transactions with more messages = less /// operational costs and a faster bridge), so this value should be significant. - const FEE_BOOST_PER_MESSAGE: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_MESSAGE: Balance = 2 * WND; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * WND; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * WND; #[test] fn ensure_bridge_hub_westend_message_lane_weights_are_correct() { @@ -297,19 +275,20 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaRococoInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + WithBridgeHubRococoMessagesInstance, + bp_bridge_hub_rococo::BridgeHubRococo, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubRococoMessagesInstance, PriorityBoostPerMessage, @@ -323,3 +302,55 @@ mod tests { ); } } + +// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI +pub mod migration_for_bridges_v2 { + use super::*; + + // /// A pair of sending chain location and message lane, used by this chain to send messages + // /// over the bridge. + // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] + // pub struct SenderAndLane { + // /// Sending chain relative location. + // pub location: Location, + // /// Message lane, used by the sending chain. + // pub lane: LaneId, + // } + // + // impl SenderAndLane { + // /// Create new object using provided location and lane. + // pub fn new(location: Location, lane: LaneId) -> Self { + // SenderAndLane { location, lane } + // } + // } + // + // pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); + // parameter_types! { + // pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = + // bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); pub AssetHubRococoParaId: + // cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); + // + // // Lanes + // pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = + // &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; pub const + // AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = + // XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; + // pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( + // ParentThen([Parachain(AssetHubWestendParaId::get().into())].into()).into(), + // XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + // ); + // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = + // alloc::vec![ ( + // FromAssetHubWestendToAssetHubRococoRoute::get(), + // (RococoGlobalConsensusNetwork::get(), [Parachain(AssetHubRococoParaId::get().into())].into()) + // ) + // ]; + // } + + pub struct StaticToDynamicLanes; + impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { + fn on_runtime_upgrade() -> Weight { + todo!() + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index d9f19afc6296..7daf9d4623f7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -36,10 +36,7 @@ extern crate alloc; use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ - check_obsolete_extension::{ - CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, - }, - refund_relayer_extension::RefundableParachain, + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::ParaId; @@ -137,6 +134,7 @@ pub type Migrations = ( // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + bridge_to_rococo_config::migration_for_bridges_v2::StaticToDynamicLanes, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -534,10 +532,8 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { // Parachains CheckAndBoostBridgeParachainsTransactions< Runtime, - RefundableParachain< - bridge_to_rococo_config::BridgeParachainRococoInstance, - bp_bridge_hub_rococo::BridgeHubRococo, - >, + bridge_to_rococo_config::BridgeParachainRococoInstance, + bp_bridge_hub_rococo::BridgeHubRococo, bridge_to_rococo_config::PriorityBoostPerParachainHeader, xcm_config::TreasuryAccount, >, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 7f94b76a005b..59c526d294ea 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -17,7 +17,7 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, + TransactionByteFee, WeightToFee, XcmOverBridgeHubRococo, XcmpQueue, }; use frame_support::{ parameter_types, @@ -197,7 +197,7 @@ impl xcm_executor::Config for XcmConfig { WaivedLocations, SendXcmFeeToAccount, >; - type MessageExporter = (crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter,); + type MessageExporter = (XcmOverBridgeHubRococo,); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 98a789eb4e00..698bee80937b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -28,7 +28,7 @@ use bridge_hub_westend_runtime::{ }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + WithBridgeHubRococoMessagesInstance, }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 3ae43075000b..9cb24a2b2820 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -12,6 +12,7 @@ scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } cumulus-primitives-core = { workspace = true } xcm = { workspace = true } pallet-message-queue = { workspace = true } @@ -28,6 +29,7 @@ std = [ "snowbridge-core/std", "sp-core/std", "sp-runtime/std", + "sp-std/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs index aac6eb036526..b806b8cdb22d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs @@ -16,6 +16,7 @@ pub mod digest_item; pub mod message_queue; +pub mod xcm_version; pub use digest_item::CustomDigestItem; pub use message_queue::{AggregateMessageOrigin, BridgeHubMessageRouter}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs new file mode 100644 index 000000000000..72e6c697e44a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs @@ -0,0 +1,44 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Custom XCM implementation. + +use frame_support::traits::Get; +use xcm::{ + latest::prelude::*, + prelude::{GetVersion, XcmVersion}, +}; + +/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal +/// configured XCM version between the destination `dest` and the bridge hub location provided as +/// `Get`. +pub struct XcmVersionOfDestAndRemoteBridge( + sp_std::marker::PhantomData<(Version, RemoteBridge)>, +); +impl> GetVersion + for XcmVersionOfDestAndRemoteBridge +{ + fn get_version_for(dest: &Location) -> Option { + let dest_version = Version::get_version_for(dest); + let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); + + match (dest_version, bridge_hub_version) { + (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), + (Some(dv), None) => Some(dv), + (None, Some(bhv)) => Some(bhv), + (None, None) => None, + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 44a8646142d6..8c048a0d2dbd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -41,14 +41,17 @@ xcm-executor = { workspace = true } # Bridges bp-header-chain = { workspace = true } bp-messages = { workspace = true } +bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-test-utils = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-parachains = { workspace = true } pallet-bridge-messages = { features = ["test-helpers"], workspace = true } pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } bridge-runtime-common = { workspace = true } [features] @@ -57,10 +60,12 @@ std = [ "asset-test-utils/std", "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", "bp-polkadot-core/std", "bp-relayers/std", "bp-runtime/std", "bp-test-utils/std", + "bp-xcm-bridge-hub/std", "bridge-runtime-common/std", "codec/std", "cumulus-pallet-parachain-system/std", @@ -75,6 +80,7 @@ std = [ "pallet-bridge-relayers/std", "pallet-timestamp/std", "pallet-utility/std", + "pallet-xcm-bridge-hub/std", "parachains-common/std", "parachains-runtimes-test-utils/std", "sp-core/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs index f2f0ccecba13..a2c2e6204400 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -26,7 +26,7 @@ use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; use bp_messages::{LaneId, UnrewardedRelayersState}; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs index 0988528c3f2a..69ff24876a37 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -28,7 +28,7 @@ use bp_messages::{LaneId, UnrewardedRelayersState}; use bp_polkadot_core::parachains::ParaHash; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Chain, Parachain}; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index c4b5e5583baa..3c2afb44a008 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -157,8 +157,8 @@ where fn verify_outcome(&self) { assert_eq!( pallet_bridge_messages::InboundLanes::::get(self.lane) - .last_delivered_nonce(), - self.expected_nonce, + .map(|d| d.last_delivered_nonce()), + Some(self.expected_nonce), ); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index a36a74dbbbc3..cd5fef0e99d7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -29,12 +29,10 @@ use crate::{test_cases::bridges_prelude::*, test_data}; use asset_test_utils::BasicParachainRuntime; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, MessageKey, MessagesOperatingMode, OutboundLaneData, + LaneId, LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData, }; use bp_runtime::BasicOperatingMode; -use bridge_runtime_common::messages_xcm_extension::{ - XcmAsPlainPayload, XcmBlobMessageDispatchResult, -}; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use frame_support::{ assert_ok, @@ -42,6 +40,7 @@ use frame_support::{ traits::{Get, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; +use pallet_xcm_bridge_hub::XcmBlobMessageDispatchResult; use parachains_common::AccountId; use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeCallOf, @@ -57,11 +56,11 @@ use xcm_executor::{ /// Common bridges exports. pub(crate) mod bridges_prelude { + pub use bp_parachains::{RelayBlockHash, RelayBlockNumber}; pub use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; pub use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; pub use pallet_bridge_parachains::{ - Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, - RelayBlockNumber, + Call as BridgeParachainsCall, Config as BridgeParachainsConfig, }; } @@ -390,6 +389,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< expected_lane_id ), Ok(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 0, latest_generated_nonce: 1, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs index 5c1dc492a9d2..2940c4e00f42 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs @@ -20,12 +20,12 @@ use crate::test_data::prepare_inbound_xcm; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, MessageNonce, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, LaneState, + MessageNonce, UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, BlockNumberOf, Chain, HeaderOf, UnverifiedStorageProofParams}; use bp_test_utils::make_default_justification; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::{BridgedChain, BridgedHeader}; use sp_runtime::traits::Header as HeaderT; @@ -225,6 +225,7 @@ where prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer_id_at_this_chain, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs index b99c275bd0df..aefbc0dbd0a7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs @@ -20,17 +20,17 @@ use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepa use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, LaneState, UnrewardedRelayersState, Weight, }; +use bp_parachains::{RelayBlockHash, RelayBlockNumber}; use bp_runtime::{ AccountIdOf, BlockNumberOf, Chain, HeaderOf, Parachain, UnverifiedStorageProofParams, }; use bp_test_utils::prepare_parachain_heads_proof; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::BridgedHeader; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber}; use sp_runtime::traits::Header as HeaderT; use xcm::latest::prelude::*; @@ -292,6 +292,7 @@ where prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer_id_at_this_chain.into(), From aee6db8f73bf267ec50ad0539c9bb1380624469a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 22 Jul 2024 22:21:40 +0200 Subject: [PATCH 26/95] Added `open_and_close_bridge_work` test case (+ to the BridgeHub tests) --- .../bridge-hub-rococo/tests/tests.rs | 40 +++++- .../bridge-hub-westend/tests/tests.rs | 21 ++- .../test-utils/src/test_cases/mod.rs | 136 +++++++++++++++++- .../parachains/runtimes/test-utils/src/lib.rs | 35 ++++- 4 files changed, 221 insertions(+), 11 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 9adfc821d83b..2969b47fca82 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -19,7 +19,7 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_common_config, bridge_to_bulletin_config, bridge_to_westend_config, - xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, + xcm_config::{LocationToAccountId, RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, @@ -148,7 +148,7 @@ mod bridge_hub_westend_tests { use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ BridgeHubWestendLocation, WestendGlobalConsensusNetwork, - WithBridgeHubWestendMessagesInstance, + WithBridgeHubWestendMessagesInstance, XcmOverBridgeHubWestendInstance, }; // Para id of sibling chain used in tests. @@ -445,6 +445,23 @@ mod bridge_hub_westend_tests { ), ) } + + #[test] + fn open_and_close_bridge_work() { + let source = Location::new(1, [Parachain(2053)]); + let destination = [GlobalConsensus(NetworkId::Westend), Parachain(1075)].into(); + + bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + source, + destination, + ) + } } mod bridge_hub_bulletin_tests { @@ -453,7 +470,7 @@ mod bridge_hub_bulletin_tests { use bridge_hub_test_utils::test_cases::from_grandpa_chain; use bridge_to_bulletin_config::{ RococoBulletinGlobalConsensusNetwork, RococoBulletinGlobalConsensusNetworkLocation, - WithRococoBulletinMessagesInstance, XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + WithRococoBulletinMessagesInstance, XcmOverPolkadotBulletinInstance, }; // Para id of sibling chain used in tests. @@ -586,4 +603,21 @@ mod bridge_hub_bulletin_tests { construct_and_apply_extrinsic, ) } + + #[test] + fn open_and_close_bridge_work() { + let source = Location::new(1, [Parachain(2053)]); + let destination = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + + bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + source, + destination, + ) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 698bee80937b..64e265579c13 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -21,14 +21,14 @@ use bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlas use bridge_hub_test_utils::{test_cases::from_parachain, SlotDurations}; use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, - xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, + xcm_config::{LocationToAccountId, RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, - WithBridgeHubRococoMessagesInstance, + WithBridgeHubRococoMessagesInstance, XcmOverBridgeHubRococoInstance, }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; @@ -326,3 +326,20 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { ), ) } + +#[test] +fn open_and_close_bridge_work() { + let source = Location::new(1, [Parachain(2053)]); + let destination = [GlobalConsensus(NetworkId::Rococo), Parachain(1075)].into(); + + bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + source, + destination, + ) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index cd5fef0e99d7..4120bff45746 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -32,15 +32,14 @@ use bp_messages::{ LaneId, LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData, }; use bp_runtime::BasicOperatingMode; -use bp_xcm_bridge_hub::XcmAsPlainPayload; +use bp_xcm_bridge_hub::{Bridge, BridgeState, XcmAsPlainPayload}; use codec::Encode; use frame_support::{ assert_ok, dispatch::GetDispatchInfo, - traits::{Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{fungible::Mutate, Get, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_xcm_bridge_hub::XcmBlobMessageDispatchResult; use parachains_common::AccountId; use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeCallOf, @@ -50,7 +49,7 @@ use sp_runtime::{traits::Zero, AccountId32}; use xcm::{latest::prelude::*, AlwaysLatest}; use xcm_builder::DispatchBlobError; use xcm_executor::{ - traits::{TransactAsset, WeightBounds}, + traits::{ConvertLocation, TransactAsset, WeightBounds}, XcmExecutor, }; @@ -58,10 +57,16 @@ use xcm_executor::{ pub(crate) mod bridges_prelude { pub use bp_parachains::{RelayBlockHash, RelayBlockNumber}; pub use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; - pub use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; + pub use pallet_bridge_messages::{ + Call as BridgeMessagesCall, Config as BridgeMessagesConfig, LanesManagerError, + }; pub use pallet_bridge_parachains::{ Call as BridgeParachainsCall, Config as BridgeParachainsConfig, }; + pub use pallet_xcm_bridge_hub::{ + Call as BridgeXcmOverBridgeCall, Config as BridgeXcmOverBridgeConfig, LanesManagerOf, + XcmBlobMessageDispatchResult, + }; } // Re-export test_case from assets @@ -641,3 +646,124 @@ where estimated_fee.into() } + +/// Helper function to open the bridge/lane for `source` and `destination` while ensuring all +/// required balances are placed into the SA of the source. +pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation,) +where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, +LocationToAccountId: ConvertLocation>{ + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 5_000_000_000_000_u128; + let buy_execution_fee = (Location::parent(), buy_execution_fee_amount).into(); + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into() + + bridge_deposit.into(); + + // SA of source location needs to have some required balance + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + + // open bridge with `Transact` call + let open_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< + Runtime, + XcmOverBridgePalletInstance, + >::open_bridge { + bridge_destination_universal_location: Box::new(destination.into()), + }); + + // execute XCM as source origin would do with `Transact -> Origin::Xcm` + assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + open_bridge_call, + source.clone(), + buy_execution_fee + ) + .ensure_complete()); +} + +/// Test-case makes sure that `Runtime` can open/close bridges. +pub fn open_and_close_bridge_work( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + source: Location, + destination: InteriorLocation, +) where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, + <>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::AccountId: From<::AccountId>, + LocationToAccountId: ConvertLocation>, +{ + run_test::(collator_session_key, runtime_para_id, vec![], || { + // construct expected bridge configuration + let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + Box::new(destination.clone().into()), + ).expect("valid bridge locations"); + let lanes_manager = LanesManagerOf::::new(); + + // check bridge/lane DOES not exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id + ), + None + ); + assert_eq!( + lanes_manager.active_inbound_lane(locations.bridge_id.lane_id()).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(locations.bridge_id.lane_id()).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + + // open bridge with Transact call from sibling + ensure_opened_bridge::( + source.clone(), + destination, + ); + + // check bridge/lane DOES exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id + ), + Some( + Bridge { + bridge_origin_relative_location: Box::new(source.clone().into()), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location(&source) + .expect("valid location") + .into(), + reserve: >::BridgeDeposit::get(), + } + ) + ); + assert_eq!( + lanes_manager + .active_inbound_lane(locations.bridge_id.lane_id()) + .map(|lane| lane.state()), + Ok(LaneState::Opened) + ); + assert_eq!( + lanes_manager + .active_outbound_lane(locations.bridge_id.lane_id()) + .map(|lane| lane.state()), + Ok(LaneState::Opened) + ); + }); +} diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 940aa1b734df..fe75b2b6e72f 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -22,7 +22,7 @@ use cumulus_primitives_core::{ use cumulus_primitives_parachain_inherent::ParachainInherentData; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use frame_support::{ - dispatch::{DispatchResult, RawOrigin}, + dispatch::{DispatchResult, GetDispatchInfo, RawOrigin}, inherent::{InherentData, ProvideInherent}, pallet_prelude::Get, traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable}, @@ -450,6 +450,7 @@ impl< require_weight_at_most, call: call.into(), }, + ExpectTransactStatus(MaybeErrorCode::Success), ]); // execute xcm as parent origin @@ -462,6 +463,38 @@ impl< Weight::zero(), ) } + + pub fn execute_as_origin_xcm( + call: Call, + origin: Location, + buy_execution_fee: Asset, + ) -> Outcome { + // prepare `Transact` xcm + let xcm = Xcm(vec![ + WithdrawAsset(buy_execution_fee.clone().into()), + BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: call.get_dispatch_info().weight, + call: call.encode().into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]); + + // execute xcm as parent origin + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + <::XcmExecutor>::prepare_and_execute( + origin.clone(), + xcm, + &mut hash, + Self::xcm_max_weight(if origin == Location::parent() { + XcmReceivedFrom::Parent + } else { + XcmReceivedFrom::Sibling + }), + Weight::zero(), + ) + } } pub enum XcmReceivedFrom { From 10b39cd23a5a2a6f802c558d10799d81dc0eb9cb Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 23 Jul 2024 13:13:16 +0200 Subject: [PATCH 27/95] More tests fixing --- .../test-utils/src/test_cases_over_bridge.rs | 4 +- .../bridge-hub-rococo/tests/tests.rs | 70 +++++++++++++++---- .../bridge-hub-westend/tests/tests.rs | 49 +++++++++++-- .../bridge-hubs/test-utils/src/lib.rs | 1 + .../test-utils/src/test_cases/helpers.rs | 67 +++++++++++++++++- .../test-utils/src/test_cases/mod.rs | 56 +++------------ 6 files changed, 181 insertions(+), 66 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 0b2364dbb8bd..7bc325f70546 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -548,7 +548,9 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< local_bridge_hub_location, xcm, &mut hash, - RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), + RuntimeHelper::::xcm_max_weight( + XcmReceivedFrom::Sibling, + ), Weight::zero(), ); assert_ok!(outcome.ensure_complete()); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 2969b47fca82..3bb3b0a1dcb2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -151,8 +151,13 @@ mod bridge_hub_westend_tests { WithBridgeHubWestendMessagesInstance, XcmOverBridgeHubWestendInstance, }; - // Para id of sibling chain used in tests. - pub const SIBLING_PARACHAIN_ID: u32 = 1000; + // Random para id of sibling chain used in tests. + pub const SIBLING_PARACHAIN_ID: u32 = 2053; + + parameter_types! { + pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub BridgedLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(1075)].into(); + } // Runtime from tests PoV type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< @@ -367,7 +372,16 @@ mod bridge_hub_westend_tests { bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Rococo, - || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedLocation::get()) + .bridge_id + .lane_id() + }, construct_and_apply_extrinsic, ) } @@ -382,7 +396,16 @@ mod bridge_hub_westend_tests { bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Rococo, - || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedLocation::get()) + .bridge_id + .lane_id() + }, construct_and_apply_extrinsic, ) } @@ -448,8 +471,8 @@ mod bridge_hub_westend_tests { #[test] fn open_and_close_bridge_work() { - let source = Location::new(1, [Parachain(2053)]); - let destination = [GlobalConsensus(NetworkId::Westend), Parachain(1075)].into(); + let source = SiblingParachainLocation::get(); + let destination = BridgedLocation::get(); bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, @@ -457,7 +480,7 @@ mod bridge_hub_westend_tests { LocationToAccountId, >( collator_session_keys(), - bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, source, destination, ) @@ -473,9 +496,14 @@ mod bridge_hub_bulletin_tests { WithRococoBulletinMessagesInstance, XcmOverPolkadotBulletinInstance, }; - // Para id of sibling chain used in tests. + // Para id of RococoPeople sibling parachain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = rococo_runtime_constants::system_parachain::PEOPLE_ID; + parameter_types! { + pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub BridgedBulletinLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + } + // Runtime from tests PoV type RuntimeTestsAdapter = from_grandpa_chain::WithRemoteGrandpaChainHelperAdapter< Runtime, @@ -585,7 +613,16 @@ mod bridge_hub_bulletin_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Rococo, - || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + || { + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) + .bridge_id + .lane_id() + }, construct_and_apply_extrinsic, ) } @@ -599,15 +636,24 @@ mod bridge_hub_bulletin_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Rococo, - || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + || { + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) + .bridge_id + .lane_id() + }, construct_and_apply_extrinsic, ) } #[test] fn open_and_close_bridge_work() { - let source = Location::new(1, [Parachain(2053)]); - let destination = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + let source = SiblingParachainLocation::get(); + let destination = BridgedBulletinLocation::get(); bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 64e265579c13..964b2171c806 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -21,6 +21,7 @@ use bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlas use bridge_hub_test_utils::{test_cases::from_parachain, SlotDurations}; use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, + bridge_to_rococo_config::RococoGlobalConsensusNetwork, xcm_config::{LocationToAccountId, RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, @@ -42,8 +43,13 @@ use sp_runtime::{ use testnet_parachains_constants::westend::{consensus::*, fee::WeightToFee}; use xcm::latest::prelude::*; -// Para id of sibling chain used in tests. -pub const SIBLING_PARACHAIN_ID: u32 = 1000; +// Random para id of sibling chain used in tests. +pub const SIBLING_PARACHAIN_ID: u32 = 2053; + +parameter_types! { + pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub BridgedLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(1075)].into(); +} // Runtime from tests PoV type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< @@ -263,7 +269,40 @@ fn relayed_incoming_message_works() { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, Westend, - || XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedLocation::get()) + .bridge_id + .lane_id() + }, + construct_and_apply_extrinsic, + ) +} + +#[test] +fn free_relay_extrinsic_works() { + // from Rococo + from_parachain::free_relay_extrinsic_works::( + collator_session_keys(), + slot_durations(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Westend, + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedLocation::get()) + .bridge_id + .lane_id() + }, construct_and_apply_extrinsic, ) } @@ -329,8 +368,8 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { #[test] fn open_and_close_bridge_work() { - let source = Location::new(1, [Parachain(2053)]); - let destination = [GlobalConsensus(NetworkId::Rococo), Parachain(1075)].into(); + let source = SiblingParachainLocation::get(); + let destination = BridgedLocation::get(); bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index 0b3463f0df97..b8d6d87051c7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -24,6 +24,7 @@ extern crate alloc; pub use bp_test_utils::test_header; pub use parachains_runtimes_test_utils::*; use sp_runtime::Perbill; +pub use test_cases::helpers::ensure_opened_bridge; /// A helper function for comparing the actual value of a fee constant with its estimated value. The /// estimated value can be overestimated (`overestimate_in_percent`), and if the difference to the diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index 3c2afb44a008..a83ed8c08cc9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -23,11 +23,13 @@ use bp_messages::{LaneId, MessageNonce}; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_relayers::RewardsAccountParams; use bp_runtime::Chain; +use bp_xcm_bridge_hub::BridgeLocations; use codec::Decode; use core::marker::PhantomData; use frame_support::{ assert_ok, - traits::{OnFinalize, OnInitialize, PalletInfoAccess}, + dispatch::GetDispatchInfo, + traits::{fungible::Mutate, OnFinalize, OnInitialize, PalletInfoAccess}, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; @@ -40,6 +42,7 @@ use sp_core::Get; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::TrailingZeroInput, AccountId32}; use xcm::latest::prelude::*; +use xcm_executor::traits::ConvertLocation; /// Verify that the transaction has succeeded. #[impl_trait_for_tuples::impl_for_tuples(30)] @@ -382,3 +385,65 @@ fn execute_and_verify_calls( verifier.verify_outcome(); } } + +/// Helper function to open the bridge/lane for `source` and `destination` while ensuring all +/// required balances are placed into the SA of the source. +pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation) -> BridgeLocations +where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, +LocationToAccountId: ConvertLocation>{ + // construct expected bridge configuration + let locations = + pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + Box::new(destination.clone().into()), + ) + .expect("valid bridge locations"); + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id + ) + .is_none()); + + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 5_000_000_000_000_u128; + let buy_execution_fee = (Location::parent(), buy_execution_fee_amount).into(); + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into() + + bridge_deposit.into(); + + // SA of source location needs to have some required balance + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + + // open bridge with `Transact` call + let open_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< + Runtime, + XcmOverBridgePalletInstance, + >::open_bridge { + bridge_destination_universal_location: Box::new(destination.into()), + }); + + // execute XCM as source origin would do with `Transact -> Origin::Xcm` + assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + open_bridge_call, + source.clone(), + buy_execution_fee + ) + .ensure_complete()); + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id + ) + .is_some()); + + // return locations + *locations +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index 4120bff45746..7ff2ffbb1886 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -37,7 +37,7 @@ use codec::Encode; use frame_support::{ assert_ok, dispatch::GetDispatchInfo, - traits::{fungible::Mutate, Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{Get, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::AccountId; @@ -647,49 +647,6 @@ where estimated_fee.into() } -/// Helper function to open the bridge/lane for `source` and `destination` while ensuring all -/// required balances are placed into the SA of the source. -pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation,) -where - Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, - XcmOverBridgePalletInstance: 'static, - ::RuntimeCall: GetDispatchInfo + From>, - ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, - ::Balance: From, -LocationToAccountId: ConvertLocation>{ - // required balance: ED + fee + BridgeDeposit - let bridge_deposit = - >::BridgeDeposit::get( - ); - // random high enough value for `BuyExecution` fees - let buy_execution_fee_amount = 5_000_000_000_000_u128; - let buy_execution_fee = (Location::parent(), buy_execution_fee_amount).into(); - let balance_needed = ::ExistentialDeposit::get() + - buy_execution_fee_amount.into() + - bridge_deposit.into(); - - // SA of source location needs to have some required balance - let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); - let _ = >::mint_into(&source_account_id, balance_needed) - .expect("mint_into passes"); - - // open bridge with `Transact` call - let open_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< - Runtime, - XcmOverBridgePalletInstance, - >::open_bridge { - bridge_destination_universal_location: Box::new(destination.into()), - }); - - // execute XCM as source origin would do with `Transact -> Origin::Xcm` - assert_ok!(RuntimeHelper::::execute_as_origin_xcm( - open_bridge_call, - source.clone(), - buy_execution_fee - ) - .ensure_complete()); -} - /// Test-case makes sure that `Runtime` can open/close bridges. pub fn open_and_close_bridge_work( collator_session_key: CollatorSessionKeys, @@ -730,9 +687,14 @@ pub fn open_and_close_bridge_work( - source.clone(), - destination, + assert_eq!( + helpers::ensure_opened_bridge::< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + >(source.clone(), destination,) + .bridge_id, + locations.bridge_id ); // check bridge/lane DOES exist From 1ffd99d21e47a80c1ce7e14ac3fb8cbe18fc7ca9 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 25 Jul 2024 17:24:51 +0200 Subject: [PATCH 28/95] Unnecessary `XcmExportFeeToRelayerRewardAccounts` + more tests fixes --- .../bridge-hub-rococo/src/xcm_config.rs | 103 ------------------ .../bridge-hub-rococo/tests/tests.rs | 4 +- .../bridge-hub-westend/tests/tests.rs | 2 +- .../test-utils/src/test_cases/mod.rs | 11 +- 4 files changed, 9 insertions(+), 111 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 185af32ee5c8..b1a7f33d835d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -19,8 +19,6 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmOverBridgeHubWestend, XcmOverRococoBulletin, XcmpQueue, }; -use bp_messages::LaneId; -use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; use core::marker::PhantomData; use frame_support::{ @@ -206,13 +204,6 @@ impl xcm_executor::Config for XcmConfig { type FeeManager = XcmFeeManagerFromComponentsBridgeHub< WaivedLocations, ( - XcmExportFeeToRelayerRewardAccounts< - Self::AssetTransactor, - crate::bridge_to_westend_config::WestendGlobalConsensusNetwork, - crate::bridge_to_westend_config::AssetHubWestendParaId, - bp_bridge_hub_westend::BridgeHubWestend, - crate::bridge_to_westend_config::AssetHubRococoToAssetHubWestendMessagesLane, - >, XcmExportFeeToSibling< bp_rococo::Balance, AccountId, @@ -293,100 +284,6 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -/// A `HandleFee` implementation that simply deposits the fees for `ExportMessage` XCM instructions -/// into the accounts that are used for paying the relayer rewards. -/// Burns the fees in case of a failure. -pub struct XcmExportFeeToRelayerRewardAccounts< - AssetTransactor, - DestNetwork, - DestParaId, - DestBridgedChain, - BridgeLaneId, ->(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgedChain, BridgeLaneId)>); - -impl< - AssetTransactor: TransactAsset, - DestNetwork: Get, - DestParaId: Get, - DestBridgedChain: bp_runtime::Chain, - BridgeLaneId: Get, - > HandleFee - for XcmExportFeeToRelayerRewardAccounts< - AssetTransactor, - DestNetwork, - DestParaId, - DestBridgedChain, - BridgeLaneId, - > -{ - fn handle_fee(fee: Assets, maybe_context: Option<&XcmContext>, reason: FeeReason) -> Assets { - if matches!(reason, FeeReason::Export { network: bridged_network, destination } - if bridged_network == DestNetwork::get() && - destination == [Parachain(DestParaId::get().into())]) - { - let bridged_chain_id = DestBridgedChain::ID; - - // We have 2 relayer rewards accounts: - // - the SA of the source parachain on this BH: this pays the relayers for delivering - // Source para -> Target Para message delivery confirmations - // - the SA of the destination parachain on this BH: this pays the relayers for - // delivering Target para -> Source Para messages - // We split the `ExportMessage` fee between these 2 accounts. - let source_para_account = PayRewardFromAccount::< - pallet_balances::Pallet, - AccountId, - >::rewards_account(RewardsAccountParams::new( - BridgeLaneId::get(), - bridged_chain_id, - RewardsAccountOwner::ThisChain, - )); - - let dest_para_account = PayRewardFromAccount::< - pallet_balances::Pallet, - AccountId, - >::rewards_account(RewardsAccountParams::new( - BridgeLaneId::get(), - bridged_chain_id, - RewardsAccountOwner::BridgedChain, - )); - - for asset in fee.into_inner() { - match asset.fun { - Fungible(total_fee) => { - let source_fee = total_fee / 2; - deposit_or_burn_fee::( - Asset { id: asset.id.clone(), fun: Fungible(source_fee) }.into(), - maybe_context, - AccountId32 { network: None, id: source_para_account.clone().into() } - .into(), - ); - - let dest_fee = total_fee - source_fee; - deposit_or_burn_fee::( - Asset { id: asset.id, fun: Fungible(dest_fee) }.into(), - maybe_context, - AccountId32 { network: None, id: dest_para_account.clone().into() } - .into(), - ); - }, - NonFungible(_) => { - deposit_or_burn_fee::( - asset.into(), - maybe_context, - AccountId32 { network: None, id: source_para_account.clone().into() } - .into(), - ); - }, - } - } - - return Assets::new() - } - - fee - } -} - pub struct XcmFeeManagerFromComponentsBridgeHub( PhantomData<(WaivedLocations, HandleFee)>, ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 3bb3b0a1dcb2..023e4ccda6a8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -358,7 +358,7 @@ mod bridge_hub_westend_tests { _ => None, } }), - || XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + || (), ) } @@ -600,7 +600,7 @@ mod bridge_hub_bulletin_tests { _ => None, } }), - || XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, + || (), ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 964b2171c806..3da1fd8f0b4f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -256,7 +256,7 @@ fn message_dispatch_routing_works() { _ => None, } }), - || XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + || (), ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index 7ff2ffbb1886..ac79e887a1e7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -434,7 +434,7 @@ pub fn message_dispatch_routing_works< unwrap_cumulus_pallet_xcmp_queue_event: Box< dyn Fn(Vec) -> Option>, >, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn(), ) where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -462,8 +462,9 @@ pub fn message_dispatch_routing_works< assert_ne!(runtime_para_id, sibling_parachain_id); run_test::(collator_session_key, runtime_para_id, vec![], || { - let expected_lane_id = prepare_configuration(); + prepare_configuration(); + let dummy_lane_id = LaneId::new(1, 2); let mut alice = [0u8; 32]; alice[0] = 1; @@ -480,7 +481,7 @@ pub fn message_dispatch_routing_works< >((RuntimeNetwork::get(), Here)); let result = <>::MessageDispatch>::dispatch( - test_data::dispatch_message(expected_lane_id, 1, bridging_message), + test_data::dispatch_message(dummy_lane_id, 1, bridging_message), ); assert_eq!( format!("{:?}", result.dispatch_level_result), @@ -508,7 +509,7 @@ pub fn message_dispatch_routing_works< let result = <>::MessageDispatch>::dispatch( DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + key: MessageKey { lane_id: dummy_lane_id, nonce: 1 }, data: DispatchMessageData { payload: Ok(bridging_message.clone()) }, }, ); @@ -540,7 +541,7 @@ pub fn message_dispatch_routing_works< let result = <>::MessageDispatch>::dispatch( DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + key: MessageKey { lane_id: dummy_lane_id, nonce: 1 }, data: DispatchMessageData { payload: Ok(bridging_message) }, }, ); From 50cc635a5ad9b24c28a38008f6554265a5dca33e Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 25 Jul 2024 17:53:44 +0200 Subject: [PATCH 29/95] More clean up WIP: partial clean up Nit+doc --- .../modules/xcm-bridge-hub-router/src/lib.rs | 1 + .../modules/xcm-bridge-hub/src/exporter.rs | 32 ++++++++--- bridges/modules/xcm-bridge-hub/src/lib.rs | 56 +++++++++++-------- bridges/modules/xcm-bridge-hub/src/mock.rs | 17 +++--- .../bridge-hub-rococo/tests/tests.rs | 42 ++++++++------ .../bridge-hub-westend/tests/tests.rs | 26 +++++---- .../test-utils/src/test_cases/mod.rs | 7 ++- 7 files changed, 113 insertions(+), 68 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 55fa3be2e675..5bad965ed7c3 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -98,6 +98,7 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; + /// TODO:(bridges-v2) - FAIL-CI - we dont use it, remove? /// Origin of the sibling bridge hub that is allowed to report bridge status. type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index bf83523f01b4..e5b0e795710e 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -74,6 +74,11 @@ where destination: &mut Option, message: &mut Option>, ) -> Result<(Self::Ticket, Assets), SendError> { + log::trace!( + target: LOG_TARGET, + "Validate for network: {network:?}, channel: {channel:?}, universal_source: {universal_source:?}, destination: {destination:?}" + ); + // `HaulBlobExporter` may consume the `universal_source` and `destination` arguments, so // let's save them before let bridge_origin_universal_location = @@ -101,7 +106,13 @@ where Box::new(bridge_origin_relative_location), Box::new(bridge_destination_universal_location.into()), ) - .map_err(|_| SendError::Unroutable)?; + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Validate `bridge_locations` with error: {e:?}", + ); + SendError::Unroutable + })?; let bridge = Self::bridge(locations.bridge_id).ok_or(SendError::Unroutable)?; let bridge_message = @@ -327,14 +338,14 @@ mod tests { BridgedRelativeDestination::get() } - fn universal_destination() -> InteriorLocation { - [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into() + fn bridged_universal_destination() -> InteriorLocation { + BridgedUniversalDestination::get() } fn open_lane() -> BridgeLocations { // open expected outbound lane let origin = OpenBridgeOrigin::sibling_parachain_origin(); - let with = bridged_asset_hub_location(); + let with = bridged_asset_hub_universal_location(); let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); @@ -350,9 +361,7 @@ mod tests { Bridges::::insert( locations.bridge_id, Bridge { - bridge_origin_relative_location: Box::new( - Location::new(1, Parachain(SIBLING_ASSET_HUB_ID)).into(), - ), + bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, @@ -514,8 +523,11 @@ mod tests { #[test] fn exporter_computes_correct_lane_id() { run_test(|| { + assert_ne!(bridged_universal_destination(), bridged_relative_destination()); + + // Note: The `BridgeId` is created from universal `InteriorLocation`. let expected_bridge_id = - BridgeId::new(&universal_source().into(), &universal_destination().into()); + BridgeId::new(&universal_source().into(), &bridged_universal_destination().into()); if LanesManagerOf::::new() .create_outbound_lane(expected_bridge_id.lane_id()) @@ -524,7 +536,7 @@ mod tests { Bridges::::insert( expected_bridge_id, Bridge { - bridge_origin_relative_location: Box::new(universal_destination().into()), + bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, @@ -537,6 +549,8 @@ mod tests { BridgedRelayNetwork::get(), 0, &mut Some(universal_source()), + // Note: The `ExportMessage` expects relative `InteriorLocation` in the + // `BridgedRelayNetwork`. &mut Some(bridged_relative_destination()), &mut Some(Vec::new().into()), ) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 3f7fb4012c7a..46f2ab01714e 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -152,7 +152,7 @@ pub mod pallet { /// An alias for the bridge metadata. pub type BridgeOf = Bridge>; - /// An alias for the this chain. + /// An alias for this chain. pub type ThisChainOf = pallet_bridge_messages::ThisChainOf>::BridgeMessagesPalletInstance>; /// An alias for the associated lanes manager. @@ -197,12 +197,12 @@ pub mod pallet { Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; // reserve balance on the parachain sovereign account - let reserve = T::BridgeDeposit::get(); + let deposit = T::BridgeDeposit::get(); let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( &locations.bridge_origin_relative_location, ) .ok_or(Error::::InvalidBridgeOriginAccount)?; - T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, reserve) + T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; // save bridge metadata @@ -215,7 +215,7 @@ pub mod pallet { ), state: BridgeState::Opened, bridge_owner_account, - reserve, + reserve: deposit, }); Ok(()) }, @@ -242,7 +242,7 @@ pub mod pallet { // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { bridge_id: locations.bridge_id, - bridge_deposit: Some(reserve), + bridge_deposit: Some(deposit), local_endpoint: Box::new(locations.bridge_origin_universal_location), remote_endpoint: Box::new(locations.bridge_destination_universal_location), }); @@ -436,7 +436,13 @@ pub mod pallet { ), Self::bridged_network_id()?, ) - .map_err(|e| Error::::BridgeLocations(e).into()) + .map_err(|e| { + log::trace!( + target: LOG_TARGET, + "bridge_locations error: {e:?}", + ); + Error::::BridgeLocations(e).into() + }) } } @@ -577,7 +583,7 @@ mod tests { let bridge_owner_account = LocationToAccountId::convert_location(&locations.bridge_origin_relative_location) .unwrap(); - Balances::mint_into(&bridge_owner_account, balance).unwrap(); + assert_ok!(Balances::mint_into(&bridge_owner_account, balance)); bridge_owner_account } @@ -612,7 +618,7 @@ mod tests { fn mock_open_bridge_from( origin: RuntimeOrigin, ) -> (BridgeOf, BridgeLocations) { - mock_open_bridge_from_with(origin, bridged_asset_hub_location()) + mock_open_bridge_from_with(origin, bridged_asset_hub_universal_location()) } fn enqueue_message(lane: LaneId) { @@ -629,7 +635,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( OpenBridgeOrigin::disallowed_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), sp_runtime::DispatchError::BadOrigin, ); @@ -642,7 +648,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( OpenBridgeOrigin::parent_relay_chain_universal_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), Error::::BridgeLocations( BridgeLocationsError::InvalidBridgeOrigin @@ -652,7 +658,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( OpenBridgeOrigin::sibling_parachain_universal_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), Error::::BridgeLocations( BridgeLocationsError::InvalidBridgeOrigin @@ -704,7 +710,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( OpenBridgeOrigin::origin_without_sovereign_account(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), Error::::InvalidBridgeOriginAccount, ); @@ -717,7 +723,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( OpenBridgeOrigin::parent_relay_chain_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), Error::::FailedToReserveBridgeDeposit, ); @@ -730,7 +736,7 @@ mod tests { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ) .unwrap(); fund_origin_sovereign_account( @@ -751,7 +757,10 @@ mod tests { ); assert_noop!( - XcmOverBridge::open_bridge(origin, Box::new(bridged_asset_hub_location().into()),), + XcmOverBridge::open_bridge( + origin, + Box::new(bridged_asset_hub_universal_location().into()), + ), Error::::BridgeAlreadyExists, ); }) @@ -763,7 +772,7 @@ mod tests { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ) .unwrap(); fund_origin_sovereign_account( @@ -777,7 +786,7 @@ mod tests { assert_noop!( XcmOverBridge::open_bridge( origin.clone(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ), Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), ); @@ -788,7 +797,10 @@ mod tests { .purge(); lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).unwrap(); assert_noop!( - XcmOverBridge::open_bridge(origin, Box::new(bridged_asset_hub_location().into()),), + XcmOverBridge::open_bridge( + origin, + Box::new(bridged_asset_hub_universal_location().into()), + ), Error::::LanesManager( LanesManagerError::OutboundLaneAlreadyExists ), @@ -818,7 +830,7 @@ mod tests { // compute all other locations let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), ) .unwrap(); @@ -903,7 +915,7 @@ mod tests { assert_noop!( XcmOverBridge::close_bridge( OpenBridgeOrigin::disallowed_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), 0, ), sp_runtime::DispatchError::BadOrigin, @@ -917,7 +929,7 @@ mod tests { assert_noop!( XcmOverBridge::close_bridge( OpenBridgeOrigin::parent_relay_chain_universal_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), 0, ), Error::::BridgeLocations( @@ -928,7 +940,7 @@ mod tests { assert_noop!( XcmOverBridge::close_bridge( OpenBridgeOrigin::sibling_parachain_universal_origin(), - Box::new(bridged_asset_hub_location().into()), + Box::new(bridged_asset_hub_universal_location().into()), 0, ), Error::::BridgeLocations( diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index a3132d3e8141..39b93130e96f 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -27,9 +27,10 @@ use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{Everything, NeverEnsureOrigin}, + traits::{EnsureOrigin, Everything, NeverEnsureOrigin, OriginTrait}, weights::RuntimeDbWeight, }; +use polkadot_parachain_primitives::primitives::Sibling; use sp_core::H256; use sp_runtime::{ testing::Header as SubstrateHeader, @@ -47,10 +48,6 @@ use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u64; - -use frame_support::traits::{EnsureOrigin, OriginTrait}; -use polkadot_parachain_primitives::primitives::Sibling; - type Block = frame_system::mocking::MockBlock; pub const SIBLING_ASSET_HUB_ID: u32 = 2001; @@ -177,6 +174,11 @@ parameter_types! { pub UnitWeightCost: Weight = Weight::from_parts(10, 10); } +/// **Universal** `InteriorLocation` of bridged asset hub. +pub fn bridged_asset_hub_universal_location() -> InteriorLocation { + BridgedUniversalDestination::get() +} + impl pallet_xcm_bridge_hub::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; @@ -532,11 +534,6 @@ impl MessageDispatch for TestMessageDispatch { } } -/// Location of bridged asset hub. -pub fn bridged_asset_hub_location() -> InteriorLocation { - [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into() -} - /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { sp_io::TestExternalities::new( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 023e4ccda6a8..c6cf60ef8bd7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -153,10 +153,12 @@ mod bridge_hub_westend_tests { // Random para id of sibling chain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = 2053; + // Random para id of bridged chain from different global consensus used in tests. + pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; parameter_types! { pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); - pub BridgedLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(1075)].into(); + pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); } // Runtime from tests PoV @@ -317,14 +319,21 @@ mod bridge_hub_westend_tests { _ => None, } }), - || ExportMessage { network: Westend, destination: [Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())].into(), xcm: Xcm(vec![]) }, + || ExportMessage { network: WestendGlobalConsensusNetwork::get(), destination: [Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(), xcm: Xcm(vec![]) }, Some((TokenLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), || { PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubWestendLocation::get()), XCM_VERSION).expect("version saved!"); - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + .bridge_id + .lane_id() }, ) } @@ -378,7 +387,7 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedLocation::get()) + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) .bridge_id .lane_id() }, @@ -402,7 +411,7 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedLocation::get()) + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) .bridge_id .lane_id() }, @@ -471,9 +480,6 @@ mod bridge_hub_westend_tests { #[test] fn open_and_close_bridge_work() { - let source = SiblingParachainLocation::get(); - let destination = BridgedLocation::get(); - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, XcmOverBridgeHubWestendInstance, @@ -481,8 +487,8 @@ mod bridge_hub_westend_tests { >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - source, - destination, + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), ) } } @@ -566,7 +572,14 @@ mod bridge_hub_bulletin_tests { || { PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(RococoBulletinGlobalConsensusNetworkLocation::get()), XCM_VERSION).expect("version saved!"); - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) + .bridge_id + .lane_id() }, ) } @@ -652,9 +665,6 @@ mod bridge_hub_bulletin_tests { #[test] fn open_and_close_bridge_work() { - let source = SiblingParachainLocation::get(); - let destination = BridgedBulletinLocation::get(); - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, XcmOverPolkadotBulletinInstance, @@ -662,8 +672,8 @@ mod bridge_hub_bulletin_tests { >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - source, - destination, + SiblingParachainLocation::get(), + BridgedBulletinLocation::get(), ) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 3da1fd8f0b4f..e5f6ddfc87a7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -45,10 +45,12 @@ use xcm::latest::prelude::*; // Random para id of sibling chain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = 2053; +// Random para id of bridged chain from different global consensus used in tests. +pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; parameter_types! { pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); - pub BridgedLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(1075)].into(); + pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); } // Runtime from tests PoV @@ -216,14 +218,21 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { _ => None, } }), - || ExportMessage { network: Rococo, destination: [Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())].into(), xcm: Xcm(vec![]) }, + || ExportMessage { network: RococoGlobalConsensusNetwork::get(), destination: [Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(), xcm: Xcm(vec![]) }, Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((WestendLocation::get(), bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()).into()), || { PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubRococoLocation::get()), XCM_VERSION).expect("version saved!"); - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + .bridge_id + .lane_id() }, ) } @@ -275,7 +284,7 @@ fn relayed_incoming_message_works() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedLocation::get()) + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) .bridge_id .lane_id() }, @@ -299,7 +308,7 @@ fn free_relay_extrinsic_works() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedLocation::get()) + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) .bridge_id .lane_id() }, @@ -368,9 +377,6 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { #[test] fn open_and_close_bridge_work() { - let source = SiblingParachainLocation::get(); - let destination = BridgedLocation::get(); - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< Runtime, XcmOverBridgeHubRococoInstance, @@ -378,7 +384,7 @@ fn open_and_close_bridge_work() { >( collator_session_keys(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - source, - destination, + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index ac79e887a1e7..a9ad66646b54 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -343,7 +343,12 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< pallet_bridge_messages::OutboundLanes::::try_get( expected_lane_id ), - Err(()) + Ok(OutboundLaneData { + state: LaneState::Opened, + oldest_unpruned_nonce: 1, + latest_received_nonce: 0, + latest_generated_nonce: 0 + }) ); // prepare `ExportMessage` From 72bf1248c9f6ab7b4b043e5db1cef040f76ab73c Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 26 Jul 2024 16:09:21 +0200 Subject: [PATCH 30/95] Remove `Default` from `LaneId` and `BridgeId` --- bridges/primitives/messages/src/lib.rs | 4 ---- bridges/primitives/xcm-bridge-hub/src/lib.rs | 1 - .../test-utils/src/test_cases/from_grandpa_chain.rs | 8 ++++---- .../test-utils/src/test_cases/from_parachain.rs | 8 ++++---- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 37dc61e8b483..1aa1792a863e 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -195,7 +195,6 @@ impl OperatingMode for MessagesOperatingMode { Clone, Copy, Decode, - Default, Encode, Eq, Ord, @@ -281,9 +280,6 @@ impl LaneState { /// Message nonce. Valid messages will never have 0 nonce. pub type MessageNonce = u64; -/// Message id as a tuple. -pub type BridgeMessageId = (LaneId, MessageNonce); - /// Opaque message payload. We only decode this payload when it is dispatched. pub type MessagePayload = Vec; diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 5752140a2a28..ba2ef20fd14f 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -40,7 +40,6 @@ pub type XcmAsPlainPayload = sp_std::vec::Vec; Clone, Copy, Decode, - Default, Encode, Eq, Ord, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs index a2c2e6204400..72743eaa41db 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -447,7 +447,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -503,7 +503,7 @@ where ThisChainOf, (), >( - LaneId::default(), + LaneId::new(1, 2), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), @@ -551,7 +551,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -603,7 +603,7 @@ where ThisChainOf, (), >( - LaneId::default(), + LaneId::new(1, 2), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs index 69ff24876a37..82edcacdcab5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -552,7 +552,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -622,7 +622,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), 1, 5, 1_000, @@ -684,7 +684,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -739,7 +739,7 @@ where BridgedChainOf, ThisChainOf, >( - LaneId::default(), + LaneId::new(1, 2), 1, 5, 1_000, From fb819e03e3bfcd202c68f7f0c817ceb76983ba7b Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Sat, 27 Jul 2024 01:29:37 +0200 Subject: [PATCH 31/95] Make `LaneId` backwards compatible - part 1 https://github.com/paritytech/parity-bridges-common/issues/2500 https://github.com/paritytech/parity-bridges-common/issues/2794 --- bridges/primitives/messages/Cargo.toml | 1 + bridges/primitives/messages/src/lane.rs | 258 ++++++++++++++++++ bridges/primitives/messages/src/lib.rs | 158 +---------- .../primitives/messages/src/storage_keys.rs | 32 +++ .../primitives/runtime/src/storage_proof.rs | 2 +- .../relays/lib-substrate-relay/src/cli/mod.rs | 90 +++--- .../src/cli/relay_headers_and_messages/mod.rs | 3 +- .../src/cli/relay_messages.rs | 4 +- 8 files changed, 349 insertions(+), 199 deletions(-) create mode 100644 bridges/primitives/messages/src/lane.rs diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 59e458a402dd..29514ecccc25 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -28,6 +28,7 @@ sp-io = { workspace = true } [dev-dependencies] hex = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } +bp-runtime = { features = ["test-helpers"], workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs new file mode 100644 index 000000000000..cd085096f1b6 --- /dev/null +++ b/bridges/primitives/messages/src/lane.rs @@ -0,0 +1,258 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Primitives of messages module, that represents lane id. + +use codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen}; +use frame_support::sp_runtime::Either; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_core::{RuntimeDebug, TypeId, H256}; +use sp_io::hashing::blake2_256; + +/// Bridge lane identifier. +/// +/// Lane connects two endpoints at both sides of the bridge. We assume that every endpoint +/// has its own unique identifier. We want lane identifiers to be the same on the both sides +/// of the bridge (and naturally unique across global consensus if endpoints have unique +/// identifiers). So lane id is the hash (`blake2_256`) of **ordered** encoded locations +/// concatenation (separated by some binary data). I.e.: +/// +/// ```nocompile +/// let endpoint1 = X2(GlobalConsensus(NetworkId::Rococo), Parachain(42)); +/// let endpoint2 = X2(GlobalConsensus(NetworkId::Wococo), Parachain(777)); +/// +/// let final_lane_key = if endpoint1 < endpoint2 { +/// (endpoint1, VALUES_SEPARATOR, endpoint2) +/// } else { +/// (endpoint2, VALUES_SEPARATOR, endpoint1) +/// }.using_encoded(blake2_256); +/// ``` +/// +/// Note: For backwards compatibility reasons, we also handle the older format `[u8; 4]`. +#[derive( + Clone, + Copy, + Decode, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct LaneId(InnerLaneId); + +impl LaneId { + /// Create lane identifier from two locations. + pub fn new(endpoint1: T, endpoint2: T) -> Self { + const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; + + LaneId(InnerLaneId::Hash( + if endpoint1 < endpoint2 { + (endpoint1, VALUES_SEPARATOR, endpoint2) + } else { + (endpoint2, VALUES_SEPARATOR, endpoint1) + } + .using_encoded(blake2_256) + .into(), + )) + } + + /// Create lane identifier from given hash. + /// + /// There's no `From` implementation for the `LaneId`, because using this conversion + /// in a wrong way (i.e. computing hash of endpoints manually) may lead to issues. So we + /// want the call to be explicit. + pub const fn from_inner(inner: Either) -> Self { + LaneId(match inner { + Either::Left(hash) => InnerLaneId::Hash(hash), + Either::Right(array) => InnerLaneId::Array(array), + }) + } +} + +impl core::fmt::Display for LaneId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Display::fmt(&self.0, f) + } +} + +impl core::fmt::Debug for LaneId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.0, f) + } +} + +impl AsRef<[u8]> for LaneId { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl TypeId for LaneId { + const TYPE_ID: [u8; 4] = *b"blan"; +} + +#[derive( + Clone, Copy, Eq, Ord, PartialOrd, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize, +)] +enum InnerLaneId { + /// Old format (for backwards compatibility). + Array([u8; 4]), + /// New format 32-byte hash generated by `blake2_256`. + Hash(H256), +} + +impl Encode for InnerLaneId { + fn encode(&self) -> Vec { + match self { + InnerLaneId::Array(array) => array.encode(), + InnerLaneId::Hash(hash) => hash.encode(), + } + } +} + +impl Decode for InnerLaneId { + fn decode(input: &mut I) -> Result { + // check backwards compatibly first + if input.remaining_len() == Ok(Some(4)) { + let array: [u8; 4] = Decode::decode(input)?; + return Ok(InnerLaneId::Array(array)) + } + + // else check new format + H256::decode(input).map(InnerLaneId::Hash) + } +} + +impl core::fmt::Display for InnerLaneId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + InnerLaneId::Array(array) => write!(f, "Array({:?})", array), + InnerLaneId::Hash(hash) => write!(f, "Hash({:?})", hash), + } + } +} + +impl core::fmt::Debug for InnerLaneId { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + InnerLaneId::Array(array) => array.fmt(fmt), + InnerLaneId::Hash(hash) => hash.fmt(fmt), + } + } +} + +impl AsRef<[u8]> for InnerLaneId { + fn as_ref(&self) -> &[u8] { + match self { + InnerLaneId::Array(array) => array.as_ref(), + InnerLaneId::Hash(hash) => hash.as_ref(), + } + } +} + +/// Lane state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum LaneState { + /// Lane is opened and messages may be sent/received over it. + Opened, + /// Lane is closed and all attempts to send/receive messages to/from this lane + /// will fail. + /// + /// Keep in mind that the lane has two ends and the state of the same lane at + /// its ends may be different. Those who are controlling/serving the lane + /// and/or sending messages over the lane, have to coordinate their actions on + /// both ends to make sure that lane is operating smoothly on both ends. + Closed, +} + +impl LaneState { + /// Returns true if lane state allows sending/receiving messages. + pub fn is_active(&self) -> bool { + matches!(*self, LaneState::Opened) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lane_id_debug_format_matches_inner_hash_format() { + assert_eq!( + format!("{:?}", LaneId(InnerLaneId::Hash(H256::from([1u8; 32])))), + format!("{:?}", H256::from([1u8; 32])), + ); + assert_eq!( + format!("{:?}", LaneId(InnerLaneId::Array([0, 0, 0, 1]))), + format!("{:?}", [0, 0, 0, 1]), + ); + } + + #[test] + fn lane_id_as_ref_works() { + assert_eq!( + "0101010101010101010101010101010101010101010101010101010101010101", + hex::encode(LaneId(InnerLaneId::Hash(H256::from([1u8; 32]))).as_ref()), + ); + assert_eq!("00000001", hex::encode(LaneId(InnerLaneId::Array([0, 0, 0, 1])).as_ref()),); + } + + #[test] + fn lane_id_is_generated_using_ordered_endpoints() { + assert_eq!(LaneId::new(1, 2), LaneId::new(2, 1)); + } + + #[test] + fn lane_id_is_different_for_different_endpoints() { + assert_ne!(LaneId::new(1, 2), LaneId::new(1, 3)); + } + + #[test] + fn lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { + /// Some artificial type that generates the same encoding for different values + /// concatenations. I.e. the encoding for `(Either::Two(1, 2), Either::Two(3, 4))` + /// is the same as encoding of `(Either::Three(1, 2, 3), Either::One(4))`. + /// In practice, this type is not useful, because you can't do a proper decoding. + /// But still there may be some collisions even in proper types. + #[derive(Eq, Ord, PartialEq, PartialOrd)] + enum Either { + Three(u64, u64, u64), + Two(u64, u64), + One(u64), + } + + impl codec::Encode for Either { + fn encode(&self) -> Vec { + match *self { + Self::One(a) => a.encode(), + Self::Two(a, b) => (a, b).encode(), + Self::Three(a, b, c) => (a, b, c).encode(), + } + } + } + + assert_ne!( + LaneId::new(Either::Two(1, 2), Either::Two(3, 4)), + LaneId::new(Either::Three(1, 2, 3), Either::One(4)), + ); + } +} diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 1aa1792a863e..7eb0c5629395 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -31,17 +31,17 @@ pub use frame_support::weights::Weight; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use source_chain::RelayersRewards; -use sp_core::{RuntimeDebug, TypeId, H256}; -use sp_io::hashing::blake2_256; +use sp_core::RuntimeDebug; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; pub use call_info::{ BaseMessagesProofInfo, BridgeMessagesCall, BridgeMessagesCallOf, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, }; +pub use lane::{LaneId, LaneState}; mod call_info; - +mod lane; pub mod source_chain; pub mod storage_keys; pub mod target_chain; @@ -173,110 +173,6 @@ impl OperatingMode for MessagesOperatingMode { } } -/// Bridge lane identifier. -/// -/// Lane connects two endpoints at both sides of the bridge. We assume that every endpoint -/// has its own unique identifier. We want lane identifiers to be the same on the both sides -/// of the bridge (and naturally unique across global consensus if endpoints have unique -/// identifiers). So lane id is the hash (`blake2_256`) of **ordered** encoded locations -/// concatenation (separated by some binary data). I.e.: -/// -/// ```nocompile -/// let endpoint1 = X2(GlobalConsensus(NetworkId::Rococo), Parachain(42)); -/// let endpoint2 = X2(GlobalConsensus(NetworkId::Wococo), Parachain(777)); -/// -/// let final_lane_key = if endpoint1 < endpoint2 { -/// (endpoint1, VALUES_SEPARATOR, endpoint2) -/// } else { -/// (endpoint2, VALUES_SEPARATOR, endpoint1) -/// }.using_encoded(blake2_256); -/// ``` -#[derive( - Clone, - Copy, - Decode, - Encode, - Eq, - Ord, - PartialOrd, - PartialEq, - TypeInfo, - MaxEncodedLen, - Serialize, - Deserialize, -)] -pub struct LaneId(H256); - -impl LaneId { - /// Create lane identifier from two locations. - pub fn new(endpoint1: T, endpoint2: T) -> Self { - const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; - - LaneId( - if endpoint1 < endpoint2 { - (endpoint1, VALUES_SEPARATOR, endpoint2) - } else { - (endpoint2, VALUES_SEPARATOR, endpoint1) - } - .using_encoded(blake2_256) - .into(), - ) - } - - /// Create lane identifier from given hash. - /// - /// There's no `From` implementation for the `LaneId`, because using this conversion - /// in a wrong way (i.e. computing hash of endpoints manually) may lead to issues. So we - /// want the call to be explicit. - pub const fn from_inner(hash: H256) -> Self { - LaneId(hash) - } -} - -impl core::fmt::Display for LaneId { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(fmt) - } -} - -impl core::fmt::Debug for LaneId { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(fmt) - } -} - -impl AsRef for LaneId { - fn as_ref(&self) -> &H256 { - &self.0 - } -} - -impl TypeId for LaneId { - const TYPE_ID: [u8; 4] = *b"blan"; -} - -/// Lane state. -#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] -pub enum LaneState { - /// Lane is opened and messages may be sent/received over it. - Opened, - /// Lane is closed and all attempts to send/receive messages to/from this lane - /// will fail. - /// - /// Keep in mind that the lane has two ends and the state of the same lane at - /// its ends may be different. Those who are controlling/serving the lane - /// and/or sending messages over the lane, have to coordinate their actions on - /// both ends to make sure that lane is operating smoothly on both ends. - Closed, -} - -impl LaneState { - /// Returns true if lane state allows sending/receiving messages. - pub fn is_active(&self) -> bool { - matches!(*self, LaneState::Opened) - } -} - /// Message nonce. Valid messages will never have 0 nonce. pub type MessageNonce = u64; @@ -709,52 +605,4 @@ mod tests { assert!(delivered_messages.contains_message(150)); assert!(!delivered_messages.contains_message(151)); } - - #[test] - fn lane_id_debug_format_matches_inner_hash_format() { - assert_eq!( - format!("{:?}", LaneId(H256::from([1u8; 32]))), - format!("{:?}", H256::from([1u8; 32])), - ); - } - - #[test] - fn lane_id_is_generated_using_ordered_endpoints() { - assert_eq!(LaneId::new(1, 2), LaneId::new(2, 1)); - } - - #[test] - fn lane_id_is_different_for_different_endpoints() { - assert_ne!(LaneId::new(1, 2), LaneId::new(1, 3)); - } - - #[test] - fn lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { - /// Some artificial type that generates the same encoding for different values - /// concatenations. I.e. the encoding for `(Either::Two(1, 2), Either::Two(3, 4))` - /// is the same as encoding of `(Either::Three(1, 2, 3), Either::One(4))`. - /// In practice, this type is not useful, because you can't do a proper decoding. - /// But still there may be some collisions even in proper types. - #[derive(Eq, Ord, PartialEq, PartialOrd)] - enum Either { - Three(u64, u64, u64), - Two(u64, u64), - One(u64), - } - - impl codec::Encode for Either { - fn encode(&self) -> Vec { - match *self { - Self::One(a) => a.encode(), - Self::Two(a, b) => (a, b).encode(), - Self::Three(a, b, c) => (a, b, c).encode(), - } - } - } - - assert_ne!( - LaneId::new(Either::Two(1, 2), Either::Two(3, 4)), - LaneId::new(Either::Three(1, 2, 3), Either::One(4)), - ); - } } diff --git a/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs index 3e7b04a50b0c..ff62dab078e7 100644 --- a/bridges/primitives/messages/src/storage_keys.rs +++ b/bridges/primitives/messages/src/storage_keys.rs @@ -72,6 +72,7 @@ pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { #[cfg(test)] mod tests { use super::*; + use frame_support::sp_runtime::Either; use hex_literal::hex; #[test] @@ -98,6 +99,16 @@ mod tests { "Unexpected storage key: {}", hex::encode(&storage_key), ); + + // check backwards compatibility + let storage_key = + message_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test")), 42).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); } #[test] @@ -111,6 +122,17 @@ mod tests { "Unexpected storage key: {}", hex::encode(&storage_key), ); + + // check backwards compatibility + let storage_key = + outbound_lane_data_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test"))) + .0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); } #[test] @@ -124,5 +146,15 @@ mod tests { "Unexpected storage key: {}", hex::encode(&storage_key), ); + + // check backwards compatibility + let storage_key = + inbound_lane_data_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test"))).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); } } diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 7bfa0d6fde01..53efd572b593 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -280,7 +280,7 @@ where /// Return valid storage proof and state root. /// -/// NOTE: This should only be used for **testing**. +/// Note: This should only be used for **testing**. #[cfg(feature = "std")] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; diff --git a/bridges/relays/lib-substrate-relay/src/cli/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/mod.rs index 2882d230f6aa..ef8403ff68ee 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/mod.rs @@ -16,14 +16,14 @@ //! Deal with CLI args of substrate-to-substrate relay. -use codec::{Decode, Encode}; +use bp_messages::LaneId; use rbtag::BuildInfo; use sp_core::H256; +use sp_runtime::Either; +use std::str::FromStr; use structopt::StructOpt; use strum::{EnumString, VariantNames}; -use bp_messages::LaneId; - pub mod bridge; pub mod chain_schema; pub mod detect_equivocations; @@ -43,7 +43,7 @@ pub type DefaultClient = relay_substrate_client::RpcWithCachingClient; /// Lane id. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HexLaneId(pub H256); +pub struct HexLaneId(Either); impl From for LaneId { fn from(lane_id: HexLaneId) -> LaneId { @@ -51,35 +51,28 @@ impl From for LaneId { } } -impl std::str::FromStr for HexLaneId { +impl FromStr for HexLaneId { type Err = rustc_hex::FromHexError; fn from_str(s: &str) -> Result { - Ok(HexLaneId(H256::from_str(s)?)) - } -} - -/// Nicer formatting for raw bytes vectors. -#[derive(Default, Encode, Decode, PartialEq, Eq)] -pub struct HexBytes(pub Vec); - -impl std::str::FromStr for HexBytes { - type Err = hex::FromHexError; - - fn from_str(s: &str) -> Result { - Ok(Self(hex::decode(s)?)) - } -} - -impl std::fmt::Debug for HexBytes { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "0x{self}") - } -} - -impl std::fmt::Display for HexBytes { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "{}", hex::encode(&self.0)) + // check `H256` variant at first + match H256::from_str(s) { + Ok(hash) => Ok(HexLaneId(Either::Left(hash))), + Err(hash_error) => { + // check backwards compatible + let mut lane_id = [0u8; 4]; + match hex::decode_to_slice(s, &mut lane_id) { + Ok(_) => Ok(HexLaneId(Either::Right(lane_id))), + Err(array_error) => { + log::error!( + target: "bridge", + "Failed to parse `HexLaneId` as hex string: {s:?} - hash_error: {hash_error:?}, array_error: {array_error:?}", + ); + Err(hash_error) + }, + } + }, + } } } @@ -181,15 +174,32 @@ mod tests { use super::*; #[test] - fn hex_bytes_display_matches_from_str_for_clap() { - // given - let hex = HexBytes(vec![1, 2, 3, 4]); - let display = format!("{hex}"); - - // when - let hex2: HexBytes = display.parse().unwrap(); - - // then - assert_eq!(hex.0, hex2.0); + fn hex_lane_id_from_str_works() { + // hash variant + assert!(HexLaneId::from_str( + "101010101010101010101010101010101010101010101010101010101010101" + ) + .is_err()); + assert!(HexLaneId::from_str( + "00101010101010101010101010101010101010101010101010101010101010101" + ) + .is_err()); + assert_eq!( + LaneId::from( + HexLaneId::from_str( + "0101010101010101010101010101010101010101010101010101010101010101" + ) + .unwrap() + ), + LaneId::from_inner(Either::Left(H256::from([1u8; 32]))) + ); + + // array variant + assert!(HexLaneId::from_str("0000001").is_err()); + assert!(HexLaneId::from_str("000000001").is_err()); + assert_eq!( + LaneId::from(HexLaneId::from_str("00000001").unwrap()), + LaneId::from_inner(Either::Right([0, 0, 0, 1])) + ); } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 8e524fe22dec..3786976bed9b 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -360,6 +360,7 @@ mod tests { use relay_substrate_client::{ChainRuntimeVersion, Parachain, SimpleRuntimeVersion}; use sp_core::H256; + use sp_runtime::Either; #[test] // We need `#[allow(dead_code)]` because some of the methods generated by the macros @@ -433,7 +434,7 @@ mod tests { res, BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages { shared: HeadersAndMessagesSharedParams { - lane: vec![HexLaneId(H256::from([0x00u8; 32]))], + lane: vec![HexLaneId(Either::Left(H256::from([0x00u8; 32])))], only_mandatory_headers: false, only_free_headers: false, prometheus_params: PrometheusParams { diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index 1771155bbcd3..34d5226e90c5 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -88,8 +88,8 @@ pub struct RelayMessagesDeliveryConfirmationParams { /// delivery proof. This header must be previously proved to the source chain. #[structopt(long)] at_target_block: u128, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, #[structopt(flatten)] source: SourceConnectionParams, From 692b80b6b33925618fce4c8e747e2a35b819015a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 29 Jul 2024 16:50:13 +0200 Subject: [PATCH 32/95] Disconnect `BridgeId` and `LaneId` to be able fix backwards compatiblity and XCM upgrades Addressing: https://github.com/paritytech/parity-bridges-common/issues/2500 https://github.com/paritytech/parity-bridges-common/issues/2794 --- Cargo.lock | 2 + .../modules/xcm-bridge-hub/src/dispatcher.rs | 26 +- .../modules/xcm-bridge-hub/src/exporter.rs | 125 +++--- bridges/modules/xcm-bridge-hub/src/lib.rs | 388 ++++++++++++------ bridges/primitives/messages/src/lane.rs | 4 +- bridges/primitives/xcm-bridge-hub/Cargo.toml | 4 + bridges/primitives/xcm-bridge-hub/src/lib.rs | 225 +++++++--- 7 files changed, 536 insertions(+), 238 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03474117d254..59025dd253f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2017,6 +2017,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-core", + "sp-io", "sp-std 14.0.0", "staging-xcm", ] diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index e08a21bc9af8..b6f6ed760653 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -28,7 +28,7 @@ use bp_messages::{ LaneId, }; use bp_runtime::messages::MessageDispatchResult; -use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager, XcmAsPlainPayload}; +use bp_xcm_bridge_hub::{LocalXcmChannelManager, XcmAsPlainPayload}; use codec::{Decode, Encode}; use frame_support::{weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; use pallet_bridge_messages::{Config as BridgeMessagesConfig, WeightInfoExt}; @@ -60,9 +60,8 @@ where type DispatchLevelResult = XcmBlobMessageDispatchResult; fn is_active(lane: LaneId) -> bool { - let bridge_id = BridgeId::from_lane_id(lane); - Pallet::::bridge(bridge_id) - .and_then(|bridge| bridge.bridge_origin_relative_location.try_as().cloned().ok()) + Pallet::::bridge_by_lane_id(&lane) + .and_then(|(_, bridge)| bridge.bridge_origin_relative_location.try_as().cloned().ok()) .map(|recipient: Location| !T::LocalXcmChannelManager::is_congested(&recipient)) .unwrap_or(false) } @@ -122,26 +121,31 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{mock::*, Bridges}; + use crate::{mock::*, Bridges, LaneToBridge}; use bp_messages::{target_chain::DispatchMessageData, MessageKey}; - use bp_xcm_bridge_hub::{Bridge, BridgeState}; + use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use frame_support::assert_ok; + use sp_core::H256; - fn bridge_id() -> BridgeId { - BridgeId::from_lane_id(LaneId::new(1, 2)) + fn bridge() -> (BridgeId, LaneId) { + (BridgeId::from_inner(H256::from([1u8; 32])), LaneId::new(1, 2)) } fn run_test_with_opened_bridge(test: impl FnOnce()) { run_test(|| { Bridges::::insert( - bridge_id(), + bridge().0, Bridge { bridge_origin_relative_location: Box::new(Location::new(0, Here).into()), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, + lane_id: bridge().1, }, ); + LaneToBridge::::insert(bridge().1, bridge().0); + assert_ok!(XcmOverBridge::do_try_state()); test(); }); @@ -165,14 +169,14 @@ mod tests { fn dispatcher_is_inactive_when_channel_with_target_chain_is_congested() { run_test_with_opened_bridge(|| { TestLocalXcmChannelManager::make_congested(); - assert!(!XcmOverBridge::is_active(bridge_id().lane_id())); + assert!(!XcmOverBridge::is_active(bridge().1)); }); } #[test] fn dispatcher_is_active_when_channel_with_target_chain_is_not_congested() { run_test_with_opened_bridge(|| { - assert!(XcmOverBridge::is_active(bridge_id().lane_id())); + assert!(XcmOverBridge::is_active(bridge().1)); }); } diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index e5b0e795710e..72d34790ebd4 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -113,34 +113,33 @@ where ); SendError::Unroutable })?; - let bridge = Self::bridge(locations.bridge_id).ok_or(SendError::Unroutable)?; - - let bridge_message = - MessagesPallet::::validate_message(locations.bridge_id.lane_id(), &blob) - .map_err(|e| { - // TODO:(bridges-v2) - add test/std feature gate? FAIL-CI - match e { - Error::LanesManager(ref ei) => - log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), - Error::MessageRejectedByPallet(ref ei) => - log::error!(target: LOG_TARGET, "MessageRejectedByPallet: {ei:?}"), - Error::ReceptionConfirmation(ref ei) => - log::error!(target: LOG_TARGET, "ReceptionConfirmation: {ei:?}"), - _ => (), - }; - - log::error!( - target: LOG_TARGET, - "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?} and laneId: {:?}", - id, - e, - locations, - locations.bridge_id.lane_id(), - ); - SendError::Transport("BridgeValidateError") - })?; - - Ok(((locations.bridge_id, bridge, bridge_message, id), price)) + let bridge = Self::bridge(locations.bridge_id()).ok_or(SendError::Unroutable)?; + + let bridge_message = MessagesPallet::::validate_message(bridge.lane_id, &blob) + .map_err(|e| { + // TODO:(bridges-v2) - add test/std feature gate? FAIL-CI + match e { + Error::LanesManager(ref ei) => + log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), + Error::MessageRejectedByPallet(ref ei) => + log::error!(target: LOG_TARGET, "MessageRejectedByPallet: {ei:?}"), + Error::ReceptionConfirmation(ref ei) => + log::error!(target: LOG_TARGET, "ReceptionConfirmation: {ei:?}"), + _ => (), + }; + + log::error!( + target: LOG_TARGET, + "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?} and laneId: {:?}", + id, + e, + locations, + bridge.lane_id, + ); + SendError::Transport("BridgeValidateError") + })?; + + Ok(((locations.bridge_id().clone(), bridge, bridge_message, id), price)) } fn deliver( @@ -150,9 +149,10 @@ where log::info!( target: LOG_TARGET, - "XCM message {:?} has been enqueued at bridge {:?} with nonce {}", + "XCM message {:?} has been enqueued at bridge {:?} and lane_id: {:?} with nonce {}", id, bridge_id, + bridge.lane_id, artifacts.nonce, ); @@ -247,9 +247,8 @@ impl, I: 'static> Pallet { // if we have not suspended the bridge before (or it is closed), we don't want to do // anything - let bridge_id = BridgeId::from_lane_id(lane_id); - let bridge = match Self::bridge(bridge_id) { - Some(bridge) if bridge.state == BridgeState::Suspended => bridge, + let (bridge_id, bridge) = match Self::bridge_by_lane_id(&lane_id) { + Some(bridge) if bridge.1.state == BridgeState::Suspended => bridge, _ => { // if there is no bridge or it has been closed, then we don't need to send resume // signal to the local origin - it has closed bridge itself, so it should have @@ -265,7 +264,8 @@ impl, I: 'static> Pallet { Err(e) => { log::debug!( target: LOG_TARGET, - "Failed to convert the bridge {:?} location: {:?}", + "Failed to convert the bridge {:?} location for lane_id: {:?}, error {:?}", + bridge_id, lane_id, e, ); @@ -280,7 +280,8 @@ impl, I: 'static> Pallet { Ok(_) => { log::debug!( target: LOG_TARGET, - "Resumed the bridge {:?}, originated by the {:?}", + "Resumed the bridge {:?} and lane_id: {:?}, originated by the {:?}", + bridge_id, lane_id, bridge_origin_relative_location, ); @@ -288,7 +289,8 @@ impl, I: 'static> Pallet { Err(e) => { log::debug!( target: LOG_TARGET, - "Failed to resume the bridge {:?}, originated by the {:?}: {:?}", + "Failed to resume the bridge {:?} and lane_id: {:?}, originated by the {:?}: {:?}", + bridge_id, lane_id, bridge_origin_relative_location, e, @@ -323,10 +325,10 @@ impl HaulBlob for DummyHaulBlob { #[cfg(test)] mod tests { use super::*; - use crate::{mock::*, Bridges, LanesManagerOf}; + use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; use bp_runtime::RangeInclusiveExt; - use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; + use bp_xcm_bridge_hub::{bridge_locations, Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; use xcm_executor::traits::export_xcm; @@ -342,61 +344,66 @@ mod tests { BridgedUniversalDestination::get() } - fn open_lane() -> BridgeLocations { + fn open_lane() -> (BridgeLocations, LaneId) { // open expected outbound lane let origin = OpenBridgeOrigin::sibling_parachain_origin(); let with = bridged_asset_hub_universal_location(); let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); let lanes_manager = LanesManagerOf::::new(); - if lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).is_ok() { + if lanes_manager.create_outbound_lane(lane_id).is_ok() { assert!(lanes_manager - .active_outbound_lane(locations.bridge_id.lane_id()) + .active_outbound_lane(lane_id) .unwrap() .queued_messages() .is_empty()); // insert bridge Bridges::::insert( - locations.bridge_id, + locations.bridge_id(), Bridge { bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, + lane_id, }, ); + LaneToBridge::::insert(lane_id, locations.bridge_id()); } - *locations + assert_ok!(XcmOverBridge::do_try_state()); + + (*locations, lane_id) } - fn open_lane_and_send_regular_message() -> BridgeId { - let locations = open_lane(); + fn open_lane_and_send_regular_message() -> (BridgeId, LaneId) { + let (locations, lane_id) = open_lane(); // now let's try to enqueue message using our `ExportXcm` implementation export_xcm::( BridgedRelayNetwork::get(), 0, - locations.bridge_origin_universal_location, - locations.bridge_destination_universal_location, + locations.bridge_origin_universal_location().clone(), + locations.bridge_destination_universal_location().clone(), vec![Instruction::ClearOrigin].into(), ) .unwrap(); - locations.bridge_id + (locations.bridge_id().clone(), lane_id) } #[test] fn exporter_works() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (_, lane_id) = open_lane_and_send_regular_message(); // double check that the message has been pushed to the expected lane // (it should already been checked during `send_message` call) assert!(!LanesManagerOf::::new() - .active_outbound_lane(bridge_id.lane_id()) + .active_outbound_lane(lane_id) .unwrap() .queued_messages() .is_empty()); @@ -406,7 +413,7 @@ mod tests { #[test] fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, _) = open_lane_and_send_regular_message(); assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); }); @@ -415,7 +422,7 @@ mod tests { #[test] fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, _) = open_lane_and_send_regular_message(); Bridges::::mutate_extant(bridge_id, |bridge| { bridge.state = BridgeState::Suspended; }); @@ -431,7 +438,7 @@ mod tests { #[test] fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, _) = open_lane_and_send_regular_message(); for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { open_lane_and_send_regular_message(); } @@ -448,12 +455,12 @@ mod tests { #[test] fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); Bridges::::mutate_extant(bridge_id, |bridge| { bridge.state = BridgeState::Suspended; }); XcmOverBridge::on_bridge_messages_delivered( - bridge_id.lane_id(), + lane_id, OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, ); @@ -465,9 +472,9 @@ mod tests { #[test] fn bridge_is_not_resumed_if_it_was_not_suspended_before() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); XcmOverBridge::on_bridge_messages_delivered( - bridge_id.lane_id(), + lane_id, OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); @@ -479,12 +486,12 @@ mod tests { #[test] fn bridge_is_resumed_when_enough_messages_are_delivered() { run_test(|| { - let bridge_id = open_lane_and_send_regular_message(); + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); Bridges::::mutate_extant(bridge_id, |bridge| { bridge.state = BridgeState::Suspended; }); XcmOverBridge::on_bridge_messages_delivered( - bridge_id.lane_id(), + lane_id, OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); @@ -569,7 +576,7 @@ mod tests { let dest = Location::new(2, BridgedUniversalDestination::get()); // open bridge - let expected_lane_id = open_lane().bridge_id.lane_id(); + let (_, expected_lane_id) = open_lane(); // check before - no messages assert_eq!( diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 46f2ab01714e..722104818bb0 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -51,7 +51,7 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bp_messages::{LaneState, MessageNonce}; +use bp_messages::{LaneId, LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; use bp_xcm_bridge_hub::{ bridge_locations, Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, @@ -171,6 +171,11 @@ pub mod pallet { T::BridgedNetwork::get() ) } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } } #[pallet::call] @@ -192,59 +197,79 @@ pub mod pallet { origin: OriginFor, bridge_destination_universal_location: Box, ) -> DispatchResult { - // check and compute required bridge locations + // check and compute required bridge locations and laneId + let xcm_version = bridge_destination_universal_location.identify_version(); let locations = Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; + let lane_id = locations.calculate_lane_id(xcm_version).map_err(|e| { + log::trace!( + target: LOG_TARGET, + "calculate_lane_id error: {e:?}", + ); + Error::::BridgeLocations(e) + })?; // reserve balance on the parachain sovereign account let deposit = T::BridgeDeposit::get(); let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - &locations.bridge_origin_relative_location, + locations.bridge_origin_relative_location(), ) .ok_or(Error::::InvalidBridgeOriginAccount)?; T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; // save bridge metadata - Bridges::::try_mutate(locations.bridge_id, |bridge| match bridge { + Bridges::::try_mutate(locations.bridge_id(), |bridge| match bridge { Some(_) => Err(Error::::BridgeAlreadyExists), None => { *bridge = Some(BridgeOf:: { bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location.clone().into(), + locations.bridge_origin_relative_location().clone().into(), ), state: BridgeState::Opened, bridge_owner_account, reserve: deposit, + lane_id, }); Ok(()) }, })?; + // save lane to bridge mapping + LaneToBridge::::try_mutate(lane_id, |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(locations.bridge_id().clone()); + Ok(()) + }, + })?; // create new lanes. Under normal circumstances, following calls shall never fail let lanes_manager = LanesManagerOf::::new(); lanes_manager - .create_inbound_lane(locations.bridge_id.lane_id()) + .create_inbound_lane(lane_id) .map_err(Error::::LanesManager)?; lanes_manager - .create_outbound_lane(locations.bridge_id.lane_id()) + .create_outbound_lane(lane_id) .map_err(Error::::LanesManager)?; // write something to log log::trace!( target: LOG_TARGET, - "Bridge {:?} between {:?} and {:?} has been opened", - locations.bridge_id, - locations.bridge_origin_universal_location, - locations.bridge_destination_universal_location, + "Bridge {:?} between {:?} and {:?} has been opened using lane_id: {lane_id:?}", + locations.bridge_id(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), ); // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), bridge_deposit: Some(deposit), - local_endpoint: Box::new(locations.bridge_origin_universal_location), - remote_endpoint: Box::new(locations.bridge_destination_universal_location), + local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), + remote_endpoint: Box::new( + locations.bridge_destination_universal_location().clone(), + ), + lane_id, }); Ok(()) @@ -283,7 +308,7 @@ pub mod pallet { // update bridge metadata - this also guarantees that the bridge is in the proper state let bridge = - Bridges::::try_mutate_exists(locations.bridge_id, |bridge| match bridge { + Bridges::::try_mutate_exists(locations.bridge_id(), |bridge| match bridge { Some(bridge) => { bridge.state = BridgeState::Closed; Ok(bridge.clone()) @@ -294,10 +319,10 @@ pub mod pallet { // close inbound and outbound lanes let lanes_manager = LanesManagerOf::::new(); let mut inbound_lane = lanes_manager - .any_state_inbound_lane(locations.bridge_id.lane_id()) + .any_state_inbound_lane(bridge.lane_id) .map_err(Error::::LanesManager)?; let mut outbound_lane = lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) + .any_state_outbound_lane(bridge.lane_id) .map_err(Error::::LanesManager)?; // now prune queued messages @@ -321,16 +346,18 @@ pub mod pallet { let enqueued_messages = outbound_lane.queued_messages().saturating_len(); log::trace!( target: LOG_TARGET, - "Bridge {:?} between {:?} and {:?} is closing. {} messages remaining", - locations.bridge_id, - locations.bridge_origin_universal_location, - locations.bridge_destination_universal_location, + "Bridge {:?} between {:?} and {:?} is closing lane_id: {:?}. {} messages remaining", + locations.bridge_id(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + bridge.lane_id, enqueued_messages, ); // deposit the `ClosingBridge` event Self::deposit_event(Event::::ClosingBridge { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), + lane_id: bridge.lane_id, pruned_messages, enqueued_messages, }); @@ -341,7 +368,8 @@ pub mod pallet { // else we have pruned all messages, so lanes and the bridge itself may gone inbound_lane.purge(); outbound_lane.purge(); - Bridges::::remove(locations.bridge_id); + Bridges::::remove(locations.bridge_id()); + LaneToBridge::::remove(bridge.lane_id); // return deposit let released_deposit = T::Currency::release( @@ -356,7 +384,7 @@ pub mod pallet { log::error!( target: LOG_TARGET, "Failed to unreserve during the bridge {:?} closure with error: {e:?}", - locations.bridge_id, + locations.bridge_id(), ); e }) @@ -365,15 +393,17 @@ pub mod pallet { // write something to log log::trace!( target: LOG_TARGET, - "Bridge {:?} between {:?} and {:?} has been closed, the bridge deposit {released_deposit:?} was returned", - locations.bridge_id, - locations.bridge_origin_universal_location, - locations.bridge_destination_universal_location, + "Bridge {:?} between {:?} and {:?} has closed lane_id: {:?}, the bridge deposit {released_deposit:?} was returned", + locations.bridge_id(), + bridge.lane_id, + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), ); // deposit the `BridgePruned` event Self::deposit_event(Event::::BridgePruned { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), + lane_id: bridge.lane_id, bridge_deposit: released_deposit, pruned_messages, }); @@ -417,23 +447,23 @@ pub mod pallet { ) -> Result, sp_runtime::DispatchError> { Self::bridge_locations( Box::new(T::OpenBridgeOrigin::ensure_origin(origin)?), - bridge_destination_universal_location, + Box::new( + (*bridge_destination_universal_location) + .try_into() + .map_err(|_| Error::::UnsupportedXcmVersion)?, + ), ) } - /// Return bridge endpoint locations and dedicated lane identifier. + /// Return bridge endpoint locations and dedicated **bridge** identifier (`BridgeId`). pub fn bridge_locations( bridge_origin_relative_location: Box, - bridge_destination_universal_location: Box, + bridge_destination_universal_location: Box, ) -> Result, sp_runtime::DispatchError> { bridge_locations( Box::new(T::UniversalLocation::get()), bridge_origin_relative_location, - Box::new( - (*bridge_destination_universal_location) - .try_into() - .map_err(|_| Error::::UnsupportedXcmVersion)?, - ), + bridge_destination_universal_location, Self::bridged_network_id()?, ) .map_err(|e| { @@ -444,6 +474,12 @@ pub mod pallet { Error::::BridgeLocations(e).into() }) } + + /// Return bridge metadata by lane_id + pub fn bridge_by_lane_id(lane_id: &LaneId) -> Option<(BridgeId, BridgeOf)> { + LaneToBridge::::get(lane_id) + .and_then(|bridge_id| Self::bridge(bridge_id).map(|bridge| (bridge_id, bridge))) + } } impl, I: 'static> Pallet { @@ -459,11 +495,50 @@ pub mod pallet { } } + #[cfg(any(feature = "try-runtime", test))] + impl, I: 'static> Pallet { + /// Ensure the correctness of the state of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + use sp_std::collections::btree_set::BTreeSet; + + let mut lanes = BTreeSet::new(); + + // check all known bridge configurations + for (bridge_id, bridge) in Bridges::::iter() { + log::info!(target: LOG_TARGET, "Checking `do_try_state` for bridge_id: {bridge_id:?} and bridge: {bridge:?}"); + lanes.insert(Self::do_try_state_for_bridge(bridge_id, bridge)?); + } + ensure!( + lanes.len() == Bridges::::iter().count(), + "Invalid `Bridges` configuration, probably two bridges handle the same laneId!" + ); + ensure!( + lanes.len() == LaneToBridge::::iter().count(), + "Invalid `LaneToBridge` configuration, probably missing or not removed laneId!" + ); + + Ok(()) + } + /// Ensure the correctness of the state of the bridge. + pub fn do_try_state_for_bridge( + bridge_id: BridgeId, + bridge: BridgeOf, + ) -> Result { + + Ok(bridge.lane_id) + } + } + /// All registered bridges. #[pallet::storage] #[pallet::getter(fn bridge)] pub type Bridges, I: 'static = ()> = StorageMap<_, Identity, BridgeId, BridgeOf>; + /// All registered `lane_id` and `bridge_id` mappings. + #[pallet::storage] + #[pallet::getter(fn lane_to_bridge)] + pub type LaneToBridge, I: 'static = ()> = + StorageMap<_, Identity, LaneId, BridgeId>; #[pallet::genesis_config] #[derive(DefaultNoBound)] @@ -492,22 +567,34 @@ pub mod pallet { Box::new(bridge_destination_universal_location.clone().into()), ) .expect("Invalid genesis configuration"); + let lane_id = + locations.calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"); let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - &locations.bridge_origin_relative_location, + locations.bridge_origin_relative_location(), ) .expect("Invalid genesis configuration"); Bridges::::insert( - locations.bridge_id, + locations.bridge_id(), Bridge { bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location.into(), + locations.bridge_origin_relative_location().clone().into(), ), state: BridgeState::Opened, bridge_owner_account, reserve: Zero::zero(), + lane_id, }, ); + LaneToBridge::::insert(lane_id, locations.bridge_id()); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .create_inbound_lane(lane_id) + .expect("Invalid genesis configuration"); + lanes_manager + .create_outbound_lane(lane_id) + .expect("Invalid genesis configuration"); } } } @@ -517,19 +604,24 @@ pub mod pallet { pub enum Event, I: 'static = ()> { /// The bridge between two locations has been opened. BridgeOpened { - /// Universal location of local bridge endpoint. - local_endpoint: Box, - /// Universal location of remote bridge endpoint. - remote_endpoint: Box, /// Bridge identifier. bridge_id: BridgeId, /// Amount of deposit held. bridge_deposit: Option>>, + + /// Universal location of local bridge endpoint. + local_endpoint: Box, + /// Universal location of remote bridge endpoint. + remote_endpoint: Box, + /// Lane identifier. + lane_id: LaneId, }, /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. ClosingBridge { /// Bridge identifier. bridge_id: BridgeId, + /// Lane identifier. + lane_id: LaneId, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, /// Number of enqueued messages that need to be pruned in follow up calls. @@ -540,6 +632,8 @@ pub mod pallet { BridgePruned { /// Bridge identifier. bridge_id: BridgeId, + /// Lane identifier. + lane_id: LaneId, /// Amount of deposit released. bridge_deposit: Option>>, /// Number of pruned messages during the close call. @@ -576,12 +670,14 @@ mod tests { use mock::*; use bp_messages::LaneId; - use frame_support::{assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; + use frame_support::{assert_err, assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; use frame_system::{EventRecord, Phase}; + use sp_core::H256; + use sp_runtime::TryRuntimeError; fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId { let bridge_owner_account = - LocationToAccountId::convert_location(&locations.bridge_origin_relative_location) + LocationToAccountId::convert_location(locations.bridge_origin_relative_location()) .unwrap(); assert_ok!(Balances::mint_into(&bridge_owner_account, balance)); bridge_owner_account @@ -594,23 +690,28 @@ mod tests { let reserve = BridgeDeposit::get(); let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); let bridge_owner_account = fund_origin_sovereign_account(&locations, reserve + ExistentialDeposit::get()); Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, reserve).unwrap(); let bridge = Bridge { bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location.clone().into(), + locations.bridge_origin_relative_location().clone().into(), ), state: BridgeState::Opened, bridge_owner_account, reserve, + lane_id, }; - Bridges::::insert(locations.bridge_id, bridge.clone()); + Bridges::::insert(locations.bridge_id(), bridge.clone()); + LaneToBridge::::insert(bridge.lane_id, locations.bridge_id()); let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_inbound_lane(locations.bridge_id.lane_id()).unwrap(); - lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).unwrap(); + lanes_manager.create_inbound_lane(bridge.lane_id).unwrap(); + lanes_manager.create_outbound_lane(bridge.lane_id).unwrap(); + + assert_ok!(XcmOverBridge::do_try_state()); (bridge, *locations) } @@ -739,20 +840,22 @@ mod tests { Box::new(bridged_asset_hub_universal_location().into()), ) .unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); fund_origin_sovereign_account( &locations, BridgeDeposit::get() + ExistentialDeposit::get(), ); Bridges::::insert( - locations.bridge_id, + locations.bridge_id(), Bridge { bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location.into(), + locations.bridge_origin_relative_location().clone().into(), ), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, + lane_id, }, ); @@ -775,6 +878,7 @@ mod tests { Box::new(bridged_asset_hub_universal_location().into()), ) .unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); fund_origin_sovereign_account( &locations, BridgeDeposit::get() + ExistentialDeposit::get(), @@ -782,7 +886,7 @@ mod tests { let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_inbound_lane(locations.bridge_id.lane_id()).unwrap(); + lanes_manager.create_inbound_lane(lane_id).unwrap(); assert_noop!( XcmOverBridge::open_bridge( origin.clone(), @@ -791,11 +895,8 @@ mod tests { Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), ); - lanes_manager - .active_inbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .purge(); - lanes_manager.create_outbound_lane(locations.bridge_id.lane_id()).unwrap(); + lanes_manager.active_inbound_lane(lane_id).unwrap().purge(); + lanes_manager.create_outbound_lane(lane_id).unwrap(); assert_noop!( XcmOverBridge::open_bridge( origin, @@ -828,22 +929,29 @@ mod tests { System::reset_events(); // compute all other locations + let xcm_version = xcm::latest::VERSION; let locations = XcmOverBridge::bridge_locations_from_origin( origin.clone(), - Box::new(bridged_asset_hub_universal_location().into()), + Box::new( + VersionedInteriorLocation::from(bridged_asset_hub_universal_location()) + .into_version(xcm_version) + .expect("valid conversion"), + ), ) .unwrap(); + let lane_id = locations.calculate_lane_id(xcm_version).unwrap(); // ensure that there's no bridge and lanes in the storage - assert_eq!(Bridges::::get(locations.bridge_id), None); + assert_eq!(Bridges::::get(locations.bridge_id()), None); assert_eq!( - lanes_manager.active_inbound_lane(locations.bridge_id.lane_id()).map(drop), + lanes_manager.active_inbound_lane(lane_id).map(drop), Err(LanesManagerError::UnknownInboundLane) ); assert_eq!( - lanes_manager.active_outbound_lane(locations.bridge_id.lane_id()).map(drop), + lanes_manager.active_outbound_lane(lane_id).map(drop), Err(LanesManagerError::UnknownOutboundLane) ); + assert_eq!(LaneToBridge::::get(lane_id), None); // give enough funds to the sovereign account of the bridge origin let bridge_owner_account = fund_origin_sovereign_account( @@ -859,33 +967,34 @@ mod tests { // now open the bridge assert_ok!(XcmOverBridge::open_bridge( origin, - Box::new(locations.bridge_destination_universal_location.clone().into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), )); // ensure that everything has been set up in the runtime storage assert_eq!( - Bridges::::get(locations.bridge_id), + Bridges::::get(locations.bridge_id()), Some(Bridge { bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location.into() + locations.bridge_origin_relative_location().clone().into() ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), reserve: expected_reserve, + lane_id }), ); assert_eq!( - lanes_manager - .active_inbound_lane(locations.bridge_id.lane_id()) - .map(|l| l.state()), + lanes_manager.active_inbound_lane(lane_id).map(|l| l.state()), Ok(LaneState::Opened) ); assert_eq!( - lanes_manager - .active_outbound_lane(locations.bridge_id.lane_id()) - .map(|l| l.state()), + lanes_manager.active_outbound_lane(lane_id).map(|l| l.state()), Ok(LaneState::Opened) ); + assert_eq!( + LaneToBridge::::get(lane_id), + Some(locations.bridge_id().clone()) + ); assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_reserve); @@ -895,12 +1004,15 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), bridge_deposit: Some(BridgeDeposit::get()), - local_endpoint: Box::new(locations.bridge_origin_universal_location), + local_endpoint: Box::new( + locations.bridge_origin_universal_location().clone() + ), remote_endpoint: Box::new( - locations.bridge_destination_universal_location + locations.bridge_destination_universal_location().clone() ), + lane_id }), topics: vec![], }), @@ -954,35 +1066,26 @@ mod tests { fn close_bridge_fails_if_its_lanes_are_unknown() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let (_, locations) = mock_open_bridge_from(origin.clone()); + let (bridge, locations) = mock_open_bridge_from(origin.clone()); let lanes_manager = LanesManagerOf::::new(); - lanes_manager - .any_state_inbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .purge(); + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().purge(); assert_noop!( XcmOverBridge::close_bridge( origin.clone(), - Box::new(locations.bridge_destination_universal_location.into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), 0, ), Error::::LanesManager(LanesManagerError::UnknownInboundLane), ); - lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .purge(); + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); let (_, locations) = mock_open_bridge_from(origin.clone()); - lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .purge(); + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); assert_noop!( XcmOverBridge::close_bridge( origin, - Box::new(locations.bridge_destination_universal_location.into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), 0, ), Error::::LanesManager(LanesManagerError::UnknownOutboundLane), @@ -1003,13 +1106,13 @@ mod tests { // enqueue some messages for _ in 0..32 { - enqueue_message(locations.bridge_id.lane_id()); + enqueue_message(bridge.lane_id); } // now call the `close_bridge`, which will only partially prune messages assert_ok!(XcmOverBridge::close_bridge( origin.clone(), - Box::new(locations.bridge_destination_universal_location.clone().into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), 16, ),); @@ -1017,31 +1120,29 @@ mod tests { // are pruned, but funds are not unreserved let lanes_manager = LanesManagerOf::::new(); assert_eq!( - Bridges::::get(locations.bridge_id).map(|b| b.state), + Bridges::::get(locations.bridge_id()).map(|b| b.state), Some(BridgeState::Closed) ); assert_eq!( - lanes_manager - .any_state_inbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .state(), + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().state(), LaneState::Closed ); assert_eq!( - lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .state(), + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().state(), LaneState::Closed ); assert_eq!( lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) + .any_state_outbound_lane(bridge.lane_id) .unwrap() .queued_messages() .checked_len(), Some(16) ); + assert_eq!( + LaneToBridge::::get(bridge.lane_id), + Some(locations.bridge_id().clone()) + ); assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); assert_eq!( @@ -1049,7 +1150,8 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), + lane_id: bridge.lane_id, pruned_messages: 16, enqueued_messages: 16, }), @@ -1060,37 +1162,35 @@ mod tests { // now call the `close_bridge` again, which will only partially prune messages assert_ok!(XcmOverBridge::close_bridge( origin.clone(), - Box::new(locations.bridge_destination_universal_location.clone().into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), 8, ),); // nothing is changed (apart from the pruned messages) assert_eq!( - Bridges::::get(locations.bridge_id).map(|b| b.state), + Bridges::::get(locations.bridge_id()).map(|b| b.state), Some(BridgeState::Closed) ); assert_eq!( - lanes_manager - .any_state_inbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .state(), + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().state(), LaneState::Closed ); assert_eq!( - lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) - .unwrap() - .state(), + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().state(), LaneState::Closed ); assert_eq!( lanes_manager - .any_state_outbound_lane(locations.bridge_id.lane_id()) + .any_state_outbound_lane(bridge.lane_id) .unwrap() .queued_messages() .checked_len(), Some(8) ); + assert_eq!( + LaneToBridge::::get(bridge.lane_id), + Some(locations.bridge_id().clone()) + ); assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); assert_eq!( @@ -1098,7 +1198,8 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), + lane_id: bridge.lane_id, pruned_messages: 8, enqueued_messages: 8, }), @@ -1110,20 +1211,24 @@ mod tests { // bridge assert_ok!(XcmOverBridge::close_bridge( origin, - Box::new(locations.bridge_destination_universal_location.into()), + Box::new(locations.bridge_destination_universal_location().clone().into()), 9, ),); // there's no traces of bridge in the runtime storage and funds are unreserved - assert_eq!(Bridges::::get(locations.bridge_id).map(|b| b.state), None); assert_eq!( - lanes_manager.any_state_inbound_lane(locations.bridge_id.lane_id()).map(drop), + Bridges::::get(locations.bridge_id()).map(|b| b.state), + None + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).map(drop), Err(LanesManagerError::UnknownInboundLane) ); assert_eq!( - lanes_manager.any_state_outbound_lane(locations.bridge_id.lane_id()).map(drop), + lanes_manager.any_state_outbound_lane(bridge.lane_id).map(drop), Err(LanesManagerError::UnknownOutboundLane) ); + assert_eq!(LaneToBridge::::get(bridge.lane_id), None); assert_eq!( Balances::free_balance(&bridge.bridge_owner_account), free_balance + reserved_balance @@ -1134,7 +1239,8 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { - bridge_id: locations.bridge_id, + bridge_id: locations.bridge_id().clone(), + lane_id: bridge.lane_id, bridge_deposit: Some(BridgeDeposit::get()), pruned_messages: 8, }), @@ -1143,4 +1249,48 @@ mod tests { ); }); } + + #[test] + fn do_try_state_works() { + use sp_runtime::Either; + + let older_xcm_version = xcm::latest::VERSION - 1; + let bridge_origin_relative_location = Location::new(1, [Parachain(2025)]); + let bridge_owner_account = + LocationToAccountId::convert_location(&bridge_origin_relative_location) + .expect("valid accountId"); + let bridge_id = BridgeId::from_inner(H256::from([1u8; 32])); + let lane_id = LaneId::from_inner(Either::Left(H256::default())); + + let test_bridge_state = + |id, bridge, (lane_id, bridge_id), expected_error: Option| { + Bridges::::insert(id, bridge); + LaneToBridge::::insert(lane_id, bridge_id); + + let result = XcmOverBridge::do_try_state(); + if let Some(e) = expected_error { + assert_err!(XcmOverBridge::do_try_state(), e); + } else { + assert_ok!(result); + } + }; + + run_test(|| { + // ok state + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + reserve: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + None, + ); + }); + } } diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs index cd085096f1b6..60c25381ed89 100644 --- a/bridges/primitives/messages/src/lane.rs +++ b/bridges/primitives/messages/src/lane.rs @@ -26,8 +26,8 @@ use sp_io::hashing::blake2_256; /// Bridge lane identifier. /// /// Lane connects two endpoints at both sides of the bridge. We assume that every endpoint -/// has its own unique identifier. We want lane identifiers to be the same on the both sides -/// of the bridge (and naturally unique across global consensus if endpoints have unique +/// has its own unique identifier. We want lane identifiers to be **the same on the both sides +/// of the bridge** (and naturally unique across global consensus if endpoints have unique /// identifiers). So lane id is the hash (`blake2_256`) of **ordered** encoded locations /// concatenation (separated by some binary data). I.e.: /// diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 9949108af21f..9dc7403fb966 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -21,6 +21,8 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Dependencies sp-std = { workspace = true } +sp-io = { workspace = true } +sp-core = { workspace = true } frame-support = { workspace = true } # Polkadot Dependencies @@ -35,6 +37,8 @@ std = [ "frame-support/std", "scale-info/std", "serde/std", + "sp-core/std", + "sp-io/std", "sp-std/std", "xcm/std", ] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index ba2ef20fd14f..3d7058d3480a 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -28,14 +28,29 @@ use frame_support::{ }; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; +use sp_core::H256; +use sp_io::hashing::blake2_256; use sp_std::boxed::Box; -use xcm::{latest::prelude::*, VersionedInteriorLocation, VersionedLocation}; +use xcm::{ + latest::prelude::*, prelude::XcmVersion, IntoVersion, VersionedInteriorLocation, + VersionedLocation, +}; /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; -/// Bridge identifier. +/// Bridge identifier - used **only** for communicating with sibling/parent chains in the same +/// consensus. +/// +/// For example, `SendXcm` implementations (which use the `latest` XCM) can use it to identify a +/// bridge and the corresponding `LaneId` that is used for over-consensus communication between +/// bridge hubs. +/// +/// This identifier is constructed from the `latest` XCM, so it is expected to ensure migration to +/// the `latest` XCM version. This could change the `BridgeId`, but it will not affect the `LaneId`. +/// In other words, `LaneId` will never change, while `BridgeId` could change with (every) XCM +/// upgrade. #[derive( Clone, Copy, @@ -51,47 +66,28 @@ pub type XcmAsPlainPayload = sp_std::vec::Vec; Serialize, Deserialize, )] -pub struct BridgeId(LaneId); +pub struct BridgeId(H256); impl BridgeId { /// Create bridge identifier from two universal locations. /// - /// The fact that we are using versioned locations here means that XCM version upgrades must - /// be coordinated at all involved chains (at source and target chains + at bridge hubs). - /// Otherwise, messages may simply be dropped anywhere on its path to the target chain. - pub fn new( - universal_location1: &VersionedInteriorLocation, - universal_location2: &VersionedInteriorLocation, - ) -> Self { - // a tricky helper struct that adds required `Ord` support for - // `VersionedInteriorMultiLocation` - #[derive(Eq, PartialEq, Ord, PartialOrd)] - struct EncodedVersionedInteriorMultiLocation(sp_std::vec::Vec); - - impl Encode for EncodedVersionedInteriorMultiLocation { - fn encode(&self) -> sp_std::vec::Vec { - self.0.clone() - } - } - - Self(LaneId::new( - EncodedVersionedInteriorMultiLocation(universal_location1.encode()), - EncodedVersionedInteriorMultiLocation(universal_location2.encode()), - )) - } - - /// Creates bridge id using lane id. - /// - /// **ATTENTION**: this function may be removed in the future. - pub fn from_lane_id(lane_id: LaneId) -> Self { - // in the future we may want to keep using the same lane identifiers if we'll be upgrading - // the XCM version (and `VersionedInteriorMultiLocation` will change) - Self(lane_id) + /// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure + /// compatibility with newer XCM versions. + fn new(universal_source: &InteriorLocation, universal_destination: &InteriorLocation) -> Self { + const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator"; + + BridgeId( + (universal_source, VALUES_SEPARATOR, universal_destination) + .using_encoded(blake2_256) + .into(), + ) } - /// Return lane id, used by this bridge. - pub fn lane_id(&self) -> LaneId { - self.0 + /// Create bridge identifier from given hash. + /// (for testing purposes) + #[cfg(any(feature = "std", test))] + pub const fn from_inner(inner: H256) -> Self { + BridgeId(inner) } } @@ -160,23 +156,26 @@ pub struct Bridge { pub bridge_origin_relative_location: Box, /// Current bridge state. pub state: BridgeState, - /// Account with the reserved funds. + /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. pub bridge_owner_account: AccountIdOf, /// Reserved amount on the sovereign account of the sibling bridge origin. pub reserve: BalanceOf, + + /// Mapping to the unique `LaneId`. + pub lane_id: LaneId, } /// Locations of bridge endpoints at both sides of the bridge. #[derive(Clone, RuntimeDebug, PartialEq, Eq)] pub struct BridgeLocations { /// Relative (to this bridge hub) location of this side of the bridge. - pub bridge_origin_relative_location: Location, + bridge_origin_relative_location: Location, /// Universal (unique) location of this side of the bridge. - pub bridge_origin_universal_location: InteriorLocation, + bridge_origin_universal_location: InteriorLocation, /// Universal (unique) location of other side of the bridge. - pub bridge_destination_universal_location: InteriorLocation, + bridge_destination_universal_location: InteriorLocation, /// An identifier of the dedicated bridge message lane. - pub bridge_id: BridgeId, + bridge_id: BridgeId, } /// Errors that may happen when we check bridge locations. @@ -195,6 +194,8 @@ pub enum BridgeLocationsError { /// Destination location is unsupported. We only support bridges with relay /// chain or its parachains. UnsupportedDestinationLocation, + /// The version of XCM location argument is unsupported. + UnsupportedXcmVersion, } /// Given XCM locations, generate lane id and universal locations of bridge endpoints. @@ -271,10 +272,8 @@ pub fn bridge_locations( // `GlobalConsensus` and we know that the `bridge_origin_universal_location` // is also within the `GlobalConsensus`. So we know that the lane id will be // the same on both ends of the bridge - let bridge_id = BridgeId::new( - &bridge_origin_universal_location.clone().into(), - &bridge_destination_universal_location.clone().into(), - ); + let bridge_id = + BridgeId::new(&bridge_origin_universal_location, &bridge_destination_universal_location); Ok(Box::new(BridgeLocations { bridge_origin_relative_location: *bridge_origin_relative_location, @@ -284,6 +283,60 @@ pub fn bridge_locations( })) } +impl BridgeLocations { + /// Getter for `bridge_origin_relative_location` + pub fn bridge_origin_relative_location(&self) -> &Location { + &self.bridge_origin_relative_location + } + + /// Getter for `bridge_origin_universal_location` + pub fn bridge_origin_universal_location(&self) -> &InteriorLocation { + &self.bridge_origin_universal_location + } + + /// Getter for `bridge_destination_universal_location` + pub fn bridge_destination_universal_location(&self) -> &InteriorLocation { + &self.bridge_destination_universal_location + } + + /// Getter for `bridge_id` + pub fn bridge_id(&self) -> &BridgeId { + &self.bridge_id + } + + /// Generates the exact same `LaneId` on the both bridge hubs. + /// + /// Note: Use this **only** when opening a new bridge. + pub fn calculate_lane_id( + &self, + xcm_version: XcmVersion, + ) -> Result { + // a tricky helper struct that adds required `Ord` support for + // `VersionedInteriorLocation` + #[derive(Eq, PartialEq, Ord, PartialOrd)] + struct EncodedVersionedInteriorLocation(sp_std::vec::Vec); + impl Encode for EncodedVersionedInteriorLocation { + fn encode(&self) -> sp_std::vec::Vec { + self.0.clone() + } + } + + let universal_location1 = + VersionedInteriorLocation::from(self.bridge_origin_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + let universal_location2 = + VersionedInteriorLocation::from(self.bridge_destination_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + + Ok(LaneId::new( + EncodedVersionedInteriorLocation(universal_location1.encode()), + EncodedVersionedInteriorLocation(universal_location2.encode()), + )) + } +} + #[cfg(test)] mod tests { use super::*; @@ -301,6 +354,8 @@ mod tests { bridge_origin_universal_location: InteriorLocation, bridge_destination_universal_location: InteriorLocation, + + expected_remote_network: NetworkId, } fn run_successful_test(test: SuccessfulTest) -> BridgeLocations { @@ -308,7 +363,7 @@ mod tests { Box::new(test.here_universal_location), Box::new(test.bridge_origin_relative_location.clone()), Box::new(test.bridge_destination_universal_location.clone()), - REMOTE_NETWORK, + test.expected_remote_network, ); assert_eq!( locations, @@ -338,6 +393,8 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -353,6 +410,8 @@ mod tests { ] .into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -368,6 +427,8 @@ mod tests { Parachain(REMOTE_PARACHAIN), ] .into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -387,6 +448,8 @@ mod tests { Parachain(REMOTE_PARACHAIN), ] .into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -399,6 +462,8 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -416,6 +481,8 @@ mod tests { ] .into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -432,6 +499,8 @@ mod tests { Parachain(REMOTE_PARACHAIN), ] .into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -453,6 +522,8 @@ mod tests { Parachain(REMOTE_PARACHAIN), ] .into(), + + expected_remote_network: REMOTE_NETWORK, }); } @@ -466,6 +537,8 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); let locations2 = run_successful_test(SuccessfulTest { here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), @@ -473,6 +546,8 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); assert_eq!(locations1.bridge_id, locations2.bridge_id); @@ -486,6 +561,8 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); let locations2 = run_successful_test(SuccessfulTest { here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), @@ -493,11 +570,65 @@ mod tests { bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, }); assert_eq!(locations1.bridge_id, locations2.bridge_id); } + #[test] + fn calculate_lane_id_works() { + let from_local_to_remote = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + let from_remote_to_local = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(REMOTE_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(REMOTE_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + + expected_remote_network: LOCAL_NETWORK, + }); + + assert_ne!( + from_local_to_remote.calculate_lane_id(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id(xcm::latest::VERSION - 1), + ); + assert_eq!( + from_local_to_remote.calculate_lane_id(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id(xcm::latest::VERSION), + ); + } + // negative tests #[test] From a3554f709553643bac29c7469f8a4bcce4e18307 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 29 Jul 2024 22:38:21 +0200 Subject: [PATCH 33/95] More fixes and `do_try_state_for_bridge` --- .../modules/xcm-bridge-hub/src/dispatcher.rs | 38 ++-- bridges/modules/xcm-bridge-hub/src/lib.rs | 162 +++++++++++++++++- bridges/modules/xcm-bridge-hub/src/mock.rs | 1 + bridges/primitives/xcm-bridge-hub/src/lib.rs | 27 +-- 4 files changed, 203 insertions(+), 25 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index b6f6ed760653..e094451ab7bb 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -124,27 +124,45 @@ mod tests { use crate::{mock::*, Bridges, LaneToBridge}; use bp_messages::{target_chain::DispatchMessageData, MessageKey}; - use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; - use sp_core::H256; - - fn bridge() -> (BridgeId, LaneId) { - (BridgeId::from_inner(H256::from([1u8; 32])), LaneId::new(1, 2)) + use xcm_executor::traits::ConvertLocation; + + fn bridge() -> (Box, LaneId) { + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let with = bridged_asset_hub_universal_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + (locations, lane_id) } fn run_test_with_opened_bridge(test: impl FnOnce()) { run_test(|| { + let (bridge, lane_id) = bridge(); + Bridges::::insert( - bridge().0, + bridge.bridge_id(), Bridge { - bridge_origin_relative_location: Box::new(Location::new(0, Here).into()), + bridge_origin_relative_location: Box::new( + bridge.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + bridge.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + bridge.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, - bridge_owner_account: [0u8; 32].into(), + bridge_owner_account: LocationToAccountId::convert_location( + bridge.bridge_origin_relative_location(), + ) + .expect("valid accountId"), reserve: 0, - lane_id: bridge().1, + lane_id, }, ); - LaneToBridge::::insert(bridge().1, bridge().0); + LaneToBridge::::insert(lane_id, bridge.bridge_id()); assert_ok!(XcmOverBridge::do_try_state()); test(); diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 722104818bb0..09e95edf5fd0 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -226,6 +226,12 @@ pub mod pallet { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location().clone().into(), ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account, reserve: deposit, @@ -524,6 +530,35 @@ pub mod pallet { bridge_id: BridgeId, bridge: BridgeOf, ) -> Result { + // check `BridgeId` points to the same `LaneId` and vice versa. + ensure!( + Some(bridge_id) == Self::lane_to_bridge(bridge.lane_id), + "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!" + ); + + // check that `locations` are convertible to the `latest` XCM. + let bridge_origin_relative_location_as_latest: &Location = + bridge.bridge_origin_relative_location.try_as().map_err(|_| { + "`bridge.bridge_origin_relative_location` cannot be converted to the `latest` XCM, needs migration!" + })?; + let bridge_origin_universal_location_as_latest: &InteriorLocation = bridge.bridge_origin_universal_location + .try_as() + .map_err(|_| "`bridge.bridge_origin_universal_location` cannot be converted to the `latest` XCM, needs migration!")?; + let bridge_destination_universal_location_as_latest: &InteriorLocation = bridge.bridge_destination_universal_location + .try_as() + .map_err(|_| "`bridge.bridge_destination_universal_location` cannot be converted to the `latest` XCM, needs migration!")?; + + // check `BridgeId` does not change + ensure!( + bridge_id == BridgeId::new(bridge_origin_universal_location_as_latest, bridge_destination_universal_location_as_latest), + "`bridge_id` is different than calculated from `bridge_origin_universal_location_as_latest` and `bridge_destination_universal_location_as_latest`, needs migration!" + ); + + // check bridge account owner + ensure!( + T::BridgeOriginAccountIdConverter::convert_location(bridge_origin_relative_location_as_latest) == Some(bridge.bridge_owner_account), + "`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!" + ); Ok(bridge.lane_id) } @@ -580,6 +615,12 @@ pub mod pallet { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location().clone().into(), ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account, reserve: Zero::zero(), @@ -699,6 +740,12 @@ mod tests { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location().clone().into(), ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account, reserve, @@ -852,6 +899,12 @@ mod tests { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location().clone().into(), ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, @@ -977,6 +1030,12 @@ mod tests { bridge_origin_relative_location: Box::new( locations.bridge_origin_relative_location().clone().into() ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), reserve: expected_reserve, @@ -1254,12 +1313,19 @@ mod tests { fn do_try_state_works() { use sp_runtime::Either; - let older_xcm_version = xcm::latest::VERSION - 1; - let bridge_origin_relative_location = Location::new(1, [Parachain(2025)]); + let bridge_origin_relative_location = SiblingLocation::get(); + let bridge_origin_universal_location = SiblingUniversalLocation::get(); + let bridge_destination_universal_location = BridgedUniversalDestination::get(); let bridge_owner_account = LocationToAccountId::convert_location(&bridge_origin_relative_location) .expect("valid accountId"); - let bridge_id = BridgeId::from_inner(H256::from([1u8; 32])); + let bridge_owner_account_mismatch = + LocationToAccountId::convert_location(&Location::parent()).expect("valid accountId"); + let bridge_id = BridgeId::new( + &bridge_origin_universal_location, + &bridge_destination_universal_location, + ); + let bridge_id_mismatch = BridgeId::new(&InteriorLocation::Here, &InteriorLocation::Here); let lane_id = LaneId::from_inner(Either::Left(H256::default())); let test_bridge_state = @@ -1269,11 +1335,16 @@ mod tests { let result = XcmOverBridge::do_try_state(); if let Some(e) = expected_error { - assert_err!(XcmOverBridge::do_try_state(), e); + assert_err!(result, e); } else { assert_ok!(result); } }; + let cleanup = |bridge_id, lane_id| { + Bridges::::remove(bridge_id); + LaneToBridge::::remove(lane_id); + assert_ok!(XcmOverBridge::do_try_state()); + }; run_test(|| { // ok state @@ -1283,6 +1354,14 @@ mod tests { bridge_origin_relative_location: Box::new(VersionedLocation::from( bridge_origin_relative_location.clone(), )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), reserve: Zero::zero(), @@ -1291,6 +1370,81 @@ mod tests { (lane_id, bridge_id), None, ); + cleanup(bridge_id, lane_id); + + // error - missing `LaneToBridge` mapping + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + reserve: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id_mismatch), + Some(TryRuntimeError::Other( + "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!", + )), + ); + cleanup(bridge_id, lane_id); + + // error bridge owner account cannot be calculated + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + )), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account_mismatch.clone(), + reserve: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + Some(TryRuntimeError::Other("`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!")), + ); + cleanup(bridge_id, lane_id); + + // error when (bridge_origin_universal_location + bridge_destination_universal_location) + // produces different `BridgeId` + test_bridge_state( + bridge_id_mismatch, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + )), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account_mismatch.clone(), + reserve: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id_mismatch), + Some(TryRuntimeError::Other("`bridge_id` is different than calculated from `bridge_origin_universal_location_as_latest` and `bridge_destination_universal_location_as_latest`, needs migration!")), + ); + cleanup(bridge_id_mismatch, lane_id); }); } } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 39b93130e96f..6ea4eb0c846c 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -150,6 +150,7 @@ parameter_types! { Parachain(THIS_BRIDGE_HUB_ID), ].into(); pub SiblingLocation: Location = Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]); + pub SiblingUniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into(); pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; pub BridgedRelayNetworkLocation: Location = (Parent, GlobalConsensus(BridgedRelayNetwork::get())).into(); diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 3d7058d3480a..1f599a2ad0e2 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -73,7 +73,10 @@ impl BridgeId { /// /// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure /// compatibility with newer XCM versions. - fn new(universal_source: &InteriorLocation, universal_destination: &InteriorLocation) -> Self { + pub fn new( + universal_source: &InteriorLocation, + universal_destination: &InteriorLocation, + ) -> Self { const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator"; BridgeId( @@ -82,13 +85,6 @@ impl BridgeId { .into(), ) } - - /// Create bridge identifier from given hash. - /// (for testing purposes) - #[cfg(any(feature = "std", test))] - pub const fn from_inner(inner: H256) -> Self { - BridgeId(inner) - } } /// Local XCM channel manager. @@ -152,8 +148,17 @@ pub enum BridgeState { )] #[scale_info(skip_type_params(ThisChain))] pub struct Bridge { - /// Relative location of the bridge origin chain. + /// Relative location of the bridge origin chain. This is expected to be **convertible** to the + /// `latest` XCM, so the check and migration needs to be ensured. pub bridge_origin_relative_location: Box, + + /// See [`BridgeLocations::bridge_origin_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_origin_universal_location: Box, + /// See [`BridgeLocations::bridge_destination_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_destination_universal_location: Box, + /// Current bridge state. pub state: BridgeState, /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. @@ -374,8 +379,8 @@ mod tests { .bridge_destination_universal_location .clone(), bridge_id: BridgeId::new( - &test.bridge_origin_universal_location.into(), - &test.bridge_destination_universal_location.into(), + &test.bridge_origin_universal_location, + &test.bridge_destination_universal_location, ), })), ); From 0739367847dc9177da802c258a99dcb7e787ab89 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 29 Jul 2024 22:51:41 +0200 Subject: [PATCH 34/95] WIP: cleanup --- .../modules/xcm-bridge-hub/src/exporter.rs | 18 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 26 +-- bridges/primitives/xcm-bridge-hub/src/lib.rs | 211 +++++++++--------- 3 files changed, 132 insertions(+), 123 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 72d34790ebd4..ad12844a0f01 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -33,7 +33,6 @@ use frame_support::traits::Get; use pallet_bridge_messages::{ Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet, }; -use sp_std::boxed::Box; use xcm::prelude::*; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::ExportXcm; @@ -328,12 +327,12 @@ mod tests { use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; use bp_runtime::RangeInclusiveExt; - use bp_xcm_bridge_hub::{bridge_locations, Bridge, BridgeLocations, BridgeState}; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; - use xcm_executor::traits::export_xcm; + use xcm_executor::traits::{export_xcm, ConvertLocation}; fn universal_source() -> InteriorLocation { - [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into() + SiblingUniversalLocation::get() } fn bridged_relative_destination() -> InteriorLocation { @@ -365,8 +364,17 @@ mod tests { locations.bridge_id(), Bridge { bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, - bridge_owner_account: [0u8; 32].into(), + bridge_owner_account: LocationToAccountId::convert_location( + locations.bridge_origin_relative_location(), + ) + .expect("valid accountId"), reserve: 0, lane_id, }, diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 09e95edf5fd0..8de9398d8e20 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -54,8 +54,7 @@ use bp_messages::{LaneId, LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; use bp_xcm_bridge_hub::{ - bridge_locations, Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, - LocalXcmChannelManager, + Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, LocalXcmChannelManager, }; use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; @@ -452,22 +451,20 @@ pub mod pallet { bridge_destination_universal_location: Box, ) -> Result, sp_runtime::DispatchError> { Self::bridge_locations( - Box::new(T::OpenBridgeOrigin::ensure_origin(origin)?), - Box::new( - (*bridge_destination_universal_location) - .try_into() - .map_err(|_| Error::::UnsupportedXcmVersion)?, - ), + T::OpenBridgeOrigin::ensure_origin(origin)?, + (*bridge_destination_universal_location) + .try_into() + .map_err(|_| Error::::UnsupportedXcmVersion)?, ) } /// Return bridge endpoint locations and dedicated **bridge** identifier (`BridgeId`). pub fn bridge_locations( - bridge_origin_relative_location: Box, - bridge_destination_universal_location: Box, + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, ) -> Result, sp_runtime::DispatchError> { - bridge_locations( - Box::new(T::UniversalLocation::get()), + BridgeLocations::bridge_locations( + T::UniversalLocation::get(), bridge_origin_relative_location, bridge_destination_universal_location, Self::bridged_network_id()?, @@ -525,6 +522,7 @@ pub mod pallet { Ok(()) } + /// Ensure the correctness of the state of the bridge. pub fn do_try_state_for_bridge( bridge_id: BridgeId, @@ -598,8 +596,8 @@ pub mod pallet { &self.opened_bridges { let locations = Pallet::::bridge_locations( - Box::new(bridge_origin_relative_location.clone()), - Box::new(bridge_destination_universal_location.clone().into()), + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone().into(), ) .expect("Invalid genesis configuration"); let lane_id = diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 1f599a2ad0e2..50d112f824a0 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -203,92 +203,95 @@ pub enum BridgeLocationsError { UnsupportedXcmVersion, } -/// Given XCM locations, generate lane id and universal locations of bridge endpoints. -/// -/// The `here_universal_location` is the universal location of the bridge hub runtime. -/// -/// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`) -/// location of the bridge endpoint at this side of the bridge. It may be the parent relay -/// chain or the sibling parachain. All junctions below parachain level are dropped. -/// -/// The `bridge_destination_universal_location` is the universal location of the bridge -/// destination. It may be the parent relay or the sibling parachain of the **bridged** -/// bridge hub. All junctions below parachain level are dropped. -/// -/// Why we drop all junctions between parachain level - that's because the lane is a bridge -/// between two chains. All routing under this level happens when the message is delivered -/// to the bridge destination. So at bridge level we don't care about low level junctions. -/// -/// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location` -/// local consensus OR if `bridge_destination_universal_location` is not a universal location. -pub fn bridge_locations( - here_universal_location: Box, - bridge_origin_relative_location: Box, - bridge_destination_universal_location: Box, - expected_remote_network: NetworkId, -) -> Result, BridgeLocationsError> { - fn strip_low_level_junctions( - location: InteriorLocation, - ) -> Result { - let mut junctions = location.into_iter(); - - let global_consensus = junctions - .next() - .filter(|junction| matches!(junction, GlobalConsensus(_))) - .ok_or(BridgeLocationsError::NonUniversalLocation)?; - - // we only expect `Parachain` junction here. There are other junctions that - // may need to be supported (like `GeneralKey` and `OnlyChild`), but now we - // only support bridges with relay and parachans - // - // if there's something other than parachain, let's strip it - let maybe_parachain = junctions.next().filter(|junction| matches!(junction, Parachain(_))); - Ok(match maybe_parachain { - Some(parachain) => [global_consensus, parachain].into(), - None => [global_consensus].into(), - }) - } +impl BridgeLocations { + /// Given XCM locations, generate lane id and universal locations of bridge endpoints. + /// + /// The `here_universal_location` is the universal location of the bridge hub runtime. + /// + /// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`) + /// location of the bridge endpoint at this side of the bridge. It may be the parent relay + /// chain or the sibling parachain. All junctions below parachain level are dropped. + /// + /// The `bridge_destination_universal_location` is the universal location of the bridge + /// destination. It may be the parent relay or the sibling parachain of the **bridged** + /// bridge hub. All junctions below parachain level are dropped. + /// + /// Why we drop all junctions between parachain level - that's because the lane is a bridge + /// between two chains. All routing under this level happens when the message is delivered + /// to the bridge destination. So at bridge level we don't care about low level junctions. + /// + /// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location` + /// local consensus OR if `bridge_destination_universal_location` is not a universal location. + pub fn bridge_locations( + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, + expected_remote_network: NetworkId, + ) -> Result, BridgeLocationsError> { + fn strip_low_level_junctions( + location: InteriorLocation, + ) -> Result { + let mut junctions = location.into_iter(); + + let global_consensus = junctions + .next() + .filter(|junction| matches!(junction, GlobalConsensus(_))) + .ok_or(BridgeLocationsError::NonUniversalLocation)?; + + // we only expect `Parachain` junction here. There are other junctions that + // may need to be supported (like `GeneralKey` and `OnlyChild`), but now we + // only support bridges with relay and parachans + // + // if there's something other than parachain, let's strip it + let maybe_parachain = + junctions.next().filter(|junction| matches!(junction, Parachain(_))); + Ok(match maybe_parachain { + Some(parachain) => [global_consensus, parachain].into(), + None => [global_consensus].into(), + }) + } - // ensure that the `here_universal_location` and `bridge_destination_universal_location` - // are universal locations within different consensus systems - let local_network = here_universal_location - .global_consensus() - .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; - let remote_network = bridge_destination_universal_location - .global_consensus() - .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; - ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal); - ensure!( - remote_network == expected_remote_network, - BridgeLocationsError::UnreachableDestination - ); - - // get universal location of endpoint, located at this side of the bridge - let bridge_origin_universal_location = here_universal_location - .within_global(*bridge_origin_relative_location.clone()) - .map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?; - // strip low-level junctions within universal locations - let bridge_origin_universal_location = - strip_low_level_junctions(bridge_origin_universal_location)?; - let bridge_destination_universal_location = - strip_low_level_junctions(*bridge_destination_universal_location)?; - - // we know that the `bridge_destination_universal_location` starts from the - // `GlobalConsensus` and we know that the `bridge_origin_universal_location` - // is also within the `GlobalConsensus`. So we know that the lane id will be - // the same on both ends of the bridge - let bridge_id = - BridgeId::new(&bridge_origin_universal_location, &bridge_destination_universal_location); - - Ok(Box::new(BridgeLocations { - bridge_origin_relative_location: *bridge_origin_relative_location, - bridge_origin_universal_location, - bridge_destination_universal_location, - bridge_id, - })) -} + // ensure that the `here_universal_location` and `bridge_destination_universal_location` + // are universal locations within different consensus systems + let local_network = here_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + let remote_network = bridge_destination_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal); + ensure!( + remote_network == expected_remote_network, + BridgeLocationsError::UnreachableDestination + ); + + // get universal location of endpoint, located at this side of the bridge + let bridge_origin_universal_location = here_universal_location + .within_global(bridge_origin_relative_location.clone()) + .map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?; + // strip low-level junctions within universal locations + let bridge_origin_universal_location = + strip_low_level_junctions(bridge_origin_universal_location)?; + let bridge_destination_universal_location = + strip_low_level_junctions(bridge_destination_universal_location)?; + + // we know that the `bridge_destination_universal_location` starts from the + // `GlobalConsensus` and we know that the `bridge_origin_universal_location` + // is also within the `GlobalConsensus`. So we know that the lane id will be + // the same on both ends of the bridge + let bridge_id = BridgeId::new( + &bridge_origin_universal_location, + &bridge_destination_universal_location, + ); + + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + bridge_id, + })) + } -impl BridgeLocations { /// Getter for `bridge_origin_relative_location` pub fn bridge_origin_relative_location(&self) -> &Location { &self.bridge_origin_relative_location @@ -364,10 +367,10 @@ mod tests { } fn run_successful_test(test: SuccessfulTest) -> BridgeLocations { - let locations = bridge_locations( - Box::new(test.here_universal_location), - Box::new(test.bridge_origin_relative_location.clone()), - Box::new(test.bridge_destination_universal_location.clone()), + let locations = BridgeLocations::bridge_locations( + test.here_universal_location, + test.bridge_origin_relative_location.clone(), + test.bridge_destination_universal_location.clone(), test.expected_remote_network, ); assert_eq!( @@ -639,10 +642,10 @@ mod tests { #[test] fn bridge_locations_fails_when_here_is_not_universal_location() { assert_eq!( - bridge_locations( - Box::new([Parachain(1000)].into()), - Box::new(Here.into()), - Box::new([GlobalConsensus(REMOTE_NETWORK)].into()), + BridgeLocations::bridge_locations( + [Parachain(1000)].into(), + Here.into(), + [GlobalConsensus(REMOTE_NETWORK)].into(), REMOTE_NETWORK, ), Err(BridgeLocationsError::NonUniversalLocation), @@ -652,10 +655,10 @@ mod tests { #[test] fn bridge_locations_fails_when_computed_destination_is_not_universal_location() { assert_eq!( - bridge_locations( - Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), - Box::new(Here.into()), - Box::new([OnlyChild].into()), + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [OnlyChild].into(), REMOTE_NETWORK, ), Err(BridgeLocationsError::NonUniversalLocation), @@ -665,10 +668,10 @@ mod tests { #[test] fn bridge_locations_fails_when_computed_destination_is_local() { assert_eq!( - bridge_locations( - Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), - Box::new(Here.into()), - Box::new([GlobalConsensus(LOCAL_NETWORK), OnlyChild].into()), + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(LOCAL_NETWORK), OnlyChild].into(), REMOTE_NETWORK, ), Err(BridgeLocationsError::DestinationIsLocal), @@ -678,10 +681,10 @@ mod tests { #[test] fn bridge_locations_fails_when_computed_destination_is_unreachable() { assert_eq!( - bridge_locations( - Box::new([GlobalConsensus(LOCAL_NETWORK)].into()), - Box::new(Here.into()), - Box::new([GlobalConsensus(UNREACHABLE_NETWORK)].into()), + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(UNREACHABLE_NETWORK)].into(), REMOTE_NETWORK, ), Err(BridgeLocationsError::UnreachableDestination), From bb91688dde1c568dde97ccd5fb42656e8d6cbc1f Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 09:37:51 +0200 Subject: [PATCH 35/95] WIP: fix runtime tests --- bridges/modules/xcm-bridge-hub/src/lib.rs | 27 +----- .../bridge-hub-rococo/tests/tests.rs | 28 +++--- .../bridge-hub-westend/tests/tests.rs | 14 +-- .../test-utils/src/test_cases/helpers.rs | 90 +++++++++++++++++-- .../test-utils/src/test_cases/mod.rs | 62 +++++++++---- 5 files changed, 151 insertions(+), 70 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 8de9398d8e20..81cfc21acf7f 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -415,31 +415,6 @@ pub mod pallet { Ok(()) } - - /// TODO:(bridges-v2) - FAIL-CI - add docs/tests/benchmarks - #[pallet::call_index(2)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI - pub fn force_open_bridge( - origin: OriginFor, - _bridge_origin_universal_location: Box, - _bridge_destination_universal_location: Box, - ) -> DispatchResult { - T::AdminOrigin::ensure_origin(origin)?; - todo!() - } - - /// TODO:(bridges-v2) - FAIL-CI - add docs/tests/benchmarks - #[pallet::call_index(3)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI - pub fn force_close_bridge( - origin: OriginFor, - _bridge_origin_universal_location: Box, - _bridge_destination_universal_location: Box, - _may_prune_messages: MessageNonce, - ) -> DispatchResult { - T::AdminOrigin::ensure_origin(origin)?; - todo!() - } } impl, I: 'static> Pallet { @@ -498,7 +473,7 @@ pub mod pallet { } } - #[cfg(any(feature = "try-runtime", test))] + #[cfg(any(test, feature = "try-runtime", feature = "std"))] impl, I: 'static> Pallet { /// Ensure the correctness of the state of this pallet. pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index c6cf60ef8bd7..17b2f5e999db 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -331,9 +331,8 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + TokenLocation, + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()).1 }, ) } @@ -387,9 +386,9 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, + TokenLocation, >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -411,9 +410,9 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, + TokenLocation, >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -484,6 +483,7 @@ mod bridge_hub_westend_tests { Runtime, XcmOverBridgeHubWestendInstance, LocationToAccountId, + TokenLocation, >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, @@ -577,9 +577,8 @@ mod bridge_hub_bulletin_tests { Runtime, XcmOverPolkadotBulletinInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) - .bridge_id - .lane_id() + TokenLocation, + >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()).1 }, ) } @@ -632,9 +631,9 @@ mod bridge_hub_bulletin_tests { Runtime, XcmOverPolkadotBulletinInstance, LocationToAccountId, + TokenLocation, >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -655,9 +654,9 @@ mod bridge_hub_bulletin_tests { Runtime, XcmOverPolkadotBulletinInstance, LocationToAccountId, + TokenLocation, >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -669,6 +668,7 @@ mod bridge_hub_bulletin_tests { Runtime, XcmOverPolkadotBulletinInstance, LocationToAccountId, + TokenLocation, >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index e5f6ddfc87a7..bc8c923e9f5a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -230,9 +230,8 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + WestendLocation, + >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()).1 }, ) } @@ -284,9 +283,9 @@ fn relayed_incoming_message_works() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, + WestendLocation, >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -308,9 +307,9 @@ fn free_relay_extrinsic_works() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, + WestendLocation, >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) - .bridge_id - .lane_id() + .1 }, construct_and_apply_extrinsic, ) @@ -381,6 +380,7 @@ fn open_and_close_bridge_work() { Runtime, XcmOverBridgeHubRococoInstance, LocationToAccountId, + WestendLocation, >( collator_session_keys(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index a83ed8c08cc9..c343e9b3e09a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -388,23 +388,24 @@ fn execute_and_verify_calls( /// Helper function to open the bridge/lane for `source` and `destination` while ensuring all /// required balances are placed into the SA of the source. -pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation) -> BridgeLocations +pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation) -> (BridgeLocations, LaneId) where Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, XcmOverBridgePalletInstance: 'static, ::RuntimeCall: GetDispatchInfo + From>, ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, ::Balance: From, -LocationToAccountId: ConvertLocation>{ + LocationToAccountId: ConvertLocation>, +TokenLocation: Get{ // construct expected bridge configuration let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( source.clone().into(), - Box::new(destination.clone().into()), + destination.clone().into(), ) .expect("valid bridge locations"); assert!(pallet_xcm_bridge_hub::Bridges::::get( - locations.bridge_id + locations.bridge_id() ) .is_none()); @@ -414,7 +415,7 @@ LocationToAccountId: ConvertLocation>{ ); // random high enough value for `BuyExecution` fees let buy_execution_fee_amount = 5_000_000_000_000_u128; - let buy_execution_fee = (Location::parent(), buy_execution_fee_amount).into(); + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); let balance_needed = ::ExistentialDeposit::get() + buy_execution_fee_amount.into() + bridge_deposit.into(); @@ -439,11 +440,84 @@ LocationToAccountId: ConvertLocation>{ buy_execution_fee ) .ensure_complete()); + + let bridge = pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id(), + ) + .expect("opened bridge"); + + // check state + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_try_state() + ); + + // return locations + (*locations, bridge.lane_id) +} + +/// Helper function to close the bridge/lane for `source` and `destination`. +pub fn close_bridge(source: Location, destination: InteriorLocation) +where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, + LocationToAccountId: ConvertLocation>, +TokenLocation: Get{ + // construct expected bridge configuration + let locations = + pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + destination.clone().into(), + ) + .expect("valid bridge locations"); assert!(pallet_xcm_bridge_hub::Bridges::::get( - locations.bridge_id + locations.bridge_id() ) .is_some()); - // return locations - *locations + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 2_500_000_000_000_u128; + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into() + + bridge_deposit.into(); + + // SA of source location needs to have some required balance + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + + // close bridge with `Transact` call + let close_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< + Runtime, + XcmOverBridgePalletInstance, + >::close_bridge { + bridge_destination_universal_location: Box::new(destination.into()), + may_prune_messages: 16, + }); + + // execute XCM as source origin would do with `Transact -> Origin::Xcm` + assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + close_bridge_call, + source.clone(), + buy_execution_fee + ) + .ensure_complete()); + + // bridge is closed + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ) + .is_none()); + + // check state + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_try_state() + ); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index a9ad66646b54..e96e2bf0e036 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -654,7 +654,7 @@ where } /// Test-case makes sure that `Runtime` can open/close bridges. -pub fn open_and_close_bridge_work( +pub fn open_and_close_bridge_work( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, source: Location, @@ -667,28 +667,31 @@ pub fn open_and_close_bridge_work::Balance: From, <>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::AccountId: From<::AccountId>, LocationToAccountId: ConvertLocation>, + TokenLocation: Get, { run_test::(collator_session_key, runtime_para_id, vec![], || { // construct expected bridge configuration let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( source.clone().into(), - Box::new(destination.clone().into()), + destination.clone().into(), ).expect("valid bridge locations"); + let expected_lane_id = + locations.calculate_lane_id(xcm::latest::VERSION).expect("valid laneId"); let lanes_manager = LanesManagerOf::::new(); // check bridge/lane DOES not exist assert_eq!( pallet_xcm_bridge_hub::Bridges::::get( - locations.bridge_id + locations.bridge_id() ), None ); assert_eq!( - lanes_manager.active_inbound_lane(locations.bridge_id.lane_id()).map(drop), + lanes_manager.active_inbound_lane(expected_lane_id).map(drop), Err(LanesManagerError::UnknownInboundLane) ); assert_eq!( - lanes_manager.active_outbound_lane(locations.bridge_id.lane_id()).map(drop), + lanes_manager.active_outbound_lane(expected_lane_id).map(drop), Err(LanesManagerError::UnknownOutboundLane) ); @@ -698,19 +701,27 @@ pub fn open_and_close_bridge_work(source.clone(), destination,) - .bridge_id, - locations.bridge_id + TokenLocation, + >(source.clone(), destination.clone()) + .0 + .bridge_id(), + locations.bridge_id() ); // check bridge/lane DOES exist assert_eq!( pallet_xcm_bridge_hub::Bridges::::get( - locations.bridge_id + locations.bridge_id() ), Some( Bridge { bridge_origin_relative_location: Box::new(source.clone().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into() + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into() + ), state: BridgeState::Opened, bridge_owner_account: LocationToAccountId::convert_location(&source) .expect("valid location") @@ -718,20 +729,41 @@ pub fn open_and_close_bridge_work>::BridgeDeposit::get(), + lane_id: expected_lane_id } ) ); assert_eq!( - lanes_manager - .active_inbound_lane(locations.bridge_id.lane_id()) - .map(|lane| lane.state()), + lanes_manager.active_inbound_lane(expected_lane_id).map(|lane| lane.state()), Ok(LaneState::Opened) ); assert_eq!( - lanes_manager - .active_outbound_lane(locations.bridge_id.lane_id()) - .map(|lane| lane.state()), + lanes_manager.active_outbound_lane(expected_lane_id).map(|lane| lane.state()), Ok(LaneState::Opened) ); + + // close bridge with Transact call from sibling + helpers::close_bridge::< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + TokenLocation, + >(source.clone(), destination); + + // check bridge/lane DOES not exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ), + None + ); + assert_eq!( + lanes_manager.active_inbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); }); } From f1573d77d88819bb3e2f5eddf8e2e6a5c9819112 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 10:34:10 +0200 Subject: [PATCH 36/95] Finally, fixed `pallet_xcm_bridge_hub::exporter` and `ExportXcm` impl --- .../modules/xcm-bridge-hub/src/exporter.rs | 110 +++++++++++++----- 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index ad12844a0f01..38390113c43e 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -29,7 +29,7 @@ use bp_messages::{ LaneId, MessageNonce, }; use bp_xcm_bridge_hub::{BridgeId, BridgeState, LocalXcmChannelManager, XcmAsPlainPayload}; -use frame_support::traits::Get; +use frame_support::{ensure, traits::Get}; use pallet_bridge_messages::{ Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet, }; @@ -82,8 +82,37 @@ where // let's save them before let bridge_origin_universal_location = universal_source.clone().take().ok_or(SendError::MissingArgument)?; - let bridge_destination_universal_location = - destination.clone().take().ok_or(SendError::MissingArgument)?; + // Note: watch out this is `ExportMessage::destination`, which is relative to the `network`, + // which means it does not contain `GlobalConsensus`, We need to find `BridgeId` with + // `Self::bridge_locations` which requires **universal** location for destination. + let bridge_destination_universal_location = { + let dest = destination.clone().take().ok_or(SendError::MissingArgument)?; + match dest.global_consensus() { + Ok(dest_network) => { + log::trace!( + target: LOG_TARGET, + "Destination: {dest:?} is already universal, checking dest_network: {dest_network:?} and network: {network:?} if matches: {:?}", + dest_network == network + ); + ensure!(dest_network == network, SendError::Unroutable); + // ok, `dest` looks like a universal location, so let's use it + dest + }, + Err(_) => { + // `dest` is not a universal location, so we need to prepend it with + // `GlobalConsensus`. + dest.pushed_front_with(GlobalConsensus(network)).map_err(|error_data| { + log::error!( + target: LOG_TARGET, + "Destination: {:?} is not a universal and prepending with {:?} failed!", + error_data.0, + error_data.1, + ); + SendError::Unroutable + })? + }, + } + }; // check if we are able to route the message. We use existing `HaulBlobExporter` for that. // It will make all required changes and will encode message properly, so that the @@ -100,10 +129,10 @@ where let bridge_origin_relative_location = bridge_origin_universal_location.relative_to(&T::UniversalLocation::get()); - // then we are able to compute the lane id used to send messages + // then we are able to compute the `BridgeId` and find `LaneId` used to send messages let locations = Self::bridge_locations( - Box::new(bridge_origin_relative_location), - Box::new(bridge_destination_universal_location.into()), + bridge_origin_relative_location, + bridge_destination_universal_location.into(), ) .map_err(|e| { log::error!( @@ -116,7 +145,6 @@ where let bridge_message = MessagesPallet::::validate_message(bridge.lane_id, &blob) .map_err(|e| { - // TODO:(bridges-v2) - add test/std feature gate? FAIL-CI match e { Error::LanesManager(ref ei) => log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), @@ -329,6 +357,7 @@ mod tests { use bp_runtime::RangeInclusiveExt; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; + use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; use xcm_executor::traits::{export_xcm, ConvertLocation}; fn universal_source() -> InteriorLocation { @@ -540,40 +569,53 @@ mod tests { run_test(|| { assert_ne!(bridged_universal_destination(), bridged_relative_destination()); - // Note: The `BridgeId` is created from universal `InteriorLocation`. - let expected_bridge_id = - BridgeId::new(&universal_source().into(), &bridged_universal_destination().into()); + let locations = BridgeLocations::bridge_locations( + UniversalLocation::get(), + SiblingLocation::get(), + bridged_universal_destination(), + BridgedRelayNetwork::get(), + ) + .unwrap(); + let expected_bridge_id = locations.bridge_id(); + let expected_lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); if LanesManagerOf::::new() - .create_outbound_lane(expected_bridge_id.lane_id()) + .create_outbound_lane(expected_lane_id) .is_ok() { Bridges::::insert( expected_bridge_id, Bridge { - bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), reserve: 0, + lane_id: expected_lane_id, }, ); } - assert_eq!( - XcmOverBridge::validate( - BridgedRelayNetwork::get(), - 0, - &mut Some(universal_source()), - // Note: The `ExportMessage` expects relative `InteriorLocation` in the - // `BridgedRelayNetwork`. - &mut Some(bridged_relative_destination()), - &mut Some(Vec::new().into()), - ) - .unwrap() - .0 - .0, - expected_bridge_id - ); + let ticket = XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + // Note: The `ExportMessage` expects relative `InteriorLocation` in the + // `BridgedRelayNetwork`. + &mut Some(bridged_relative_destination()), + &mut Some(Vec::new().into()), + ) + .unwrap() + .0; + assert_eq!(&ticket.0, expected_bridge_id); + assert_eq!(ticket.1.lane_id, expected_lane_id); }); } @@ -597,9 +639,19 @@ mod tests { 0 ); + // send `ExportMessage(message)` by `UnpaidRemoteExporter`. + TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::< + UnpaidRemoteExporter< + NetworkExportTable, + TestExportXcmWithXcmOverBridge, + UniversalLocation, + >, + >(dest.clone(), Xcm::<()>::default())); + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); - assert_ok!(send_xcm::(dest, Xcm::<()>::default())); + assert_ok!(send_xcm::(dest.clone(), Xcm::<()>::default())); // check after - a message ready to be relayed assert_eq!( @@ -609,7 +661,7 @@ mod tests { .unwrap() .queued_messages() .saturating_len(), - 1 + 2 ); }) } From 681aec0c8d21bad267b7978fdd5b18bc091913c4 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 12:01:09 +0200 Subject: [PATCH 37/95] Add `AllowWithoutBridgeDeposit` feature --- bridges/modules/xcm-bridge-hub/src/lib.rs | 69 ++++++++++++++-------- bridges/modules/xcm-bridge-hub/src/mock.rs | 8 ++- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 81cfc21acf7f..077a5d36129e 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -80,7 +80,10 @@ pub const LOG_TARGET: &str = "runtime::bridge-xcm"; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::tokens::Precision}; + use frame_support::{ + pallet_prelude::*, + traits::{tokens::Precision, Contains}, + }; use frame_system::pallet_prelude::{BlockNumberFor, *}; /// The reason for this pallet placing a hold on funds. @@ -127,7 +130,7 @@ pub mod pallet { ::RuntimeOrigin, Success = Location, >; - /// A converter between a multi-location and a sovereign account. + /// A converter between a location and a sovereign account. type BridgeOriginAccountIdConverter: ConvertLocation>>; /// Amount of this chain native tokens that is reserved on the sibling parachain account @@ -142,6 +145,9 @@ pub mod pallet { >; /// The overarching runtime hold reason. type RuntimeHoldReason: From>; + /// Do not hold `Self::BridgeDeposit` for the location of `Self::OpenBridgeOrigin`. + /// For example, it is possible to make an exception for a system parachain or relay. + type AllowWithoutBridgeDeposit: Contains; /// Local XCM channel manager. type LocalXcmChannelManager: LocalXcmChannelManager; @@ -208,8 +214,14 @@ pub mod pallet { Error::::BridgeLocations(e) })?; - // reserve balance on the parachain sovereign account - let deposit = T::BridgeDeposit::get(); + // reserve balance on the origin's sovereign account + let deposit = if T::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location(), + ) { + BalanceOf::>::zero() + } else { + T::BridgeDeposit::get() + }; let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( locations.bridge_origin_relative_location(), ) @@ -269,7 +281,7 @@ pub mod pallet { // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { bridge_id: locations.bridge_id().clone(), - bridge_deposit: Some(deposit), + bridge_deposit: deposit, local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), remote_endpoint: Box::new( locations.bridge_destination_universal_location().clone(), @@ -393,7 +405,8 @@ pub mod pallet { ); e }) - .ok(); + .ok() + .unwrap_or(BalanceOf::>::zero()); // write something to log log::trace!( @@ -621,7 +634,7 @@ pub mod pallet { /// Bridge identifier. bridge_id: BridgeId, /// Amount of deposit held. - bridge_deposit: Option>>, + bridge_deposit: BalanceOf>, /// Universal location of local bridge endpoint. local_endpoint: Box, @@ -649,7 +662,7 @@ pub mod pallet { /// Lane identifier. lane_id: LaneId, /// Amount of deposit released. - bridge_deposit: Option>>, + bridge_deposit: BalanceOf>, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, }, @@ -699,15 +712,15 @@ mod tests { fn mock_open_bridge_from_with( origin: RuntimeOrigin, + deposit: Balance, with: InteriorLocation, ) -> (BridgeOf, BridgeLocations) { - let reserve = BridgeDeposit::get(); let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); let bridge_owner_account = - fund_origin_sovereign_account(&locations, reserve + ExistentialDeposit::get()); - Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, reserve).unwrap(); + fund_origin_sovereign_account(&locations, deposit + ExistentialDeposit::get()); + Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit).unwrap(); let bridge = Bridge { bridge_origin_relative_location: Box::new( @@ -721,7 +734,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account, - reserve, + reserve: deposit, lane_id, }; Bridges::::insert(locations.bridge_id(), bridge.clone()); @@ -738,8 +751,9 @@ mod tests { fn mock_open_bridge_from( origin: RuntimeOrigin, + deposit: Balance, ) -> (BridgeOf, BridgeLocations) { - mock_open_bridge_from_with(origin, bridged_asset_hub_universal_location()) + mock_open_bridge_from_with(origin, deposit, bridged_asset_hub_universal_location()) } fn enqueue_message(lane: LaneId) { @@ -941,15 +955,14 @@ mod tests { // in our test runtime, we expect that bridge may be opened by parent relay chain // and any sibling parachain let origins = [ - OpenBridgeOrigin::parent_relay_chain_origin(), - OpenBridgeOrigin::sibling_parachain_origin(), + (OpenBridgeOrigin::parent_relay_chain_origin(), 0), + (OpenBridgeOrigin::sibling_parachain_origin(), BridgeDeposit::get()), ]; // check that every origin may open the bridge let lanes_manager = LanesManagerOf::::new(); - let expected_reserve = BridgeDeposit::get(); let existential_deposit = ExistentialDeposit::get(); - for origin in origins { + for (origin, expected_deposit) in origins { // reset events System::set_block_number(1); System::reset_events(); @@ -982,11 +995,11 @@ mod tests { // give enough funds to the sovereign account of the bridge origin let bridge_owner_account = fund_origin_sovereign_account( &locations, - expected_reserve + existential_deposit, + expected_deposit + existential_deposit, ); assert_eq!( Balances::free_balance(&bridge_owner_account), - expected_reserve + existential_deposit + expected_deposit + existential_deposit ); assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); @@ -1011,7 +1024,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), - reserve: expected_reserve, + reserve: expected_deposit, lane_id }), ); @@ -1028,7 +1041,7 @@ mod tests { Some(locations.bridge_id().clone()) ); assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); - assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_reserve); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_deposit); // ensure that the proper event is deposited assert_eq!( @@ -1037,7 +1050,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { bridge_id: locations.bridge_id().clone(), - bridge_deposit: Some(BridgeDeposit::get()), + bridge_deposit: expected_deposit, local_endpoint: Box::new( locations.bridge_origin_universal_location().clone() ), @@ -1049,6 +1062,9 @@ mod tests { topics: vec![], }), ); + + // check state + assert_ok!(XcmOverBridge::do_try_state()); } }); } @@ -1098,7 +1114,7 @@ mod tests { fn close_bridge_fails_if_its_lanes_are_unknown() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let (bridge, locations) = mock_open_bridge_from(origin.clone()); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), 0); let lanes_manager = LanesManagerOf::::new(); lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().purge(); @@ -1112,7 +1128,7 @@ mod tests { ); lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); - let (_, locations) = mock_open_bridge_from(origin.clone()); + let (_, locations) = mock_open_bridge_from(origin.clone(), 0); lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); assert_noop!( XcmOverBridge::close_bridge( @@ -1129,7 +1145,8 @@ mod tests { fn close_bridge_works() { run_test(|| { let origin = OpenBridgeOrigin::parent_relay_chain_origin(); - let (bridge, locations) = mock_open_bridge_from(origin.clone()); + let expected_deposit = BridgeDeposit::get(); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), expected_deposit); System::set_block_number(1); // remember owner balances @@ -1273,7 +1290,7 @@ mod tests { event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { bridge_id: locations.bridge_id().clone(), lane_id: bridge.lane_id, - bridge_deposit: Some(BridgeDeposit::get()), + bridge_deposit: expected_deposit, pruned_messages: 8, }), topics: vec![], diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 6ea4eb0c846c..b4b26515295d 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -27,7 +27,7 @@ use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{EnsureOrigin, Everything, NeverEnsureOrigin, OriginTrait}, + traits::{EnsureOrigin, Equals, Everything, NeverEnsureOrigin, OriginTrait}, weights::RuntimeDbWeight, }; use polkadot_parachain_primitives::primitives::Sibling; @@ -197,6 +197,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; + type AllowWithoutBridgeDeposit = Equals; type LocalXcmChannelManager = TestLocalXcmChannelManager; @@ -315,6 +316,9 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, ); +parameter_types! { + pub ParentRelayChainLocation: Location = Location { parents: 1, interior: Here }; +} pub struct OpenBridgeOrigin; impl OpenBridgeOrigin { @@ -351,7 +355,7 @@ impl EnsureOrigin for OpenBridgeOrigin { fn try_origin(o: RuntimeOrigin) -> Result { let signer = o.clone().into_signer(); if signer == Self::parent_relay_chain_origin().into_signer() { - return Ok(Location { parents: 1, interior: Here }) + return Ok(ParentRelayChainLocation::get()) } else if signer == Self::parent_relay_chain_universal_origin().into_signer() { return Ok(Location { parents: 2, From 4f2beee9e4f8c5fe2e57b1847847e964e3a51bc6 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 12:29:55 +0200 Subject: [PATCH 38/95] Rename reserve to deposit + test cleanup --- .../modules/xcm-bridge-hub/src/dispatcher.rs | 2 +- .../modules/xcm-bridge-hub/src/exporter.rs | 4 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 20 ++--- bridges/primitives/xcm-bridge-hub/src/lib.rs | 2 +- .../src/bridge_to_bulletin_config.rs | 7 +- .../src/bridge_to_westend_config.rs | 7 +- .../bridge-hub-rococo/tests/tests.rs | 80 +++++++++++-------- .../src/bridge_to_rococo_config.rs | 7 +- .../bridge-hub-westend/tests/tests.rs | 31 ++++--- .../test-utils/src/test_cases/mod.rs | 50 +++++++----- 10 files changed, 126 insertions(+), 84 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index e094451ab7bb..db533cd41608 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -158,7 +158,7 @@ mod tests { bridge.bridge_origin_relative_location(), ) .expect("valid accountId"), - reserve: 0, + deposit: 0, lane_id, }, ); diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 38390113c43e..26bcd1cedf7e 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -404,7 +404,7 @@ mod tests { locations.bridge_origin_relative_location(), ) .expect("valid accountId"), - reserve: 0, + deposit: 0, lane_id, }, ); @@ -597,7 +597,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), - reserve: 0, + deposit: 0, lane_id: expected_lane_id, }, ); diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 077a5d36129e..0421c64b3d47 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -245,7 +245,7 @@ pub mod pallet { ), state: BridgeState::Opened, bridge_owner_account, - reserve: deposit, + deposit, lane_id, }); Ok(()) @@ -392,7 +392,7 @@ pub mod pallet { let released_deposit = T::Currency::release( &HoldReason::BridgeDeposit.into(), &bridge.bridge_owner_account, - bridge.reserve, + bridge.deposit, Precision::BestEffort, ) .map_err(|e| { @@ -609,7 +609,7 @@ pub mod pallet { ), state: BridgeState::Opened, bridge_owner_account, - reserve: Zero::zero(), + deposit: Zero::zero(), lane_id, }, ); @@ -734,7 +734,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account, - reserve: deposit, + deposit, lane_id, }; Bridges::::insert(locations.bridge_id(), bridge.clone()); @@ -894,7 +894,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: [0u8; 32].into(), - reserve: 0, + deposit: 0, lane_id, }, ); @@ -1024,7 +1024,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), - reserve: expected_deposit, + deposit: expected_deposit, lane_id }), ); @@ -1354,7 +1354,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), - reserve: Zero::zero(), + deposit: Zero::zero(), lane_id, }, (lane_id, bridge_id), @@ -1379,7 +1379,7 @@ mod tests { ), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account.clone(), - reserve: Zero::zero(), + deposit: Zero::zero(), lane_id, }, (lane_id, bridge_id_mismatch), @@ -1404,7 +1404,7 @@ mod tests { )), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account_mismatch.clone(), - reserve: Zero::zero(), + deposit: Zero::zero(), lane_id, }, (lane_id, bridge_id), @@ -1428,7 +1428,7 @@ mod tests { )), state: BridgeState::Opened, bridge_owner_account: bridge_owner_account_mismatch.clone(), - reserve: Zero::zero(), + deposit: Zero::zero(), lane_id, }, (lane_id, bridge_id_mismatch), diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 50d112f824a0..b2d5a51b95e3 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -164,7 +164,7 @@ pub struct Bridge { /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. pub bridge_owner_account: AccountIdOf, /// Reserved amount on the sovereign account of the sibling bridge origin. - pub reserve: BalanceOf, + pub deposit: BalanceOf, /// Mapping to the unique `LaneId`. pub lane_id: LaneId, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 672b2c847899..01ab1c040cbf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -37,7 +37,9 @@ use pallet_bridge_relayers::extension::{ }; use pallet_xcm::EnsureXcm; use pallet_xcm_bridge_hub::XcmAsPlainPayload; -use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, +}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ @@ -144,6 +146,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; type LocalXcmChannelManager = (); type BlobDispatcher = FromRococoBulletinMessageBlobDispatcher; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 42ba288b788c..81fb181cfd40 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -37,7 +37,9 @@ use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; use pallet_xcm::EnsureXcm; -use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, +}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ @@ -171,6 +173,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 17b2f5e999db..b5b187d3bd29 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -153,11 +153,14 @@ mod bridge_hub_westend_tests { // Random para id of sibling chain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = 2053; + // Random para id of sibling chain used in tests. + pub const SIBLING_SYSTEM_PARACHAIN_ID: u32 = 1008; // Random para id of bridged chain from different global consensus used in tests. pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; parameter_types! { pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub SiblingSystemParachainLocation: Location = Location::new(1, [Parachain(SIBLING_SYSTEM_PARACHAIN_ID)]); pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); } @@ -478,18 +481,22 @@ mod bridge_hub_westend_tests { } #[test] - fn open_and_close_bridge_work() { - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< - Runtime, - XcmOverBridgeHubWestendInstance, - LocationToAccountId, - TokenLocation, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SiblingParachainLocation::get(), - BridgedUniversalLocation::get(), - ) + fn open_and_close_bridge_works() { + let origins = [SiblingParachainLocation::get(), SiblingSystemParachainLocation::get()]; + + for origin in origins { + bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + TokenLocation, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + origin, + BridgedUniversalLocation::get(), + ) + } } } @@ -502,11 +509,12 @@ mod bridge_hub_bulletin_tests { WithRococoBulletinMessagesInstance, XcmOverPolkadotBulletinInstance, }; - // Para id of RococoPeople sibling parachain used in tests. - pub const SIBLING_PARACHAIN_ID: u32 = rococo_runtime_constants::system_parachain::PEOPLE_ID; + // Random para id of sibling chain used in tests. + pub const SIBLING_PEOPLE_PARACHAIN_ID: u32 = + rococo_runtime_constants::system_parachain::PEOPLE_ID; parameter_types! { - pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub SiblingPeopleParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PEOPLE_PARACHAIN_ID)]); pub BridgedBulletinLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); } @@ -555,7 +563,7 @@ mod bridge_hub_bulletin_tests { >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { Ok(RuntimeEvent::BridgePolkadotBulletinMessages(event)) => Some(event), @@ -578,7 +586,7 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()).1 + >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()).1 }, ) } @@ -599,7 +607,7 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), @@ -623,7 +631,7 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Rococo, || { // we need to create lane between RococoPeople and RococoBulletin @@ -632,7 +640,7 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) + >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()) .1 }, construct_and_apply_extrinsic, @@ -646,7 +654,7 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Rococo, || { // we need to create lane between RococoPeople and RococoBulletin @@ -655,7 +663,7 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedBulletinLocation::get()) + >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()) .1 }, construct_and_apply_extrinsic, @@ -663,17 +671,21 @@ mod bridge_hub_bulletin_tests { } #[test] - fn open_and_close_bridge_work() { - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< - Runtime, - XcmOverPolkadotBulletinInstance, - LocationToAccountId, - TokenLocation, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SiblingParachainLocation::get(), - BridgedBulletinLocation::get(), - ) + fn open_and_close_bridge_works() { + let origins = [SiblingPeopleParachainLocation::get()]; + + for origin in origins { + bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + TokenLocation, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + origin, + BridgedBulletinLocation::get(), + ) + } } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 2f211f8f38c1..bec868999e00 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -39,7 +39,9 @@ use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; use pallet_xcm::EnsureXcm; -use parachains_common::xcm_config::ParentRelayOrSiblingParachains; +use parachains_common::xcm_config::{ + AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, +}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ @@ -202,6 +204,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index bc8c923e9f5a..73a333368a19 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -45,11 +45,14 @@ use xcm::latest::prelude::*; // Random para id of sibling chain used in tests. pub const SIBLING_PARACHAIN_ID: u32 = 2053; +// Random para id of sibling chain used in tests. +pub const SIBLING_SYSTEM_PARACHAIN_ID: u32 = 1008; // Random para id of bridged chain from different global consensus used in tests. pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; parameter_types! { pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub SiblingSystemParachainLocation: Location = Location::new(1, [Parachain(SIBLING_SYSTEM_PARACHAIN_ID)]); pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); } @@ -375,16 +378,20 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { } #[test] -fn open_and_close_bridge_work() { - bridge_hub_test_utils::test_cases::open_and_close_bridge_work::< - Runtime, - XcmOverBridgeHubRococoInstance, - LocationToAccountId, - WestendLocation, - >( - collator_session_keys(), - bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - SiblingParachainLocation::get(), - BridgedUniversalLocation::get(), - ) +fn open_and_close_bridge_works() { + let origins = [SiblingParachainLocation::get(), SiblingSystemParachainLocation::get()]; + + for origin in origins { + bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + WestendLocation, + >( + collator_session_keys(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + origin, + BridgedUniversalLocation::get(), + ) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index e96e2bf0e036..de117982b26f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -37,7 +37,7 @@ use codec::Encode; use frame_support::{ assert_ok, dispatch::GetDispatchInfo, - traits::{Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{Contains, Get, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::AccountId; @@ -654,7 +654,7 @@ where } /// Test-case makes sure that `Runtime` can open/close bridges. -pub fn open_and_close_bridge_work( +pub fn open_and_close_bridge_works( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, source: Location, @@ -679,6 +679,18 @@ pub fn open_and_close_bridge_work::new(); + let expected_deposit = if >::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location() + ) { + Zero::zero() + } else { + >::BridgeDeposit::get() + }; + // check bridge/lane DOES not exist assert_eq!( pallet_xcm_bridge_hub::Bridges::::get( @@ -713,25 +725,21 @@ pub fn open_and_close_bridge_work::get( locations.bridge_id() ), - Some( - Bridge { - bridge_origin_relative_location: Box::new(source.clone().into()), - bridge_origin_universal_location: Box::new( - locations.bridge_origin_universal_location().clone().into() - ), - bridge_destination_universal_location: Box::new( - locations.bridge_destination_universal_location().clone().into() - ), - state: BridgeState::Opened, - bridge_owner_account: LocationToAccountId::convert_location(&source) - .expect("valid location") - .into(), - reserve: >::BridgeDeposit::get(), - lane_id: expected_lane_id - } - ) + Some(Bridge { + bridge_origin_relative_location: Box::new(source.clone().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into() + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into() + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location(&source) + .expect("valid location") + .into(), + deposit: expected_deposit, + lane_id: expected_lane_id + }) ); assert_eq!( lanes_manager.active_inbound_lane(expected_lane_id).map(|lane| lane.state()), From 32690b781a8367555b96f6d55bf0d6bedd57c737 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 13:19:47 +0200 Subject: [PATCH 39/95] Adjust AssetHubs --- Cargo.lock | 2 +- .../modules/xcm-bridge-hub-router/Cargo.toml | 2 - .../modules/xcm-bridge-hub-router/src/lib.rs | 4 +- .../modules/xcm-bridge-hub-router/src/mock.rs | 14 +-- bridges/modules/xcm-bridge-hub/src/mock.rs | 6 ++ .../xcm-bridge-hub-router/Cargo.toml | 5 +- .../xcm-bridge-hub-router/src/lib.rs | 5 +- cumulus/pallets/xcmp-queue/src/bridging.rs | 50 ++++++----- .../assets/asset-hub-rococo/src/lib.rs | 9 +- .../weights/pallet_xcm_bridge_hub_router.rs | 46 ---------- .../assets/asset-hub-rococo/src/xcm_config.rs | 11 --- .../assets/asset-hub-rococo/tests/tests.rs | 90 +------------------ .../assets/asset-hub-westend/src/lib.rs | 9 +- .../weights/pallet_xcm_bridge_hub_router.rs | 46 ---------- .../asset-hub-westend/src/xcm_config.rs | 11 --- .../assets/asset-hub-westend/tests/tests.rs | 88 +----------------- .../test-utils/src/test_cases_over_bridge.rs | 7 +- 17 files changed, 60 insertions(+), 345 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59025dd253f5..314afb5476f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2031,6 +2031,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", + "staging-xcm", ] [[package]] @@ -12039,7 +12040,6 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ - "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-benchmarking", "frame-support", diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 1cda8893967e..55824f6a7fe7 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -17,7 +17,6 @@ scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } # Bridge dependencies bp-xcm-bridge-hub-router = { workspace = true } -bp-xcm-bridge-hub = { workspace = true } # Substrate Dependencies frame-benchmarking = { optional = true, workspace = true } @@ -39,7 +38,6 @@ sp-std = { workspace = true, default-features = true } default = ["std"] std = [ "bp-xcm-bridge-hub-router/std", - "bp-xcm-bridge-hub/std", "codec/std", "frame-benchmarking/std", "frame-support/std", diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 5bad965ed7c3..2cf98fd180b8 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -30,7 +30,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use bp_xcm_bridge_hub::LocalXcmChannelManager; +pub use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::Encode; use frame_support::traits::Get; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; @@ -104,7 +104,7 @@ pub mod pallet { /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. type ToBridgeHubSender: SendXcm + InspectMessageQueues; /// Local XCM channel manager. - type LocalXcmChannelManager: LocalXcmChannelManager; + type LocalXcmChannelManager: XcmChannelStatusProvider; /// Additional fee that is paid for every byte of the outbound message. type ByteFee: Get; diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index e3a52879d856..6eab168698f6 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -18,7 +18,7 @@ use crate as pallet_xcm_bridge_hub_router; -use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; +use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::Encode; use frame_support::{ construct_runtime, derive_impl, parameter_types, @@ -160,22 +160,12 @@ impl TestLocalXcmChannelManager { } } -impl LocalXcmChannelManager for TestLocalXcmChannelManager { - type Error = (); - +impl XcmChannelStatusProvider for TestLocalXcmChannelManager { fn is_congested(with: &Location) -> bool { frame_support::storage::unhashed::get_or_default( &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], ) } - - fn suspend_bridge(_with: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - Ok(()) - } - - fn resume_bridge(_with: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - Ok(()) - } } /// Return test externalities to use in tests. diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index b4b26515295d..2b90c5fa77e8 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -423,6 +423,12 @@ impl LocalXcmChannelManager for TestLocalXcmChannelManager { } } +impl pallet_xcm_bridge_hub_router::XcmChannelStatusProvider for TestLocalXcmChannelManager { + fn is_congested(with: &Location) -> bool { + ::is_congested(with) + } +} + pub struct TestBlobDispatcher; impl TestBlobDispatcher { diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index c3cf3356184b..76857c62e925 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -18,6 +18,9 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } sp-runtime = { workspace = true } sp-core = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + [features] default = ["std"] -std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std"] +std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "xcm/std"] diff --git a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs index dbedb7a52c7f..89123b51ef2f 100644 --- a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs @@ -22,6 +22,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::H256; use sp_runtime::{FixedU128, RuntimeDebug}; +use xcm::latest::prelude::Location; /// Minimal delivery fee factor. pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); @@ -32,11 +33,11 @@ pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); /// of the bridge queues. pub trait XcmChannelStatusProvider { /// Returns true if the channel is currently congested. - fn is_congested() -> bool; + fn is_congested(with: &Location) -> bool; } impl XcmChannelStatusProvider for () { - fn is_congested() -> bool { + fn is_congested(_with: &Location) -> bool { false } } diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index eff4a37b0cef..8ed11505a27a 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -15,48 +15,52 @@ use crate::{pallet, OutboundState}; use cumulus_primitives_core::ParaId; -use frame_support::pallet_prelude::Get; +use xcm::latest::prelude::*; /// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks -/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `ParaId` if any of those is +/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `Location` if any of those is /// suspended. -pub struct InAndOutXcmpChannelStatusProvider( - core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, -); -impl, Runtime: crate::Config> - bp_xcm_bridge_hub_router::XcmChannelStatusProvider - for InAndOutXcmpChannelStatusProvider +pub struct InAndOutXcmpChannelStatusProvider(core::marker::PhantomData); +impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for InAndOutXcmpChannelStatusProvider { - fn is_congested() -> bool { + fn is_congested(with: &Location) -> bool { + // handle congestion only for a sibling parachain locations. + let sibling_para_id: ParaId = match with.unpack() { + (_, [Parachain(para_id)]) => (*para_id).into(), + _ => return false, + }; + // if the inbound channel with recipient is suspended, it means that we are unable to - // receive congestion reports from the bridge hub. So we assume the bridge pipeline is - // congested too - if pallet::Pallet::::is_inbound_channel_suspended(SiblingBridgeHubParaId::get()) { + // receive congestion reports from the `with` location. So we assume the pipeline is + // congested too. + if pallet::Pallet::::is_inbound_channel_suspended(sibling_para_id) { return true } // if the outbound channel with recipient is suspended, it means that one of further - // bridge queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall + // queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall // take larger fee for our outbound messages - OutXcmpChannelStatusProvider::::is_congested() + OutXcmpChannelStatusProvider::::is_congested(with) } } /// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks /// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. -pub struct OutXcmpChannelStatusProvider( - core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, -); -impl, Runtime: crate::Config> - bp_xcm_bridge_hub_router::XcmChannelStatusProvider - for OutXcmpChannelStatusProvider +pub struct OutXcmpChannelStatusProvider(core::marker::PhantomData); +impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for OutXcmpChannelStatusProvider { - fn is_congested() -> bool { - let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); + fn is_congested(with: &Location) -> bool { + // handle congestion only for a sibling parachain locations. + let sibling_para_id: ParaId = match with.unpack() { + (_, [Parachain(para_id)]) => (*para_id).into(), + _ => return false, + }; // let's find the channel's state with the sibling parachain, let Some((outbound_state, queued_pages)) = - pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) + pallet::Pallet::::outbound_channel_state(sibling_para_id) else { return false }; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 7414adacc448..c7d91366d512 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -912,9 +912,11 @@ impl pallet_nfts::Config for Runtime { /// consensus with dynamic fees and back-pressure. pub type ToWestendXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance3; impl pallet_xcm_bridge_hub_router::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; type UniversalLocation = xcm_config::UniversalLocation; + type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; @@ -930,11 +932,8 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim >; type ToBridgeHubSender = XcmpQueue; - type WithBridgeHubChannel = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< - xcm_config::bridging::SiblingBridgeHubParaId, - Runtime, - >; + type LocalXcmChannelManager = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 0a86037391b4..4a29ea81f5c1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -77,50 +77,4 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `150` - // Estimated: `1502` - // Minimum execution time: 9_959_000 picoseconds. - Weight::from_parts(10_372_000, 0) - .saturating_add(Weight::from_parts(0, 1502)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `6388` - // Minimum execution time: 45_888_000 picoseconds. - Weight::from_parts(47_022_000, 0) - .saturating_add(Weight::from_parts(0, 6388)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index a11dca4f6d7c..7b9d008fce9d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -610,17 +610,6 @@ pub mod bridging { /// Allow any asset native to the Westend ecosystem if it comes from Westend Asset Hub. pub type WestendAssetFromAssetHubWestend = matching::RemoteAssetFromLocation, AssetHubWestend>; - - impl Contains for ToWestendXcmRouter { - fn contains(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::ToWestendXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) - } - } } pub mod to_ethereum { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index ee1461b7f9c8..2026e387f6c0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -27,7 +27,7 @@ use asset_hub_rococo_runtime::{ AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + SessionKeys, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -1265,94 +1265,6 @@ mod asset_hub_rococo_tests { ) } - #[test] - fn report_bridge_status_from_xcm_bridge_router_for_westend_works() { - asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - LocationToAccountId, - ToWestendXcmRouterInstance, - >( - collator_session_keys(), - bridging_to_asset_hub_westend, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: false, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - ) - } - - #[test] - fn test_report_bridge_status_call_compatibility() { - // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding - assert_eq!( - RuntimeCall::ToWestendXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode(), - bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode() - ); - } - - #[test] - fn check_sane_weight_report_bridge_status_for_westend() { - use pallet_xcm_bridge_hub_router::WeightInfo; - let actual = >::WeightInfo::report_bridge_status(); - let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); - assert!( - actual.all_lte(max_weight), - "max_weight: {:?} should be adjusted to actual {:?}", - max_weight, - actual - ); - } - #[test] fn reserve_transfer_native_asset_to_non_teleport_para_works() { asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 62d3462038c8..44d39792fe03 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -901,9 +901,11 @@ impl pallet_nfts::Config for Runtime { /// consensus with dynamic fees and back-pressure. pub type ToRococoXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance1; impl pallet_xcm_bridge_hub_router::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; type UniversalLocation = xcm_config::UniversalLocation; + type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; @@ -919,11 +921,8 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime >; type ToBridgeHubSender = XcmpQueue; - type WithBridgeHubChannel = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< - xcm_config::bridging::SiblingBridgeHubParaId, - Runtime, - >; + type LocalXcmChannelManager = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 21d15c75af55..5326173691aa 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -77,50 +77,4 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `150` - // Estimated: `1502` - // Minimum execution time: 9_706_000 picoseconds. - Weight::from_parts(10_139_000, 0) - .saturating_add(Weight::from_parts(0, 1502)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `520` - // Estimated: `6460` - // Minimum execution time: 46_250_000 picoseconds. - Weight::from_parts(47_801_000, 0) - .saturating_add(Weight::from_parts(0, 6460)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 5ecfce18b6da..7a2ee6f13994 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -614,17 +614,6 @@ pub mod bridging { (StartsWith, StartsWith), AssetHubRococo, >; - - impl Contains for ToRococoXcmRouter { - fn contains(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::ToRococoXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) - } - } } /// Benchmarks helper for bridging configuration. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 48e6c11d268c..0bc660d6592b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -28,7 +28,7 @@ use asset_hub_westend_runtime::{ AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + TrustBackedAssetsInstance, XcmpQueue, }; pub use asset_hub_westend_runtime::{AssetConversion, AssetDeposit, CollatorSelection, System}; use asset_test_utils::{ @@ -1246,92 +1246,6 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic ) } -#[test] -fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { - asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - LocationToAccountId, - ToRococoXcmRouterInstance, - >( - collator_session_keys(), - bridging_to_asset_hub_rococo, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: false, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - ) -} - -#[test] -fn test_report_bridge_status_call_compatibility() { - // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding - assert_eq!( - RuntimeCall::ToRococoXcmRouter(pallet_xcm_bridge_hub_router::Call::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }) - .encode(), - bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode() - ) -} - -#[test] -fn check_sane_weight_report_bridge_status() { - use pallet_xcm_bridge_hub_router::WeightInfo; - let actual = >::WeightInfo::report_bridge_status(); - let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); - assert!( - actual.all_lte(max_weight), - "max_weight: {:?} should be adjusted to actual {:?}", - max_weight, - actual - ); -} - #[test] fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { asset_test_utils::test_cases::change_storage_constant_by_governance_works::< diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 7bc325f70546..cf6924014a75 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -545,7 +545,7 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< // execute xcm as XcmpQueue would do let outcome = XcmExecutor::::prepare_and_execute( - local_bridge_hub_location, + local_bridge_hub_location.clone(), xcm, &mut hash, RuntimeHelper::::xcm_max_weight( @@ -554,7 +554,10 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< Weight::zero(), ); assert_ok!(outcome.ensure_complete()); - assert_eq!(is_congested, pallet_xcm_bridge_hub_router::Pallet::::bridge().is_congested); + assert_eq!( + is_congested, + <>::LocalXcmChannelManager as pallet_xcm_bridge_hub_router::XcmChannelStatusProvider>::is_congested(&local_bridge_hub_location) + ); }; report_bridge_status(true); From 294523d613a15c33d6ea3eae3c779a8c541d5231 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 30 Jul 2024 16:02:39 +0200 Subject: [PATCH 40/95] More validations for LaneId --- bridges/bin/runtime-common/src/integrity.rs | 10 ++++----- bridges/modules/messages/src/lib.rs | 20 ----------------- bridges/primitives/messages/src/lane.rs | 25 ++++++++++++++++++++- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index c2c5b4e94ab2..2ff6c4c9165a 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -72,17 +72,17 @@ macro_rules! assert_bridge_messages_pallet_types( use $crate::integrity::__private::static_assertions::assert_type_eq_all; use bp_messages::ChainWithMessages; use bp_runtime::Chain; - use pallet_bridge_messages::Config as MessagesConfig; + use pallet_bridge_messages::Config as BridgeMessagesConfig; // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard // configuration is used), or something has broke existing configuration (meaning that all bridged chains // and relays will stop functioning) - assert_type_eq_all!(<$r as MessagesConfig<$i>>::ThisChain, $this); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::BridgedChain, $bridged); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::ThisChain, $this); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::BridgedChain, $bridged); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, XcmAsPlainPayload); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, XcmAsPlainPayload); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::OutboundPayload, XcmAsPlainPayload); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::InboundPayload, XcmAsPlainPayload); } } ); diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index b03fa14637a4..606d67d957da 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -519,26 +519,6 @@ pub mod pallet { QueryKind = OptionQuery, >; - // TODO:(bridges-v2) - do we still need this? FAIL-CI - /// Map of lane id => is congested signal sent. It is managed by the - /// `bridge_runtime_common::LocalXcmQueueManager`. - /// - /// **bridges-v1**: this map is a temporary hack and will be dropped in the `v2`. We can emulate - /// a storage map using `sp_io::unhashed` storage functions, but then benchmarks are not - /// accounting its `proof_size`, so it is missing from the final weights. So we need to make it - /// a map inside some pallet. We could use a simply value instead of map here, because - /// in `v1` we'll only have a single lane. But in the case of adding another lane before `v2`, - /// it'll be easier to deal with the isolated storage map instead. - #[pallet::storage] - pub type OutboundLanesCongestedSignals, I: 'static = ()> = StorageMap< - Hasher = Blake2_128Concat, - Key = LaneId, - Value = bool, - QueryKind = ValueQuery, - OnEmpty = GetDefault, - MaxValues = MaybeOutboundLanesCount, - >; - /// All queued outbound messages. #[pallet::storage] pub type OutboundMessages, I: 'static = ()> = diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs index 60c25381ed89..6d4ca402eb34 100644 --- a/bridges/primitives/messages/src/lane.rs +++ b/bridges/primitives/messages/src/lane.rs @@ -121,7 +121,7 @@ enum InnerLaneId { } impl Encode for InnerLaneId { - fn encode(&self) -> Vec { + fn encode(&self) -> sp_std::vec::Vec { match self { InnerLaneId::Array(array) => array.encode(), InnerLaneId::Hash(hash) => hash.encode(), @@ -216,6 +216,29 @@ mod tests { assert_eq!("00000001", hex::encode(LaneId(InnerLaneId::Array([0, 0, 0, 1])).as_ref()),); } + #[test] + fn lane_id_encode_decode_works() { + let test_encode_decode = |expected_hex, lane_id: LaneId| { + let enc = lane_id.encode(); + let decoded_lane_id = LaneId::decode(&mut &enc[..]).expect("decodable"); + assert_eq!(lane_id, decoded_lane_id); + + assert_eq!(expected_hex, hex::encode(lane_id.as_ref()),); + assert_eq!(expected_hex, hex::encode(decoded_lane_id.as_ref()),); + + let hex_bytes = hex::decode(expected_hex).expect("valid hex"); + let hex_decoded_lane_id = LaneId::decode(&mut &hex_bytes[..]).expect("decodable"); + assert_eq!(hex_decoded_lane_id, lane_id); + assert_eq!(hex_decoded_lane_id, decoded_lane_id); + }; + + test_encode_decode( + "0101010101010101010101010101010101010101010101010101010101010101", + LaneId(InnerLaneId::Hash(H256::from([1u8; 32]))), + ); + test_encode_decode("00000001", LaneId(InnerLaneId::Array([0, 0, 0, 1]))); + } + #[test] fn lane_id_is_generated_using_ordered_endpoints() { assert_eq!(LaneId::new(1, 2), LaneId::new(2, 1)); From d6e2136a071ac8e06b512061cf8449932486e01a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 00:13:07 +0200 Subject: [PATCH 41/95] Fixing integration tests + added stubs for open/close_bridge calls --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 314afb5476f3..59025dd253f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2031,7 +2031,6 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "staging-xcm", ] [[package]] @@ -12040,6 +12039,7 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ + "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-benchmarking", "frame-support", From 7a8098f60cdbd08a3244db4b33e266fe6893de82 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 00:23:29 +0200 Subject: [PATCH 42/95] zepter/taplo --- Cargo.lock | 2 -- bridges/bin/runtime-common/Cargo.toml | 16 ++++++---------- bridges/modules/messages/Cargo.toml | 5 +---- bridges/modules/relayers/Cargo.toml | 9 +++++++++ bridges/modules/xcm-bridge-hub/Cargo.toml | 5 +++++ bridges/primitives/messages/Cargo.toml | 2 +- bridges/primitives/polkadot-core/Cargo.toml | 4 +++- .../primitives/xcm-bridge-hub-router/Cargo.toml | 8 +++++++- bridges/relays/client-substrate/Cargo.toml | 8 ++++++-- .../assets/asset-hub-rococo/Cargo.toml | 3 +++ .../assets/asset-hub-westend/Cargo.toml | 3 +++ 11 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59025dd253f5..fa7d4a7ec8d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2365,7 +2365,6 @@ dependencies = [ "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", "frame-support", "frame-system", "log", @@ -2384,7 +2383,6 @@ dependencies = [ "sp-std 14.0.0", "sp-trie", "staging-xcm", - "staging-xcm-builder", "static_assertions", "tuplex", ] diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index c454ad9b5b1b..b8835d55f0da 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -25,7 +25,6 @@ bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } -bp-xcm-bridge-hub-router = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } pallet-bridge-parachains = { workspace = true } @@ -43,12 +42,14 @@ sp-trie = { optional = true, workspace = true } # Polkadot dependencies xcm = { workspace = true } -xcm-builder = { workspace = true } [dev-dependencies] bp-test-utils = { workspace = true } pallet-balances = { workspace = true } -pallet-bridge-messages = { features = ["std", "test-helpers"], workspace = true } +pallet-bridge-messages = { features = [ + "std", + "test-helpers", +], workspace = true } sp-core = { workspace = true } [features] @@ -61,7 +62,6 @@ std = [ "bp-relayers/std", "bp-runtime/std", "bp-test-utils/std", - "bp-xcm-bridge-hub-router/std", "bp-xcm-bridge-hub/std", "codec/std", "frame-support/std", @@ -75,12 +75,12 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "scale-info/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", "sp-trie/std", "tuplex/std", - "xcm-builder/std", "xcm/std", ] runtime-benchmarks = [ @@ -96,10 +96,6 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-trie", - "xcm-builder/runtime-benchmarks", ] integrity-test = ["static_assertions"] -test-helpers = [ - "bp-runtime/test-helpers", - "sp-trie", -] +test-helpers = ["bp-runtime/test-helpers", "sp-trie"] diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 33f524030d26..9df318587e38 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -73,7 +73,4 @@ try-runtime = [ "pallet-bridge-grandpa/try-runtime", "sp-runtime/try-runtime", ] -test-helpers = [ - "bp-runtime/test-helpers", - "sp-trie", -] +test-helpers = ["bp-runtime/test-helpers", "sp-trie"] diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index d98edb7dca08..0bf889bcca0e 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -49,8 +49,11 @@ default = ["std"] std = [ "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", + "bp-polkadot-core/std", "bp-relayers/std", "bp-runtime/std", + "bp-test-utils/std", "codec/std", "frame-benchmarking/std", "frame-support/std", @@ -60,8 +63,11 @@ std = [ "pallet-bridge-messages/std", "pallet-bridge-parachains/std", "pallet-transaction-payment/std", + "pallet-utility/std", "scale-info/std", "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", ] @@ -73,6 +79,7 @@ runtime-benchmarks = [ "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "pallet-bridge-parachains/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ @@ -82,6 +89,8 @@ try-runtime = [ "pallet-bridge-grandpa/try-runtime", "pallet-bridge-messages/try-runtime", "pallet-bridge-parachains/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", "sp-runtime/try-runtime", ] integrity-test = [] diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index a1c623cb0b38..7d00d7904713 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -44,6 +44,7 @@ polkadot-parachain-primitives = { workspace = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", "bp-runtime/std", "bp-xcm-bridge-hub/std", @@ -51,10 +52,13 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "pallet-bridge-messages/std", "pallet-xcm-bridge-hub-router/std", + "polkadot-parachain-primitives/std", "scale-info/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", "xcm-builder/std", @@ -67,6 +71,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "pallet-xcm-bridge-hub-router/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 29514ecccc25..271325b47355 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -41,5 +41,5 @@ std = [ "serde/std", "sp-core/std", "sp-io/std", - "sp-std/std" + "sp-std/std", ] diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index acae2f431bf2..366ee7aa948e 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -14,7 +14,9 @@ workspace = true codec = { features = ["derive"], workspace = true } parity-util-mem = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde = { optional = true, features = [ + "derive", +], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 76857c62e925..ba0c51152bd2 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -23,4 +23,10 @@ xcm = { workspace = true } [features] default = ["std"] -std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "xcm/std"] +std = [ + "codec/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "xcm/std", +] diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index 969cd73d6194..6065c23773e3 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -20,8 +20,12 @@ log = { workspace = true } num-traits = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } -tokio = { features = ["rt-multi-thread"], workspace = true, default-features = true } +scale-info = { features = [ + "derive", +], workspace = true, default-features = true } +tokio = { features = [ + "rt-multi-thread", +], workspace = true, default-features = true } thiserror = { workspace = true } quick_cache = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index 7bd91ae6774c..51ce5b180056 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -26,3 +26,6 @@ testnet-parachains-constants = { features = ["rococo"], workspace = true, defaul # Polkadot xcm = { workspace = true } + +# Bridges +bp-bridge-hub-rococo = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index 86d4ce3e7ac8..d32f98321706 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -26,3 +26,6 @@ testnet-parachains-constants = { features = ["westend"], workspace = true, defau # Polkadot xcm = { workspace = true } + +# Bridges +bp-bridge-hub-westend = { workspace = true } From 61bc9cc611d9c1f33d79993ebceac3dcc0fc51fe Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 00:40:25 +0200 Subject: [PATCH 43/95] Adjust base fee constants --- bridges/chains/chain-bridge-hub-rococo/src/lib.rs | 4 ++-- bridges/chains/chain-bridge-hub-westend/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index 73af997b9950..cf444a25f8bb 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -108,9 +108,9 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 314_037_860; + pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 316_520_502; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 57_414_813; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 59_941_787; } diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 17ff2c858a1d..e9455063cd02 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -97,9 +97,9 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 94_211_536_452; + pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 94_956_336_452; /// Transaction fee that is paid at the Westend BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_224_486_452; + pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_982_586_452; } From 4e1fec44189b82a51093d09363534180f5c56317 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 00:48:09 +0200 Subject: [PATCH 44/95] CI nits --- bridges/docs/polkadot-kusama-bridge-overview.md | 4 ++-- bridges/primitives/xcm-bridge-hub/Cargo.toml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bridges/docs/polkadot-kusama-bridge-overview.md b/bridges/docs/polkadot-kusama-bridge-overview.md index bd8e48285856..b1812e4caf12 100644 --- a/bridges/docs/polkadot-kusama-bridge-overview.md +++ b/bridges/docs/polkadot-kusama-bridge-overview.md @@ -99,8 +99,8 @@ Bridge Hub. The sovereign accounts are used as a source of funds when the relaye `pallet_bridge_relayers::claim_rewards`. Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. -Kusama Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign account -is not used to cover rewards of bridging with some other Polkadot Parachain. +Kusama Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. +The Kusama Asset Hub sovereign account is not used to cover rewards of bridging with some other Polkadot Parachain. ### Multiple Relayers and Rewards diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 9dc7403fb966..79201a8756f9 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -11,13 +11,13 @@ repository.workspace = true workspace = true [dependencies] -codec = { features = ["derive"], default-features = false, workspace = true } +codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge Dependencies -bp-messages = { path = "../messages", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies sp-std = { workspace = true } From 5e1be0b25b947c34df50742428c3c8a491881d96 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 01:02:04 +0200 Subject: [PATCH 45/95] CI clippy --- bridges/modules/xcm-bridge-hub/src/exporter.rs | 2 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 16 ++++++++-------- bridges/primitives/runtime/src/lib.rs | 2 +- bridges/primitives/runtime/src/storage_proof.rs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 26bcd1cedf7e..9625be0d07e2 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -166,7 +166,7 @@ where SendError::Transport("BridgeValidateError") })?; - Ok(((locations.bridge_id().clone(), bridge, bridge_message, id), price)) + Ok(((*locations.bridge_id(), bridge, bridge_message, id), price)) } fn deliver( diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 0421c64b3d47..cb41353e96bf 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -255,7 +255,7 @@ pub mod pallet { LaneToBridge::::try_mutate(lane_id, |bridge| match bridge { Some(_) => Err(Error::::BridgeAlreadyExists), None => { - *bridge = Some(locations.bridge_id().clone()); + *bridge = Some(*locations.bridge_id()); Ok(()) }, })?; @@ -280,7 +280,7 @@ pub mod pallet { // deposit `BridgeOpened` event Self::deposit_event(Event::::BridgeOpened { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), bridge_deposit: deposit, local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), remote_endpoint: Box::new( @@ -373,7 +373,7 @@ pub mod pallet { // deposit the `ClosingBridge` event Self::deposit_event(Event::::ClosingBridge { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id, pruned_messages, enqueued_messages, @@ -420,7 +420,7 @@ pub mod pallet { // deposit the `BridgePruned` event Self::deposit_event(Event::::BridgePruned { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id, bridge_deposit: released_deposit, pruned_messages, @@ -1049,7 +1049,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), bridge_deposit: expected_deposit, local_endpoint: Box::new( locations.bridge_origin_universal_location().clone() @@ -1199,7 +1199,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id, pruned_messages: 16, enqueued_messages: 16, @@ -1247,7 +1247,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id, pruned_messages: 8, enqueued_messages: 8, @@ -1288,7 +1288,7 @@ mod tests { Some(&EventRecord { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { - bridge_id: locations.bridge_id().clone(), + bridge_id: *locations.bridge_id(), lane_id: bridge.lane_id, bridge_deposit: expected_deposit, pruned_messages: 8, diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 8f5040ad9a1b..da112c26e103 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -40,7 +40,7 @@ pub use chain::{ }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", test))] pub use storage_proof::craft_valid_storage_proof; #[cfg(feature = "test-helpers")] pub use storage_proof::{ diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 53efd572b593..baaea449b068 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -281,7 +281,7 @@ where /// Return valid storage proof and state root. /// /// Note: This should only be used for **testing**. -#[cfg(feature = "std")] +#[cfg(any(feature = "std", test))] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; From 74e0bcf4906b70072aae2ce948b6e7f0e7b6eb97 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 09:58:49 +0200 Subject: [PATCH 46/95] Clippy --- bridges/modules/xcm-bridge-hub/src/exporter.rs | 2 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 9625be0d07e2..9805866bc93d 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -429,7 +429,7 @@ mod tests { ) .unwrap(); - (locations.bridge_id().clone(), lane_id) + (*locations.bridge_id(), lane_id) } #[test] diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index cb41353e96bf..eb11a15f00bc 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -1038,7 +1038,7 @@ mod tests { ); assert_eq!( LaneToBridge::::get(lane_id), - Some(locations.bridge_id().clone()) + Some(*locations.bridge_id()) ); assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_deposit); @@ -1190,7 +1190,7 @@ mod tests { ); assert_eq!( LaneToBridge::::get(bridge.lane_id), - Some(locations.bridge_id().clone()) + Some(*locations.bridge_id()) ); assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); @@ -1238,7 +1238,7 @@ mod tests { ); assert_eq!( LaneToBridge::::get(bridge.lane_id), - Some(locations.bridge_id().clone()) + Some(*locations.bridge_id()) ); assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); From 9a2202afde30e33cd285bd26c65993c1e9f4b9a1 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 10:13:04 +0200 Subject: [PATCH 47/95] toml --- bridges/chains/chain-bridge-hub-rococo/Cargo.toml | 2 +- bridges/chains/chain-bridge-hub-westend/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 5c9184703223..8abb35e4d7b6 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -14,7 +14,7 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } bp-messages = { workspace = true } # Substrate Based Dependencies diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 0b429ab9a0bd..6f954b1e1df4 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -15,7 +15,7 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } +bp-runtime = { features = ["test-helpers"], workspace = true } bp-messages = { workspace = true } # Substrate Based Dependencies From 5a60c8615060c8437c065d51f7441995871ebcf9 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 12:03:38 +0200 Subject: [PATCH 48/95] Add pallet's README.md --- bridges/modules/xcm-bridge-hub/README.md | 86 ++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 bridges/modules/xcm-bridge-hub/README.md diff --git a/bridges/modules/xcm-bridge-hub/README.md b/bridges/modules/xcm-bridge-hub/README.md new file mode 100644 index 000000000000..42bf3c18bed6 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/README.md @@ -0,0 +1,86 @@ +# Bridge XCM Bridge Hub Pallet + +The `pallet_xcm_bridge_hub` pallet is used to manage (open, close) bridges between chains from different consensuses. +The new extrinsics `fn open_bridge` and `fn close_bridge` are introduced. Other chains can manage channels +with different bridged global consensuses. + +## Concept of `lane` and `LaneId` + +There is another `pallet_bridge_messages` pallet that handles inbound/outbound lanes for messages. +Each lane is a unique connection between two chains from different consensuses and is identified by `LaneId`. +`LaneId` is generated once when a new bridge is requested by `fn open_bridge`. +It is generated by `BridgeLocations::calculate_lane_id` based on the following parameters: +- Source `bridge_origin_universal_location` (latest XCM) +- Destination `bridge_destination_universal_location` (latest XCM) +- XCM version (both sides of the bridge must use the same parameters to generate the same `LaneId`) + - `bridge_origin_universal_location`, `bridge_destination_universal_location` is converted to the `Versioned*` structs + +`LaneId` is expected to never change because: +- We need the same `LaneId` on both sides of the bridge, as `LaneId` is part of the message key proofs. +- Runtime upgrades are entirely asynchronous. +- We already have a running production Polkadot/Kusama bridge that uses `LaneId([0, 0, 0, 0])`. + +`LaneId` is backward compatible, meaning it can be encoded/decoded from the older format `[u8; 4]` used for +static lanes, as well as the new format `H256` generated by `BridgeLocations::calculate_lane_id`. + +## Concept of `bridge` and `BridgeId` + +The `pallet_xcm_bridge_hub` pallet needs to store some metadata about opened bridges. +The bridge (or bridge metadata) is stored under the `BridgeId` key. + +`BridgeId` is generated from `bridge_origin_relative_location` and `bridge_origin_universal_location` +using the `latest` XCM structs. `BridgeId` is not transferred over the bridge; it is only important for local consensus. +It essentially serves as an index/key to bridge metadata. +All the XCM infrastructure around `XcmExecutor`, `SendXcm`, `ExportXcm` use the `latest` XCM, +so `BridgeId` must remain compatible with the `latest` XCM. For example, we have an `ExportXcm` implementation +in `exporter.rs` that handles the `ExportMessage` instruction with `universal_source` and `destination` (latest XCM), +so we need to create `BridgeId` and the corresponding `LaneId`. + +## Migrations and State + +This pallet implements `try_state`, ensuring compatibility and checking everything so we know if any migration is needed. +`do_try_state` checks for `BridgeId` compatibility, which is recalculated on runtime upgrade. +Upgrading to a new XCM version should not break anything, except removing older XCM versions. +In such cases, we need to add migration for `BridgeId` and stored `Versioned*` structs and +update `LaneToBridge` mapping, but this won't affect `LaneId` over the bridge. + +## How to Open a Bridge? + +The `pallet_xcm_bridge_hub` pallet has the extrinsic `fn open_bridge` and +an important configuration `pallet_xcm_bridge_hub::Config::OpenBridgeOrigin`, +which translates the call's origin to the XCM `Location` and converts it to the `bridge_origin_universal_location`. +With the current setup, this origin/location is expected to be either the relay chain or a sibling parachain +as one side of the bridge. Another parameter is `bridge_destination_universal_location`, +which is the other side of the bridge from a different global consensus. + +Example of opening a bridge between some random parachains from Polkadot and Kusama: + +1. The local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs to its sovereign account + on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. +2. Send a call to the BridgeHubPolkadot from the local sibling parachain: `Location::new(1, Parachain(1234))` + ``` + xcm::Transact( + origin_kind: OriginKind::Xcm, + XcmOverBridgeHubKusama::open_bridge( + VersionedInteriorLocation::V4([GlobalConsensus(Kusama), Parachain(4567)].into()), + ); + ) + ``` +3. Check the stored bridge metadata and generated `LaneId`. +4. The local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to its sovereign account + on BridgeHubKusama to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. +5. Send a call to the BridgeHubKusama from the local sibling parachain: `Location::new(1, Parachain(4567))` + ``` + xcm::Transact( + origin_kind: OriginKind::Xcm, + XcmOverBridgeHubKusama::open_bridge( + VersionedInteriorLocation::V4([GlobalConsensus(Polkadot), Parachain(1234)].into()), + ); + ) + ``` +6. Check the stored bridge metadata and generated `LaneId`. +7. Run the bridge messages relayer for `LaneId`. +8. Send messages from both sides. + +The opening bridge holds the configured `BridgeDeposit` from the origin's sovereign account, +but this deposit is returned when the bridge is closed with `fn close_bridge`. \ No newline at end of file From e19b1e580008a1eb5b18efead69b6d3b84e18b6d Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 12:38:22 +0200 Subject: [PATCH 49/95] Fix BridgeHub benchmarks --- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 21 +++++++++++++++++-- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 21 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 3305c6a5cf5c..95ce4cee9b36 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -1375,11 +1375,28 @@ impl_runtime_apis! { ); BenchmarkError::Stop("XcmVersion was not stored!") })?; + + // open bridge + let origin_location = Location::new(1, [Parachain(5678)]); + let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(origin_location.clone())); + XcmOverBridgeHubWestend::open_bridge( + origin.clone(), + Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Westend), Parachain(8765)])), + ).map_err(|e| { + log::error!( + "Failed to `XcmOverBridgeHubWestend::open_bridge`({:?}, {:?})`, error: {:?}", + origin, + [GlobalConsensus(NetworkId::Westend), Parachain(8765)], + e + ); + BenchmarkError::Stop("Bridge was not opened!") + })?; + Ok( ( - bridge_to_westend_config::FromAssetHubRococoToAssetHubWestendRoute::get().location, + origin_location, NetworkId::Westend, - [Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())].into() + [Parachain(8765)].into() ) ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 7daf9d4623f7..10c74577b311 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -1061,11 +1061,28 @@ impl_runtime_apis! { ); BenchmarkError::Stop("XcmVersion was not stored!") })?; + + // open bridge + let origin_location = Location::new(1, [Parachain(5678)]); + let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(origin_location.clone())); + XcmOverBridgeHubRococo::open_bridge( + origin.clone(), + alloc::boxed::Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Rococo), Parachain(8765)])), + ).map_err(|e| { + log::error!( + "Failed to `XcmOverBridgeHubRococo::open_bridge`({:?}, {:?})`, error: {:?}", + origin, + [GlobalConsensus(NetworkId::Rococo), Parachain(8765)], + e + ); + BenchmarkError::Stop("Bridge was not opened!") + })?; + Ok( ( - bridge_to_rococo_config::FromAssetHubWestendToAssetHubRococoRoute::get().location, + origin_location, NetworkId::Rococo, - [Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())].into() + [Parachain(8765)].into() ) ) } From 0b8d920d0449fb14fe0111e0e933341d09c4c9e2 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 12:51:22 +0200 Subject: [PATCH 50/95] Moved README.md to the lib.rs --- Cargo.lock | 4 +- bridges/modules/xcm-bridge-hub/README.md | 86 ---------------------- bridges/modules/xcm-bridge-hub/src/lib.rs | 87 +++++++++++++++++++++++ 3 files changed, 90 insertions(+), 87 deletions(-) delete mode 100644 bridges/modules/xcm-bridge-hub/README.md diff --git a/Cargo.lock b/Cargo.lock index fa7d4a7ec8d1..549959571e9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -790,6 +790,7 @@ name = "asset-hub-rococo-emulated-chain" version = "0.0.0" dependencies = [ "asset-hub-rococo-runtime", + "bp-bridge-hub-rococo", "cumulus-primitives-core", "emulated-integration-tests-common", "frame-support", @@ -915,6 +916,7 @@ name = "asset-hub-westend-emulated-chain" version = "0.0.0" dependencies = [ "asset-hub-westend-runtime", + "bp-bridge-hub-westend", "cumulus-primitives-core", "emulated-integration-tests-common", "frame-support", @@ -2031,6 +2033,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", + "staging-xcm", ] [[package]] @@ -12037,7 +12040,6 @@ dependencies = [ name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ - "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-benchmarking", "frame-support", diff --git a/bridges/modules/xcm-bridge-hub/README.md b/bridges/modules/xcm-bridge-hub/README.md deleted file mode 100644 index 42bf3c18bed6..000000000000 --- a/bridges/modules/xcm-bridge-hub/README.md +++ /dev/null @@ -1,86 +0,0 @@ -# Bridge XCM Bridge Hub Pallet - -The `pallet_xcm_bridge_hub` pallet is used to manage (open, close) bridges between chains from different consensuses. -The new extrinsics `fn open_bridge` and `fn close_bridge` are introduced. Other chains can manage channels -with different bridged global consensuses. - -## Concept of `lane` and `LaneId` - -There is another `pallet_bridge_messages` pallet that handles inbound/outbound lanes for messages. -Each lane is a unique connection between two chains from different consensuses and is identified by `LaneId`. -`LaneId` is generated once when a new bridge is requested by `fn open_bridge`. -It is generated by `BridgeLocations::calculate_lane_id` based on the following parameters: -- Source `bridge_origin_universal_location` (latest XCM) -- Destination `bridge_destination_universal_location` (latest XCM) -- XCM version (both sides of the bridge must use the same parameters to generate the same `LaneId`) - - `bridge_origin_universal_location`, `bridge_destination_universal_location` is converted to the `Versioned*` structs - -`LaneId` is expected to never change because: -- We need the same `LaneId` on both sides of the bridge, as `LaneId` is part of the message key proofs. -- Runtime upgrades are entirely asynchronous. -- We already have a running production Polkadot/Kusama bridge that uses `LaneId([0, 0, 0, 0])`. - -`LaneId` is backward compatible, meaning it can be encoded/decoded from the older format `[u8; 4]` used for -static lanes, as well as the new format `H256` generated by `BridgeLocations::calculate_lane_id`. - -## Concept of `bridge` and `BridgeId` - -The `pallet_xcm_bridge_hub` pallet needs to store some metadata about opened bridges. -The bridge (or bridge metadata) is stored under the `BridgeId` key. - -`BridgeId` is generated from `bridge_origin_relative_location` and `bridge_origin_universal_location` -using the `latest` XCM structs. `BridgeId` is not transferred over the bridge; it is only important for local consensus. -It essentially serves as an index/key to bridge metadata. -All the XCM infrastructure around `XcmExecutor`, `SendXcm`, `ExportXcm` use the `latest` XCM, -so `BridgeId` must remain compatible with the `latest` XCM. For example, we have an `ExportXcm` implementation -in `exporter.rs` that handles the `ExportMessage` instruction with `universal_source` and `destination` (latest XCM), -so we need to create `BridgeId` and the corresponding `LaneId`. - -## Migrations and State - -This pallet implements `try_state`, ensuring compatibility and checking everything so we know if any migration is needed. -`do_try_state` checks for `BridgeId` compatibility, which is recalculated on runtime upgrade. -Upgrading to a new XCM version should not break anything, except removing older XCM versions. -In such cases, we need to add migration for `BridgeId` and stored `Versioned*` structs and -update `LaneToBridge` mapping, but this won't affect `LaneId` over the bridge. - -## How to Open a Bridge? - -The `pallet_xcm_bridge_hub` pallet has the extrinsic `fn open_bridge` and -an important configuration `pallet_xcm_bridge_hub::Config::OpenBridgeOrigin`, -which translates the call's origin to the XCM `Location` and converts it to the `bridge_origin_universal_location`. -With the current setup, this origin/location is expected to be either the relay chain or a sibling parachain -as one side of the bridge. Another parameter is `bridge_destination_universal_location`, -which is the other side of the bridge from a different global consensus. - -Example of opening a bridge between some random parachains from Polkadot and Kusama: - -1. The local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs to its sovereign account - on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. -2. Send a call to the BridgeHubPolkadot from the local sibling parachain: `Location::new(1, Parachain(1234))` - ``` - xcm::Transact( - origin_kind: OriginKind::Xcm, - XcmOverBridgeHubKusama::open_bridge( - VersionedInteriorLocation::V4([GlobalConsensus(Kusama), Parachain(4567)].into()), - ); - ) - ``` -3. Check the stored bridge metadata and generated `LaneId`. -4. The local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to its sovereign account - on BridgeHubKusama to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. -5. Send a call to the BridgeHubKusama from the local sibling parachain: `Location::new(1, Parachain(4567))` - ``` - xcm::Transact( - origin_kind: OriginKind::Xcm, - XcmOverBridgeHubKusama::open_bridge( - VersionedInteriorLocation::V4([GlobalConsensus(Polkadot), Parachain(1234)].into()), - ); - ) - ``` -6. Check the stored bridge metadata and generated `LaneId`. -7. Run the bridge messages relayer for `LaneId`. -8. Send messages from both sides. - -The opening bridge holds the configured `BridgeDeposit` from the origin's sovereign account, -but this deposit is returned when the bridge is closed with `fn close_bridge`. \ No newline at end of file diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index eb11a15f00bc..ddae48c079e9 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -18,6 +18,67 @@ //! open and close bridges between local (to this pallet location) and remote XCM //! destinations. //! +//! The `pallet_xcm_bridge_hub` pallet is used to manage (open, close) bridges between chains from +//! different consensuses. The new extrinsics `fn open_bridge` and `fn close_bridge` are introduced. +//! Other chains can manage channels with different bridged global consensuses. +//! +//! # Concept of `lane` and `LaneId` +//! +//! There is another `pallet_bridge_messages` pallet that handles inbound/outbound lanes for +//! messages. Each lane is a unique connection between two chains from different consensuses and is +//! identified by `LaneId`. `LaneId` is generated once when a new bridge is requested by `fn +//! open_bridge`. It is generated by `BridgeLocations::calculate_lane_id` based on the following +//! parameters: +//! - Source `bridge_origin_universal_location` (latest XCM) +//! - Destination `bridge_destination_universal_location` (latest XCM) +//! - XCM version (both sides of the bridge must use the same parameters to generate the same +//! `LaneId`) +//! - `bridge_origin_universal_location`, `bridge_destination_universal_location` is converted to +//! the `Versioned*` structs +//! +//! `LaneId` is expected to never change because: +//! - We need the same `LaneId` on both sides of the bridge, as `LaneId` is part of the message key +//! proofs. +//! - Runtime upgrades are entirely asynchronous. +//! - We already have a running production Polkadot/Kusama bridge that uses `LaneId([0, 0, 0, 0])`. +//! +//! `LaneId` is backward compatible, meaning it can be encoded/decoded from the older format `[u8; +//! 4]` used for static lanes, as well as the new format `H256` generated by +//! `BridgeLocations::calculate_lane_id`. +//! +//! # Concept of `bridge` and `BridgeId` +//! +//! The `pallet_xcm_bridge_hub` pallet needs to store some metadata about opened bridges. The bridge +//! (or bridge metadata) is stored under the `BridgeId` key. +//! +//! `BridgeId` is generated from `bridge_origin_relative_location` and +//! `bridge_origin_universal_location` using the `latest` XCM structs. `BridgeId` is not transferred +//! over the bridge; it is only important for local consensus. It essentially serves as an index/key +//! to bridge metadata. All the XCM infrastructure around `XcmExecutor`, `SendXcm`, `ExportXcm` use +//! the `latest` XCM, so `BridgeId` must remain compatible with the `latest` XCM. For example, we +//! have an `ExportXcm` implementation in `exporter.rs` that handles the `ExportMessage` instruction +//! with `universal_source` and `destination` (latest XCM), so we need to create `BridgeId` and the +//! corresponding `LaneId`. +//! +//! # Migrations and State +//! +//! This pallet implements `try_state`, ensuring compatibility and checking everything so we know if +//! any migration is needed. `do_try_state` checks for `BridgeId` compatibility, which is +//! recalculated on runtime upgrade. Upgrading to a new XCM version should not break anything, +//! except removing older XCM versions. In such cases, we need to add migration for `BridgeId` and +//! stored `Versioned*` structs and update `LaneToBridge` mapping, but this won't affect `LaneId` +//! over the bridge. +//! +//! # How to Open a Bridge? +//! +//! The `pallet_xcm_bridge_hub` pallet has the extrinsic `fn open_bridge` and an important +//! configuration `pallet_xcm_bridge_hub::Config::OpenBridgeOrigin`, which translates the call's +//! origin to the XCM `Location` and converts it to the `bridge_origin_universal_location`. With the +//! current setup, this origin/location is expected to be either the relay chain or a sibling +//! parachain as one side of the bridge. Another parameter is +//! `bridge_destination_universal_location`, which is the other side of the bridge from a different +//! global consensus. +//! //! Every bridge between two XCM locations has a dedicated lane in associated //! messages pallet. Assuming that this pallet is deployed at the bridge hub //! parachain and there's a similar pallet at the bridged network, the dynamic @@ -47,6 +108,32 @@ //! are delivered to the destination, are processed in the way their sender expects. So if we //! can't guarantee that, we shall not care about more complex procedures and leave it to the //! participating parties. +//! +//! # Example +//! +//! Example of opening a bridge between some random parachains from Polkadot and Kusama: +//! +//! 1. The local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs to its +//! sovereign account on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, and the +//! existential deposit. +//! 2. Send a call to the BridgeHubPolkadot from the local sibling parachain: `Location::new(1, +//! Parachain(1234))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, +//! XcmOverBridgeHubKusama::open_bridge( VersionedInteriorLocation::V4([GlobalConsensus(Kusama), +//! Parachain(4567)].into()), ); ) ``` +//! 3. Check the stored bridge metadata and generated `LaneId`. +//! 4. The local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to its +//! sovereign account +//! on BridgeHubKusama to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. +//! 5. Send a call to the BridgeHubKusama from the local sibling parachain: `Location::new(1, +//! Parachain(4567))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, +//! XcmOverBridgeHubKusama::open_bridge( +//! VersionedInteriorLocation::V4([GlobalConsensus(Polkadot), Parachain(1234)].into()), ); ) ``` +//! 6. Check the stored bridge metadata and generated `LaneId`. +//! 7. Run the bridge messages relayer for `LaneId`. +//! 8. Send messages from both sides. +//! +//! The opening bridge holds the configured `BridgeDeposit` from the origin's sovereign account, but +//! this deposit is returned when the bridge is closed with `fn close_bridge`. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] From 956f347643b6db7ac79f905ce40c9a38f9b77cc4 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 15:15:07 +0200 Subject: [PATCH 51/95] Imports --- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 95ce4cee9b36..1d29ec256d21 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -1524,8 +1524,8 @@ impl_runtime_apis! { parachain_head_size: u32, proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, + bp_parachains::RelayBlockNumber, + bp_parachains::RelayBlockHash, bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 10c74577b311..15d3eed61f6d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -1172,8 +1172,8 @@ impl_runtime_apis! { parachain_head_size: u32, proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, + bp_parachains::RelayBlockNumber, + bp_parachains::RelayBlockHash, bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { From 0f4a4b396abc7081ac8904f954270fa746d270fe Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 00:13:07 +0200 Subject: [PATCH 52/95] Fixing integration tests + added stubs for open/close_bridge calls --- Cargo.lock | 9 ++ .../chains/chain-bridge-hub-rococo/Cargo.toml | 7 +- .../chains/chain-bridge-hub-rococo/src/lib.rs | 9 ++ .../chain-bridge-hub-westend/Cargo.toml | 6 +- .../chain-bridge-hub-westend/src/lib.rs | 9 ++ bridges/modules/xcm-bridge-hub/src/lib.rs | 39 ++++++ .../xcm-bridge-hub/src/call_info.rs | 43 +++++++ bridges/primitives/xcm-bridge-hub/src/lib.rs | 3 + .../assets/asset-hub-rococo/src/lib.rs | 10 +- .../assets/asset-hub-westend/src/lib.rs | 10 +- .../emulated/common/Cargo.toml | 2 + .../emulated/common/src/impls.rs | 111 +++++++++++++----- .../emulated/common/src/xcm_helpers.rs | 6 +- .../bridges/bridge-hub-rococo/Cargo.toml | 3 +- .../src/tests/asset_transfers.rs | 3 + .../bridge-hub-rococo/src/tests/mod.rs | 59 +++++++++- .../bridge-hub-rococo/src/tests/send_xcm.rs | 3 + .../bridges/bridge-hub-westend/Cargo.toml | 2 + .../src/tests/asset_transfers.rs | 3 + .../bridge-hub-westend/src/tests/mod.rs | 59 +++++++++- .../bridge-hub-westend/src/tests/send_xcm.rs | 3 + cumulus/xcm/xcm-emulator/src/lib.rs | 14 ++- 22 files changed, 362 insertions(+), 51 deletions(-) create mode 100644 bridges/primitives/xcm-bridge-hub/src/call_info.rs diff --git a/Cargo.lock b/Cargo.lock index 549959571e9c..bdce2dfb70a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1794,7 +1794,9 @@ dependencies = [ "bp-bridge-hub-cumulus", "bp-messages", "bp-runtime", + "bp-xcm-bridge-hub", "frame-support", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-std 14.0.0", @@ -1807,7 +1809,9 @@ dependencies = [ "bp-bridge-hub-cumulus", "bp-messages", "bp-runtime", + "bp-xcm-bridge-hub", "frame-support", + "parity-scale-codec", "sp-api", "sp-runtime", "sp-std 14.0.0", @@ -2079,6 +2083,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "rococo-system-emulated-network", @@ -2263,11 +2268,13 @@ dependencies = [ "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "rococo-westend-system-emulated-network", "sp-runtime", "staging-xcm", "staging-xcm-executor", + "testnet-parachains-constants", ] [[package]] @@ -5184,6 +5191,7 @@ version = "3.0.0" dependencies = [ "asset-test-utils", "bp-messages", + "bp-xcm-bridge-hub", "bridge-runtime-common", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -5194,6 +5202,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "paste", diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 8abb35e4d7b6..17aef80627c4 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -11,14 +11,15 @@ repository.workspace = true workspace = true [dependencies] -# Bridge Dependencies +codec = { features = ["derive"], workspace = true } +# Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } bp-runtime = { features = ["test-helpers"], workspace = true } bp-messages = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies - frame-support = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } @@ -30,6 +31,8 @@ std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub/std", + "codec/std", "frame-support/std", "sp-api/std", "sp-runtime/std", diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index cf444a25f8bb..505be5adf33d 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -25,6 +25,7 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; +use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchClass, sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug, StateVersion}, @@ -114,3 +115,11 @@ frame_support::parameter_types! { /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 59_941_787; } + +/// Wrapper over `BridgeHubRococo`'s `RuntimeCall` that can be used without a runtime. +#[derive(Decode, Encode)] +pub enum RuntimeCall { + /// Points to the `pallet_xcm_bridge_hub` pallet instance for `BridgeHubWestend`. + #[codec(index = 52)] + XcmOverBridgeHubWestend(bp_xcm_bridge_hub::XcmBridgeHubCall), +} diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 6f954b1e1df4..f21fd5787427 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -11,15 +11,15 @@ repository.workspace = true workspace = true [dependencies] +codec = { features = ["derive"], workspace = true } # Bridge Dependencies - bp-bridge-hub-cumulus = { workspace = true } bp-runtime = { features = ["test-helpers"], workspace = true } bp-messages = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies - frame-support = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } @@ -31,6 +31,8 @@ std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub/std", + "codec/std", "frame-support/std", "sp-api/std", "sp-runtime/std", diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index e9455063cd02..009ae1a96867 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -24,6 +24,7 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; +use codec::{Decode, Encode}; use frame_support::dispatch::DispatchClass; use sp_runtime::{RuntimeDebug, StateVersion}; @@ -103,3 +104,11 @@ frame_support::parameter_types! { /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_982_586_452; } + +/// Wrapper over `BridgeHubWestend`'s `RuntimeCall` that can be used without a runtime. +#[derive(Decode, Encode)] +pub enum RuntimeCall { + /// Points to the `pallet_xcm_bridge_hub` pallet instance for `BridgeHubRococo`. + #[codec(index = 45)] + XcmOverBridgeHubRococo(bp_xcm_bridge_hub::XcmBridgeHubCall), +} diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index ddae48c079e9..86363c5c969d 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -1524,4 +1524,43 @@ mod tests { cleanup(bridge_id_mismatch, lane_id); }); } + + #[test] + fn ensure_encoding_compatibility() { + use codec::Encode; + + let bridge_destination_universal_location = BridgedUniversalDestination::get(); + let may_prune_messages = 13; + + assert_eq!( + bp_xcm_bridge_hub::XcmBridgeHubCall::open_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ) + } + .encode(), + Call::::open_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ) + } + .encode() + ); + assert_eq!( + bp_xcm_bridge_hub::XcmBridgeHubCall::close_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ), + may_prune_messages, + } + .encode(), + Call::::close_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ), + may_prune_messages, + } + .encode() + ); + } } diff --git a/bridges/primitives/xcm-bridge-hub/src/call_info.rs b/bridges/primitives/xcm-bridge-hub/src/call_info.rs new file mode 100644 index 000000000000..fd4fc67822fe --- /dev/null +++ b/bridges/primitives/xcm-bridge-hub/src/call_info.rs @@ -0,0 +1,43 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-xcm-bridge-hub` pallet. + +use bp_messages::MessageNonce; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_std::boxed::Box; +use xcm::prelude::VersionedInteriorLocation; + +/// A minimized version of `pallet_xcm_bridge_hub::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum XcmBridgeHubCall { + /// `pallet_xcm_bridge_hub::Call::open_bridge` + #[codec(index = 0)] + open_bridge { + /// Universal `InteriorLocation` from the bridged consensus. + bridge_destination_universal_location: Box, + }, + /// `pallet_xcm_bridge_hub::Call::close_bridge` + #[codec(index = 1)] + close_bridge { + /// Universal `InteriorLocation` from the bridged consensus. + bridge_destination_universal_location: Box, + /// The number of messages that we may prune in a single call. + may_prune_messages: MessageNonce, + }, +} diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index b2d5a51b95e3..44a90a57d4fb 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -21,6 +21,7 @@ use bp_messages::LaneId; use bp_runtime::{AccountIdOf, BalanceOf, Chain}; +pub use call_info::XcmBridgeHubCall; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, sp_runtime::RuntimeDebug, CloneNoBound, PalletError, PartialEqNoBound, @@ -36,6 +37,8 @@ use xcm::{ VersionedLocation, }; +mod call_info; + /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 80d2376c6811..1c0a75c13758 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -24,8 +24,8 @@ use frame_support::traits::OnInitialize; use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_bridge_helpers_for_chain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -61,3 +61,9 @@ impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); impl_assets_helpers_for_parachain!(AssetHubRococo); impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v3::Location); impl_xcm_helpers_for_parachain!(AssetHubRococo); +impl_bridge_helpers_for_chain!( + AssetHubRococo, + ParaPallet, + PolkadotXcm, + bp_bridge_hub_rococo::RuntimeCall::XcmOverBridgeHubWestend +); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 608690218d2f..e484d908df29 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -24,8 +24,8 @@ use frame_support::traits::OnInitialize; use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_bridge_helpers_for_chain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -61,3 +61,9 @@ impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); impl_assets_helpers_for_parachain!(AssetHubWestend); impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v3::Location); impl_xcm_helpers_for_parachain!(AssetHubWestend); +impl_bridge_helpers_for_chain!( + AssetHubWestend, + ParaPallet, + PolkadotXcm, + bp_bridge_hub_westend::RuntimeCall::XcmOverBridgeHubRococo +); diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 7152f1dbc272..981ee5c88b4e 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -42,5 +42,7 @@ asset-test-utils = { workspace = true, default-features = true } # Bridges bp-messages = { workspace = true, default-features = true } +bp-xcm-bridge-hub = { workspace = true, default-features = true } pallet-bridge-messages = { workspace = true, default-features = true } +pallet-xcm-bridge-hub = { workspace = true, default-features = true } bridge-runtime-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 8f2789eb2f3a..559a16379bb4 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -17,7 +17,8 @@ pub use codec::{Decode, Encode}; pub use paste; pub use crate::{ - xcm_helpers::xcm_transact_unpaid_execution, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, }; // Substrate @@ -30,7 +31,6 @@ pub use frame_support::{ pub use pallet_assets; pub use pallet_message_queue; pub use pallet_xcm; -use sp_core::Get; // Polkadot pub use polkadot_runtime_parachains::{ @@ -38,7 +38,9 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{Location, OriginKind, Outcome, VersionedXcm, XcmError, XcmVersion}, + prelude::{ + Asset, InteriorLocation, Location, OriginKind, Outcome, VersionedXcm, XcmError, XcmVersion, + }, DoubleEncoded, }; @@ -51,7 +53,7 @@ pub use cumulus_primitives_core::{ }; pub use parachains_common::{AccountId, Balance}; pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, BridgeMessage, + assert_expected_events, bx, helpers::weight_within_threshold, BridgeLaneId, BridgeMessage, BridgeMessageDispatchError, BridgeMessageHandler, Chain, Network, Parachain, RelayChain, TestExt, }; @@ -61,60 +63,60 @@ use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, LaneId, MessageKey, OutboundLaneData, }; -use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; -use pallet_bridge_messages::{Config, OutboundLanes, Pallet}; +pub use bp_xcm_bridge_hub::XcmBridgeHubCall; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, OutboundLanes, Pallet}; pub use pallet_bridge_messages::{ Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2, Instance3 as BridgeMessagesInstance3, }; +use pallet_xcm_bridge_hub::XcmBlobMessageDispatchResult; pub struct BridgeHubMessageHandler { _marker: std::marker::PhantomData<(S, SI, T, TI)>, } struct LaneIdWrapper(LaneId); - -impl From for u32 { - fn from(lane_id: LaneIdWrapper) -> u32 { - u32::from_be_bytes(lane_id.0 .0) +impl From for BridgeLaneId { + fn from(lane_id: LaneIdWrapper) -> BridgeLaneId { + lane_id.0.encode() } } - -impl From for LaneIdWrapper { - fn from(id: u32) -> LaneIdWrapper { - LaneIdWrapper(LaneId(id.to_be_bytes())) +impl From for LaneIdWrapper { + fn from(id: BridgeLaneId) -> LaneIdWrapper { + LaneIdWrapper(LaneId::decode(&mut &id[..]).expect("decodable")) } } impl BridgeMessageHandler for BridgeHubMessageHandler where - S: Config, + S: BridgeMessagesConfig, SI: 'static, - T: Config, + T: BridgeMessagesConfig, TI: 'static, - >::InboundPayload: From>, - >::MessageDispatch: + >::InboundPayload: From>, + >::MessageDispatch: MessageDispatch, { fn get_source_outbound_messages() -> Vec { // get the source active outbound lanes - let active_lanes = S::ActiveOutboundLanes::get(); + let active_outbound_lanes = OutboundLanes::::iter_keys(); let mut messages: Vec = Default::default(); // collect messages from `OutboundMessages` for each active outbound lane in the source - for lane in active_lanes { - let latest_generated_nonce = OutboundLanes::::get(lane).latest_generated_nonce; - let latest_received_nonce = OutboundLanes::::get(lane).latest_received_nonce; + for lane in active_outbound_lanes { + let latest_generated_nonce = + OutboundLanes::::get(lane).unwrap().latest_generated_nonce; + let latest_received_nonce = + OutboundLanes::::get(lane).unwrap().latest_received_nonce; (latest_received_nonce + 1..=latest_generated_nonce).for_each(|nonce| { - let encoded_payload: Vec = Pallet::::outbound_message_data(*lane, nonce) + let encoded_payload: Vec = Pallet::::outbound_message_data(lane, nonce) .expect("Bridge message does not exist") .into(); let payload = Vec::::decode(&mut &encoded_payload[..]) .expect("Decoding XCM message failed"); - let id: u32 = LaneIdWrapper(*lane).into(); - let message = BridgeMessage { id, nonce, payload }; + let message = BridgeMessage { lane_id: LaneIdWrapper(lane).into(), nonce, payload }; messages.push(message); }); @@ -125,10 +127,10 @@ where fn dispatch_target_inbound_message( message: BridgeMessage, ) -> Result<(), BridgeMessageDispatchError> { - type TargetMessageDispatch = >::MessageDispatch; - type InboundPayload = >::InboundPayload; + type TargetMessageDispatch = >::MessageDispatch; + type InboundPayload = >::InboundPayload; - let lane_id = LaneIdWrapper::from(message.id).0; + let lane_id = LaneIdWrapper::from(message.lane_id).0; let nonce = message.nonce; let payload = Ok(From::from(message.payload)); @@ -151,15 +153,16 @@ where result } - fn notify_source_message_delivery(lane_id: u32) { - let data = OutboundLanes::::get(LaneIdWrapper::from(lane_id).0); + fn notify_source_message_delivery(lane_id: BridgeLaneId) { + let lane_id = LaneIdWrapper::from(lane_id).0; + let data = OutboundLanes::::get(lane_id).unwrap(); let new_data = OutboundLaneData { oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1, latest_received_nonce: data.latest_received_nonce + 1, ..data }; - OutboundLanes::::insert(LaneIdWrapper::from(lane_id).0, new_data); + OutboundLanes::::insert(lane_id, new_data); } } @@ -925,3 +928,49 @@ macro_rules! impl_xcm_helpers_for_parachain { } } } + +#[macro_export] +macro_rules! impl_bridge_helpers_for_chain { + ( $chain:ident, $pallet:ident, $pallet_xcm:ident, $runtime_call_wrapper:path ) => { + $crate::impls::paste::paste! { + impl $chain { + /// Open bridge with `dest`. + pub fn open_bridge( + bridge_location: $crate::impls::Location, + bridge_destination_universal_location: $crate::impls::InteriorLocation, + maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)> + ) { + ::execute_with(|| { + use $crate::impls::{bx, Chain}; + use $crate::impls::XcmBridgeHubCall; + use $crate::impls::Encode; + + // important to use `root` and `OriginKind::Xcm` + let root_origin = ::RuntimeOrigin::root(); + + // construct call + let call: $crate::impls::DoubleEncoded<()> = $runtime_call_wrapper(XcmBridgeHubCall::open_bridge { + bridge_destination_universal_location: bx!( + bridge_destination_universal_location.clone().into() + ) + }).encode().into(); + + let xcm = if let Some((fee_asset, beneficiary)) = maybe_paid { + $crate::impls::xcm_transact_paid_execution(call, $crate::impls::OriginKind::Xcm, fee_asset, beneficiary) + } else { + $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Xcm) + }; + + // Send XCM `Transact` with `open_bridge` call + $crate::impls::assert_ok!(]>::$pallet_xcm::send( + root_origin, + bx!(bridge_location.into()), + bx!(xcm), + )); + Self::assert_xcm_pallet_sent(); + }); + } + } + } + } +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index 76179c6d82c6..54e0e95a0a6b 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -23,16 +23,16 @@ use xcm::{prelude::*, DoubleEncoded}; pub fn xcm_transact_paid_execution( call: DoubleEncoded<()>, origin_kind: OriginKind, - native_asset: Asset, + asset: Asset, beneficiary: AccountId, ) -> VersionedXcm<()> { let weight_limit = WeightLimit::Unlimited; let require_weight_at_most = Weight::from_parts(1000000000, 200000); - let native_assets: Assets = native_asset.clone().into(); + let native_assets: Assets = asset.clone().into(); VersionedXcm::from(Xcm(vec![ WithdrawAsset(native_assets), - BuyExecution { fees: native_asset, weight_limit }, + BuyExecution { fees: asset, weight_limit }, Transact { require_weight_at_most, origin_kind, call }, RefundSurplus, DepositAsset { diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index a5787885329d..86ace7d564e8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -31,6 +31,7 @@ xcm-executor = { workspace = true } # Bridges pallet-bridge-messages = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } # Cumulus cumulus-pallet-xcmp-queue = { workspace = true } @@ -38,7 +39,7 @@ emulated-integration-tests-common = { workspace = true } parachains-common = { workspace = true, default-features = true } rococo-system-emulated-network = { workspace = true } rococo-westend-system-emulated-network = { workspace = true } -testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } +testnet-parachains-constants = { features = ["rococo", "westend"], workspace = true, default-features = true } # Snowbridge snowbridge-core = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 6053936487b2..492992366697 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -25,6 +25,9 @@ fn send_assets_over_bridge(send_fn: F) { AssetHubRococo::force_xcm_version(asset_hub_westend_location(), XCM_VERSION); BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send message over bridge send_fn(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index ceccf98a0240..0696a8e55290 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -36,7 +36,10 @@ pub(crate) fn bridged_roc_at_ah_westend() -> Location { Location::new(2, [GlobalConsensus(Rococo)]) } -// wWND +// WND and wWND +pub(crate) fn wnd_at_ah_westend() -> Location { + Parent.into() +} pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { Location::new(2, [GlobalConsensus(Westend)]) } @@ -210,3 +213,57 @@ pub(crate) fn assert_bridge_hub_westend_message_received() { ); }) } + +pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { + use testnet_parachains_constants::{ + rococo::currency::UNITS as ROC, westend::currency::UNITS as WND, + }; + + // open AHR -> AHW + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); + AssetHubRococo::open_bridge( + AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), + [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + Some(( + (roc_at_ah_rococo(), ROC * 1).into(), + BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( + AssetHubRococo::para_id(), + )), + )), + ); + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmOverBridgeHubWestend( + pallet_xcm_bridge_hub::Event::BridgeOpened { .. } + ) => {}, + ] + ); + }); + + // open AHW -> AHR + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); + AssetHubWestend::open_bridge( + AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), + [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + Some(( + (wnd_at_ah_westend(), WND * 1).into(), + BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( + AssetHubWestend::para_id(), + )), + )), + ); + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::XcmOverBridgeHubRococo( + pallet_xcm_bridge_hub::Event::BridgeOpened { .. } + ) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 652447fa5601..18752b81d79e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -79,6 +79,9 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // fund sender AssetHubRococo::fund_accounts(vec![(AssetHubRococoSender::get().into(), amount * 10)]); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send XCM from AssetHubRococo - fails - destination version not known assert_err!( send_assets_from_asset_hub_rococo( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 6b83479eaf89..2d20cd48474b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -28,9 +28,11 @@ xcm-executor = { workspace = true } # Bridges pallet-bridge-messages = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } # Cumulus cumulus-pallet-xcmp-queue = { workspace = true } emulated-integration-tests-common = { workspace = true } parachains-common = { workspace = true, default-features = true } rococo-westend-system-emulated-network = { workspace = true } +testnet-parachains-constants = { features = ["rococo", "westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index 0c0b04cd45a9..baf01ea9d46e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -24,6 +24,9 @@ fn send_assets_over_bridge(send_fn: F) { AssetHubWestend::force_xcm_version(asset_hub_rococo_location(), XCM_VERSION); BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send message over bridge send_fn(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 768b647a13fc..194e8bec2465 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -41,7 +41,10 @@ pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { Location::new(2, [GlobalConsensus(Westend)]) } -// wROC +// ROC and wROC +pub(crate) fn roc_at_ah_rococo() -> Location { + Parent.into() +} pub(crate) fn bridged_roc_at_ah_westend() -> Location { Location::new(2, [GlobalConsensus(Rococo)]) } @@ -228,3 +231,57 @@ pub(crate) fn assert_bridge_hub_rococo_message_received() { ); }) } + +pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { + use testnet_parachains_constants::{ + rococo::currency::UNITS as ROC, westend::currency::UNITS as WND, + }; + + // open AHR -> AHW + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); + AssetHubRococo::open_bridge( + AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), + [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + Some(( + (roc_at_ah_rococo(), ROC * 1).into(), + BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( + AssetHubRococo::para_id(), + )), + )), + ); + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmOverBridgeHubWestend( + pallet_xcm_bridge_hub::Event::BridgeOpened { .. } + ) => {}, + ] + ); + }); + + // open AHW -> AHR + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); + AssetHubWestend::open_bridge( + AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), + [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + Some(( + (wnd_at_ah_westend(), WND * 1).into(), + BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( + AssetHubWestend::para_id(), + )), + )), + ); + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::XcmOverBridgeHubRococo( + pallet_xcm_bridge_hub::Event::BridgeOpened { .. } + ) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index dee411bea8b7..ae05e4223b07 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -79,6 +79,9 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // fund sender AssetHubWestend::fund_accounts(vec![(AssetHubWestendSender::get().into(), amount * 10)]); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send XCM from AssetHubWestend - fails - destination version not known assert_err!( send_assets_from_asset_hub_westend( diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 8de3660c2236..afed14278d17 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -296,9 +296,11 @@ impl Bridge for () { fn init() {} } +pub type BridgeLaneId = Vec; + #[derive(Clone, Default, Debug)] pub struct BridgeMessage { - pub id: u32, + pub lane_id: BridgeLaneId, pub nonce: u64, pub payload: Vec, } @@ -310,7 +312,7 @@ pub trait BridgeMessageHandler { message: BridgeMessage, ) -> Result<(), BridgeMessageDispatchError>; - fn notify_source_message_delivery(lane_id: u32); + fn notify_source_message_delivery(lane_id: BridgeLaneId); } impl BridgeMessageHandler for () { @@ -324,7 +326,7 @@ impl BridgeMessageHandler for () { Err(BridgeMessageDispatchError(Box::new("Not a bridge"))) } - fn notify_source_message_delivery(_lane_id: u32) {} + fn notify_source_message_delivery(_lane_id: BridgeLaneId) {} } #[derive(Debug)] @@ -1079,12 +1081,12 @@ macro_rules! decl_test_networks { }); match dispatch_result { - Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg.clone()), + Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg), Ok(()) => { <::Source as TestExt>::ext_wrapper(|| { - <::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.id); + <::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.lane_id.clone()); }); - $crate::log::debug!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg.clone()); + $crate::log::debug!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg); } } } From d442936fdc7415be4ddc045d3e924c0d941a0736 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 31 Jul 2024 16:20:29 +0200 Subject: [PATCH 53/95] Fix BridgeHub benchmarks for export_message --- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 19 ++++++++++++++++--- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 1d29ec256d21..4f798596d270 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -1376,9 +1376,22 @@ impl_runtime_apis! { BenchmarkError::Stop("XcmVersion was not stored!") })?; + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); + + // fund SA + use frame_support::traits::fungible::Mutate; + use xcm_executor::traits::ConvertLocation; + frame_support::assert_ok!( + Balances::mint_into( + &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), + bridge_to_westend_config::BridgeDeposit::get() + .saturating_add(ExistentialDeposit::get()) + .saturating_add(UNITS * 5) + ) + ); + // open bridge - let origin_location = Location::new(1, [Parachain(5678)]); - let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(origin_location.clone())); + let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(sibling_parachain_location.clone())); XcmOverBridgeHubWestend::open_bridge( origin.clone(), Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Westend), Parachain(8765)])), @@ -1394,7 +1407,7 @@ impl_runtime_apis! { Ok( ( - origin_location, + sibling_parachain_location, NetworkId::Westend, [Parachain(8765)].into() ) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 15d3eed61f6d..c8fc6b0fc0b5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -1062,9 +1062,22 @@ impl_runtime_apis! { BenchmarkError::Stop("XcmVersion was not stored!") })?; + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); + + // fund SA + use frame_support::traits::fungible::Mutate; + use xcm_executor::traits::ConvertLocation; + frame_support::assert_ok!( + Balances::mint_into( + &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), + bridge_to_rococo_config::BridgeDeposit::get() + .saturating_add(ExistentialDeposit::get()) + .saturating_add(UNITS * 5) + ) + ); + // open bridge - let origin_location = Location::new(1, [Parachain(5678)]); - let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(origin_location.clone())); + let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(sibling_parachain_location.clone())); XcmOverBridgeHubRococo::open_bridge( origin.clone(), alloc::boxed::Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Rococo), Parachain(8765)])), @@ -1080,7 +1093,7 @@ impl_runtime_apis! { Ok( ( - origin_location, + sibling_parachain_location, NetworkId::Rococo, [Parachain(8765)].into() ) From d463d01612d8cbf2e94bff3c6d8a7ac1d9dcd845 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 1 Aug 2024 00:10:53 +0200 Subject: [PATCH 54/95] Fix `pallet_bridge_messages` benchmarks --- bridges/modules/xcm-bridge-hub/src/lib.rs | 5 +- .../src/bridge_to_bulletin_config.rs | 47 +++++++++++++++++++ .../src/bridge_to_westend_config.rs | 46 ++++++++++++++++++ .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 8 +++- .../src/bridge_to_rococo_config.rs | 46 ++++++++++++++++++ .../bridge-hubs/bridge-hub-westend/src/lib.rs | 4 +- 6 files changed, 150 insertions(+), 6 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 86363c5c969d..40e58f18e46d 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -140,9 +140,8 @@ use bp_messages::{LaneId, LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; -use bp_xcm_bridge_hub::{ - Bridge, BridgeId, BridgeLocations, BridgeLocationsError, BridgeState, LocalXcmChannelManager, -}; +pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; +use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError, LocalXcmChannelManager}; use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 01ab1c040cbf..afe5dee9d435 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -227,6 +227,53 @@ mod tests { } } +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: bp_messages::LaneId, + sibling_para_id: u32, +) -> InteriorLocation { + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + use xcm_executor::traits::ConvertLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get()), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( + &sibling_parachain, + ) + .expect("valid AccountId"), + deposit: Balance::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert( + lane_id, bridge_id, + ); + + universal_source +} + // TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI pub mod migration_for_bridges_v2 { use super::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 81fb181cfd40..e3e5fb15aef2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -186,6 +186,52 @@ impl pallet_xcm_bridge_hub::Config for Runtime type BlobDispatcher = FromWestendMessageBlobDispatcher; } +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: bp_messages::LaneId, + sibling_para_id: u32, +) -> InteriorLocation { + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + use xcm_executor::traits::ConvertLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); + let universal_destination = [GlobalConsensus(Westend), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( + &sibling_parachain, + ) + .expect("valid AccountId"), + deposit: Balance::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert( + lane_id, bridge_id, + ); + + universal_source +} + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 4f798596d270..74ef8e195abd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -1461,16 +1461,18 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_westend_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { + let _ = bridge_to_westend_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, @@ -1496,16 +1498,18 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_bulletin_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { + let _ = bridge_to_bulletin_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_delivery_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index bec868999e00..1af1a85d38fe 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -217,6 +217,52 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type BlobDispatcher = FromRococoMessageBlobDispatcher; } +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: bp_messages::LaneId, + sibling_para_id: u32, +) -> InteriorLocation { + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + use xcm_executor::traits::ConvertLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Westend), Parachain(sibling_para_id)].into(); + let universal_destination = [GlobalConsensus(Rococo), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( + &sibling_parachain, + ) + .expect("valid AccountId"), + deposit: Balance::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert( + lane_id, bridge_id, + ); + + universal_source +} + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index c8fc6b0fc0b5..039b459cfabf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -1144,16 +1144,18 @@ impl_runtime_apis! { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_rococo_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Westend), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { + let _ = bridge_to_rococo_config::open_bridge_for_benchmarks(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, From bbe088cc177fee235f0e6ca22867e65579a34d10 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 13 Aug 2024 11:09:37 +0200 Subject: [PATCH 55/95] Fix feature propagation and cargo check CI nit --- bridges/chains/chain-bridge-hub-rococo/Cargo.toml | 2 +- bridges/chains/chain-bridge-hub-westend/Cargo.toml | 2 +- bridges/modules/xcm-bridge-hub/Cargo.toml | 2 +- bridges/primitives/messages/Cargo.toml | 2 +- bridges/primitives/relayers/Cargo.toml | 2 +- bridges/primitives/runtime/Cargo.toml | 3 +-- bridges/primitives/runtime/src/lib.rs | 6 ++---- bridges/primitives/runtime/src/storage_proof.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-westend/src/xcm_config.rs | 6 ++---- 11 files changed, 14 insertions(+), 19 deletions(-) diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index d17accdb3ae2..23fbd9a2742f 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -18,7 +18,7 @@ codec = { features = ["derive"], workspace = true } # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-messages = { workspace = true } bp-xcm-bridge-hub = { workspace = true } diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 432ef78815cb..61357e6aa6c8 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -18,7 +18,7 @@ codec = { features = ["derive"], workspace = true } # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-messages = { workspace = true } bp-xcm-bridge-hub = { workspace = true } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 7d00d7904713..fe58b910a94e 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -36,7 +36,7 @@ xcm-executor = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true } sp-io = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-header-chain = { workspace = true } pallet-xcm-bridge-hub-router = { workspace = true } polkadot-parachain-primitives = { workspace = true } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 271325b47355..87c8cbe88180 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -28,7 +28,7 @@ sp-io = { workspace = true } [dev-dependencies] hex = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 2019b7196573..34be38bed4ac 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } bp-header-chain = { workspace = true } bp-messages = { workspace = true } bp-parachains = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies frame-system = { workspace = true } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 034e6c12610d..18ecb789e1e1 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -20,7 +20,6 @@ scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies - frame-support = { workspace = true } frame-system = { workspace = true } sp-core = { workspace = true } @@ -33,6 +32,7 @@ trie-db = { workspace = true } [dev-dependencies] hex-literal = { workspace = true, default-features = true } +sp-state-machine = { workspace = true } [features] default = ["std"] @@ -48,7 +48,6 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", - "sp-state-machine?/std", "sp-std/std", "sp-trie/std", "trie-db/std", diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index da112c26e103..efa8e659b368 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -40,12 +40,10 @@ pub use chain::{ }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; -#[cfg(any(feature = "std", test))] -pub use storage_proof::craft_valid_storage_proof; #[cfg(feature = "test-helpers")] pub use storage_proof::{ - grow_storage_proof, grow_storage_value, record_all_keys as record_all_trie_keys, - UnverifiedStorageProofParams, + craft_valid_storage_proof, grow_storage_proof, grow_storage_value, + record_all_keys as record_all_trie_keys, UnverifiedStorageProofParams, }; pub use storage_proof::{ raw_storage_proof_size, RawStorageProof, StorageProofChecker, StorageProofError, diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index baaea449b068..1cf4987aa730 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -18,7 +18,7 @@ use frame_support::PalletError; use sp_core::RuntimeDebug; -use sp_std::{default::Default, vec::Vec}; +use sp_std::vec::Vec; use sp_trie::{ accessed_nodes_tracker::AccessedNodesTracker, read_trie_value, LayoutV1, MemoryDB, StorageProof, }; @@ -281,7 +281,7 @@ where /// Return valid storage proof and state root. /// /// Note: This should only be used for **testing**. -#[cfg(any(feature = "std", test))] +#[cfg(any(feature = "test-helpers", test))] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index b343482aff38..e5b753ac1f3f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -97,7 +97,7 @@ bp-parachains = { workspace = true } bp-polkadot-bulletin = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-rococo = { workspace = true } bp-westend = { workspace = true } pallet-bridge-grandpa = { workspace = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 949ac83ff371..984c9407c6b4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -90,7 +90,7 @@ bp-messages = { workspace = true } bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-rococo = { workspace = true } bp-westend = { workspace = true } pallet-bridge-grandpa = { workspace = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 503a1c20b658..491caa38dc5f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -212,10 +212,8 @@ impl xcm_executor::Config for XcmConfig { SendXcmFeeToAccount, ), >; - type MessageExporter = ( - XcmOverBridgeHubRococo, - crate::bridge_to_ethereum_config::SnowbridgeExporter, - ); + type MessageExporter = + (XcmOverBridgeHubRococo, crate::bridge_to_ethereum_config::SnowbridgeExporter); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; From b0f360c2e57873375af28db0a2a91ce3cf74afe5 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 13 Aug 2024 13:47:39 +0200 Subject: [PATCH 56/95] Allow empty migration for CI --- .../bridge-hub-rococo/src/bridge_to_bulletin_config.rs | 2 +- .../bridge-hub-rococo/src/bridge_to_westend_config.rs | 2 +- .../bridge-hub-westend/src/bridge_to_rococo_config.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index afe5dee9d435..c4ddd4583a1e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -325,7 +325,7 @@ pub mod migration_for_bridges_v2 { pub struct StaticToDynamicLanes; impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { fn on_runtime_upgrade() -> Weight { - todo!() + Weight::zero() } } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index e3e5fb15aef2..ecc6522a533c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -372,7 +372,7 @@ pub mod migration_for_bridges_v2 { pub struct StaticToDynamicLanes; impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { fn on_runtime_upgrade() -> Weight { - todo!() + Weight::zero() } } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 1af1a85d38fe..532f556e5ae2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -401,7 +401,7 @@ pub mod migration_for_bridges_v2 { pub struct StaticToDynamicLanes; impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { fn on_runtime_upgrade() -> Weight { - todo!() + Weight::zero() } } } From ad93c2b0c8114a0e014d04ef532c46f46fa9bca1 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 13 Aug 2024 14:02:09 +0200 Subject: [PATCH 57/95] Removed unneeded `_phantom` (for Cisco) --- bridges/modules/messages/src/lanes_manager.rs | 2 -- bridges/modules/messages/src/tests/pallet_tests.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs index b3455202259c..9325a9f58a18 100644 --- a/bridges/modules/messages/src/lanes_manager.rs +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -137,7 +137,6 @@ impl, I: 'static> LanesManager { pub struct RuntimeInboundLaneStorage, I: 'static = ()> { pub(crate) lane_id: LaneId, pub(crate) cached_data: InboundLaneData>>, - pub(crate) _phantom: PhantomData, } impl, I: 'static> RuntimeInboundLaneStorage { @@ -177,7 +176,6 @@ impl, I: 'static> RuntimeInboundLaneStorage { Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into(), - _phantom: Default::default(), }) } diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index a3497c4b66dd..0cf7d6977877 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -1090,7 +1090,6 @@ fn inbound_storage_extra_proof_size_bytes_works() { relayers: vec![relayer_entry(); relayer_entries].into(), last_confirmed_nonce: 0, }, - _phantom: Default::default(), } } From 2b5c43f6dee7bbc7ceca42271006dd04dbe4f559 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 14 Aug 2024 12:06:28 +0200 Subject: [PATCH 58/95] Added storage_version and migration for `pallet_bridge_messages` --- bridges/modules/messages/src/lanes_manager.rs | 5 +- bridges/modules/messages/src/lib.rs | 2 + bridges/modules/messages/src/migration.rs | 146 ++++++++++++++++++ 3 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 bridges/modules/messages/src/migration.rs diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs index 9325a9f58a18..4f5ac1c0a403 100644 --- a/bridges/modules/messages/src/lanes_manager.rs +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -173,10 +173,7 @@ impl, I: 'static> RuntimeInboundLaneStorage { ); } - Ok(RuntimeInboundLaneStorage { - lane_id, - cached_data: cached_data.into(), - }) + Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into() }) } /// Returns number of bytes that may be subtracted from the PoV component of diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 606d67d957da..b1ac27386380 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -84,6 +84,7 @@ pub mod weights; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; +pub mod migration; pub use call_ext::*; pub use pallet::*; @@ -143,6 +144,7 @@ pub mod pallet { pub type BridgedHeaderChainOf = >::BridgedHeaderChain; #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); impl, I: 'static> OwnedBridgeModule for Pallet { diff --git a/bridges/modules/messages/src/migration.rs b/bridges/modules/messages/src/migration.rs new file mode 100644 index 000000000000..dc9a8119079e --- /dev/null +++ b/bridges/modules/messages/src/migration.rs @@ -0,0 +1,146 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::{Config, Pallet}; +use frame_support::{ + traits::{Get, StorageVersion}, + weights::Weight, +}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// This module contains data structures that are valid for the initial state of `0`. +/// (used with v1 migration). +pub mod v0 { + use super::Config; + use crate::BridgedChainOf; + use bp_messages::{MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } +} + +/// This migration to `1` updates the metadata of `InboundLanes` and `OutboundLanes` to the new +/// structures. +pub mod v1 { + use super::*; + use crate::{ + InboundLaneData, InboundLanes, OutboundLaneData, OutboundLanes, StoredInboundLaneData, + }; + use bp_messages::LaneState; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use sp_std::marker::PhantomData; + + /// Migrates the pallet storage to v1. + pub struct UncheckedMigrationV0ToV1(PhantomData<(T, I)>); + + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrationV0ToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v0::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = |pre: v0::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + OutboundLanes::::translate_values(translate_outbound); + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + use codec::Encode; + + let number_of_inbound_to_migrate = InboundLanes::::iter_keys().count(); + let number_of_outbound_to_migrate = OutboundLanes::::iter_keys().count(); + Ok((number_of_inbound_to_migrate as u32, number_of_outbound_to_migrate as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + use codec::Decode; + const LOG_TARGET: &str = "runtime::bridge-messages-migration"; + + let (number_of_inbound_to_migrate, number_of_outbound_to_migrate): (u32, u32) = + Decode::decode(&mut &state[..]).unwrap(); + let number_of_inbound = InboundLanes::::iter_keys().count(); + let number_of_outbound = OutboundLanes::::iter_keys().count(); + + log::info!(target: LOG_TARGET, "post-upgrade expects '{number_of_inbound_to_migrate}' inbound lanes to have been migrated."); + log::info!(target: LOG_TARGET, "post-upgrade expects '{number_of_outbound_to_migrate}' outbound lanes to have been migrated."); + + frame_support::ensure!( + number_of_inbound_to_migrate as usize == number_of_inbound, + "must migrate all `InboundLanes`." + ); + frame_support::ensure!( + number_of_outbound_to_migrate as usize == number_of_outbound, + "must migrate all `OutboundLanes`." + ); + + log::info!(target: LOG_TARGET, "migrated all."); + Ok(()) + } + } + + /// [`UncheckedMigrationV0ToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationV0ToV1, + Pallet, + ::DbWeight, + >; +} From 2b6c21edb420d161fe683b94e0f213c70df2b1d9 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 14 Aug 2024 13:57:45 +0200 Subject: [PATCH 59/95] Improved and more strict `try_state` for `pallet_xcm_bridge_hub` --- .../modules/xcm-bridge-hub/src/dispatcher.rs | 71 ++-- .../modules/xcm-bridge-hub/src/exporter.rs | 32 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 320 ++++++++++++------ 3 files changed, 296 insertions(+), 127 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index db533cd41608..2412bb0f3bb0 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -121,11 +121,12 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{mock::*, Bridges, LaneToBridge}; + use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; use bp_messages::{target_chain::DispatchMessageData, MessageKey}; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; + use pallet_bridge_messages::InboundLaneStorage; use xcm_executor::traits::ConvertLocation; fn bridge() -> (Box, LaneId) { @@ -141,28 +142,52 @@ mod tests { run_test(|| { let (bridge, lane_id) = bridge(); - Bridges::::insert( - bridge.bridge_id(), - Bridge { - bridge_origin_relative_location: Box::new( - bridge.bridge_origin_relative_location().clone().into(), - ), - bridge_origin_universal_location: Box::new( - bridge.bridge_origin_universal_location().clone().into(), - ), - bridge_destination_universal_location: Box::new( - bridge.bridge_destination_universal_location().clone().into(), - ), - state: BridgeState::Opened, - bridge_owner_account: LocationToAccountId::convert_location( - bridge.bridge_origin_relative_location(), - ) - .expect("valid accountId"), - deposit: 0, - lane_id, - }, - ); - LaneToBridge::::insert(lane_id, bridge.bridge_id()); + if !Bridges::::contains_key(bridge.bridge_id()) { + // insert bridge + Bridges::::insert( + bridge.bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new( + bridge.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + bridge.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + bridge.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location( + bridge.bridge_origin_relative_location(), + ) + .expect("valid accountId"), + deposit: 0, + lane_id, + }, + ); + LaneToBridge::::insert(lane_id, bridge.bridge_id()); + + // create lanes + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_inbound_lane(lane_id).is_ok() { + assert_eq!( + 0, + lanes_manager + .active_inbound_lane(lane_id) + .unwrap() + .storage() + .data() + .last_confirmed_nonce + ); + } + if lanes_manager.create_outbound_lane(lane_id).is_ok() { + assert!(lanes_manager + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + } + } assert_ok!(XcmOverBridge::do_try_state()); test(); diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 9805866bc93d..e31b47a8297e 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -357,6 +357,7 @@ mod tests { use bp_runtime::RangeInclusiveExt; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; + use pallet_bridge_messages::InboundLaneStorage; use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; use xcm_executor::traits::{export_xcm, ConvertLocation}; @@ -380,14 +381,7 @@ mod tests { XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); - let lanes_manager = LanesManagerOf::::new(); - if lanes_manager.create_outbound_lane(lane_id).is_ok() { - assert!(lanes_manager - .active_outbound_lane(lane_id) - .unwrap() - .queued_messages() - .is_empty()); - + if !Bridges::::contains_key(locations.bridge_id()) { // insert bridge Bridges::::insert( locations.bridge_id(), @@ -409,8 +403,28 @@ mod tests { }, ); LaneToBridge::::insert(lane_id, locations.bridge_id()); - } + // create lanes + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_inbound_lane(lane_id).is_ok() { + assert_eq!( + 0, + lanes_manager + .active_inbound_lane(lane_id) + .unwrap() + .storage() + .data() + .last_confirmed_nonce + ); + } + if lanes_manager.create_outbound_lane(lane_id).is_ok() { + assert!(lanes_manager + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + } + } assert_ok!(XcmOverBridge::do_try_state()); (*locations, lane_id) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 40e58f18e46d..b71d5032a8c8 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -300,82 +300,7 @@ pub mod pallet { Error::::BridgeLocations(e) })?; - // reserve balance on the origin's sovereign account - let deposit = if T::AllowWithoutBridgeDeposit::contains( - locations.bridge_origin_relative_location(), - ) { - BalanceOf::>::zero() - } else { - T::BridgeDeposit::get() - }; - let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - locations.bridge_origin_relative_location(), - ) - .ok_or(Error::::InvalidBridgeOriginAccount)?; - T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) - .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; - - // save bridge metadata - Bridges::::try_mutate(locations.bridge_id(), |bridge| match bridge { - Some(_) => Err(Error::::BridgeAlreadyExists), - None => { - *bridge = Some(BridgeOf:: { - bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location().clone().into(), - ), - bridge_origin_universal_location: Box::new( - locations.bridge_origin_universal_location().clone().into(), - ), - bridge_destination_universal_location: Box::new( - locations.bridge_destination_universal_location().clone().into(), - ), - state: BridgeState::Opened, - bridge_owner_account, - deposit, - lane_id, - }); - Ok(()) - }, - })?; - // save lane to bridge mapping - LaneToBridge::::try_mutate(lane_id, |bridge| match bridge { - Some(_) => Err(Error::::BridgeAlreadyExists), - None => { - *bridge = Some(*locations.bridge_id()); - Ok(()) - }, - })?; - - // create new lanes. Under normal circumstances, following calls shall never fail - let lanes_manager = LanesManagerOf::::new(); - lanes_manager - .create_inbound_lane(lane_id) - .map_err(Error::::LanesManager)?; - lanes_manager - .create_outbound_lane(lane_id) - .map_err(Error::::LanesManager)?; - - // write something to log - log::trace!( - target: LOG_TARGET, - "Bridge {:?} between {:?} and {:?} has been opened using lane_id: {lane_id:?}", - locations.bridge_id(), - locations.bridge_origin_universal_location(), - locations.bridge_destination_universal_location(), - ); - - // deposit `BridgeOpened` event - Self::deposit_event(Event::::BridgeOpened { - bridge_id: *locations.bridge_id(), - bridge_deposit: deposit, - local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), - remote_endpoint: Box::new( - locations.bridge_destination_universal_location().clone(), - ), - lane_id, - }); - - Ok(()) + Self::do_open_bridge(locations, lane_id) } /// Try to close the bridge. @@ -516,6 +441,90 @@ pub mod pallet { } } + impl, I: 'static> Pallet { + fn do_open_bridge( + locations: Box, + lane_id: LaneId, + ) -> Result<(), DispatchError> { + // reserve balance on the origin's sovereign account + let deposit = if T::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location(), + ) { + BalanceOf::>::zero() + } else { + T::BridgeDeposit::get() + }; + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + locations.bridge_origin_relative_location(), + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; + T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) + .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; + + // save bridge metadata + Bridges::::try_mutate(locations.bridge_id(), |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(BridgeOf:: { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + deposit, + lane_id, + }); + Ok(()) + }, + })?; + // save lane to bridge mapping + LaneToBridge::::try_mutate(lane_id, |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(*locations.bridge_id()); + Ok(()) + }, + })?; + + // create new lanes. Under normal circumstances, following calls shall never fail + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .create_inbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + lanes_manager + .create_outbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + + // write something to log + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} has been opened using lane_id: {lane_id:?}", + locations.bridge_id(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + ); + + // deposit `BridgeOpened` event + Self::deposit_event(Event::::BridgeOpened { + bridge_id: *locations.bridge_id(), + bridge_deposit: deposit, + local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), + remote_endpoint: Box::new( + locations.bridge_destination_universal_location().clone(), + ), + lane_id, + }); + + Ok(()) + } + } + impl, I: 'static> Pallet { /// Return bridge endpoint locations and dedicated lane identifier. This method converts /// runtime `origin` argument to relative `Location` using the `T::OpenBridgeOrigin` @@ -582,7 +591,6 @@ pub mod pallet { // check all known bridge configurations for (bridge_id, bridge) in Bridges::::iter() { - log::info!(target: LOG_TARGET, "Checking `do_try_state` for bridge_id: {bridge_id:?} and bridge: {bridge:?}"); lanes.insert(Self::do_try_state_for_bridge(bridge_id, bridge)?); } ensure!( @@ -594,7 +602,8 @@ pub mod pallet { "Invalid `LaneToBridge` configuration, probably missing or not removed laneId!" ); - Ok(()) + // check connected `pallet_bridge_messages` state. + Self::do_try_state_for_messages() } /// Ensure the correctness of the state of the bridge. @@ -602,12 +611,25 @@ pub mod pallet { bridge_id: BridgeId, bridge: BridgeOf, ) -> Result { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_bridge` for bridge_id: {bridge_id:?} and bridge: {bridge:?}"); + // check `BridgeId` points to the same `LaneId` and vice versa. ensure!( Some(bridge_id) == Self::lane_to_bridge(bridge.lane_id), "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!" ); + // check `pallet_bridge_messages` state for that `LaneId`. + let lanes_manager = LanesManagerOf::::new(); + ensure!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).is_ok(), + "Inbound lane not found!", + ); + ensure!( + lanes_manager.any_state_outbound_lane(bridge.lane_id).is_ok(), + "Outbound lane not found!", + ); + // check that `locations` are convertible to the `latest` XCM. let bridge_origin_relative_location_as_latest: &Location = bridge.bridge_origin_relative_location.try_as().map_err(|_| { @@ -634,6 +656,29 @@ pub mod pallet { Ok(bridge.lane_id) } + + /// Ensure the correctness of the state of the connected `pallet_bridge_messages` instance. + pub fn do_try_state_for_messages() -> Result<(), sp_runtime::TryRuntimeError> { + // check that all `InboundLanes` laneIds have mapping to some bridge. + for lane_id in pallet_bridge_messages::InboundLanes::::iter_keys() { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `InboundLanes`'s lane_id: {lane_id:?}..."); + ensure!( + Self::lane_to_bridge(lane_id).is_some(), + "Found `LaneToBridge` inconsistency for `InboundLanes`'s lane_id - missing mapping!" + ); + } + + // check that all `OutboundLanes` laneIds have mapping to some bridge. + for lane_id in pallet_bridge_messages::OutboundLanes::::iter_keys() { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `OutboundLanes`'s lane_id: {lane_id:?}..."); + ensure!( + Self::lane_to_bridge(lane_id).is_some(), + "Found `LaneToBridge` inconsistency for `OutboundLanes`'s lane_id - missing mapping!" + ); + } + + Ok(()) + } } /// All registered bridges. @@ -1403,22 +1448,39 @@ mod tests { ); let bridge_id_mismatch = BridgeId::new(&InteriorLocation::Here, &InteriorLocation::Here); let lane_id = LaneId::from_inner(Either::Left(H256::default())); + let lane_id_mismatch = LaneId::from_inner(Either::Left(H256::from([1u8; 32]))); - let test_bridge_state = - |id, bridge, (lane_id, bridge_id), expected_error: Option| { - Bridges::::insert(id, bridge); - LaneToBridge::::insert(lane_id, bridge_id); + let test_bridge_state = |id, + bridge, + (lane_id, bridge_id), + (inbound_lane_id, outbound_lane_id), + expected_error: Option| { + Bridges::::insert(id, bridge); + LaneToBridge::::insert(lane_id, bridge_id); - let result = XcmOverBridge::do_try_state(); - if let Some(e) = expected_error { - assert_err!(result, e); - } else { - assert_ok!(result); - } - }; - let cleanup = |bridge_id, lane_id| { + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_inbound_lane(inbound_lane_id).unwrap(); + lanes_manager.create_outbound_lane(outbound_lane_id).unwrap(); + + let result = XcmOverBridge::do_try_state(); + if let Some(e) = expected_error { + assert_err!(result, e); + } else { + assert_ok!(result); + } + }; + let cleanup = |bridge_id, lane_ids| { Bridges::::remove(bridge_id); - LaneToBridge::::remove(lane_id); + for lane_id in lane_ids { + LaneToBridge::::remove(lane_id); + let lanes_manager = LanesManagerOf::::new(); + if let Ok(lane) = lanes_manager.any_state_inbound_lane(lane_id) { + lane.purge(); + } + if let Ok(lane) = lanes_manager.any_state_outbound_lane(lane_id) { + lane.purge(); + } + } assert_ok!(XcmOverBridge::do_try_state()); }; @@ -1444,9 +1506,10 @@ mod tests { lane_id, }, (lane_id, bridge_id), + (lane_id, lane_id), None, ); - cleanup(bridge_id, lane_id); + cleanup(bridge_id, vec![lane_id]); // error - missing `LaneToBridge` mapping test_bridge_state( @@ -1469,11 +1532,12 @@ mod tests { lane_id, }, (lane_id, bridge_id_mismatch), + (lane_id, lane_id), Some(TryRuntimeError::Other( "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!", )), ); - cleanup(bridge_id, lane_id); + cleanup(bridge_id, vec![lane_id]); // error bridge owner account cannot be calculated test_bridge_state( @@ -1494,9 +1558,10 @@ mod tests { lane_id, }, (lane_id, bridge_id), + (lane_id, lane_id), Some(TryRuntimeError::Other("`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!")), ); - cleanup(bridge_id, lane_id); + cleanup(bridge_id, vec![lane_id]); // error when (bridge_origin_universal_location + bridge_destination_universal_location) // produces different `BridgeId` @@ -1518,9 +1583,74 @@ mod tests { lane_id, }, (lane_id, bridge_id_mismatch), + (lane_id, lane_id), Some(TryRuntimeError::Other("`bridge_id` is different than calculated from `bridge_origin_universal_location_as_latest` and `bridge_destination_universal_location_as_latest`, needs migration!")), ); - cleanup(bridge_id_mismatch, lane_id); + cleanup(bridge_id_mismatch, vec![lane_id]); + + // missing inbound lane for a bridge + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id_mismatch, lane_id), + Some(TryRuntimeError::Other("Inbound lane not found!")), + ); + cleanup(bridge_id, vec![lane_id, lane_id_mismatch]); + + // missing outbound lane for a bridge + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id, lane_id_mismatch), + Some(TryRuntimeError::Other("Outbound lane not found!")), + ); + cleanup(bridge_id, vec![lane_id, lane_id_mismatch]); + + // missing bridge for inbound lane + let lanes_manager = LanesManagerOf::::new(); + assert!(lanes_manager.create_inbound_lane(lane_id).is_ok()); + assert_err!(XcmOverBridge::do_try_state(), TryRuntimeError::Other("Found `LaneToBridge` inconsistency for `InboundLanes`'s lane_id - missing mapping!")); + cleanup(bridge_id, vec![lane_id]); + + // missing bridge for outbound lane + let lanes_manager = LanesManagerOf::::new(); + assert!(lanes_manager.create_outbound_lane(lane_id).is_ok()); + assert_err!(XcmOverBridge::do_try_state(), TryRuntimeError::Other("Found `LaneToBridge` inconsistency for `OutboundLanes`'s lane_id - missing mapping!")); + cleanup(bridge_id, vec![lane_id]); }); } From 45b5659192ed82f491d45edde50e60a4314d7864 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 14 Aug 2024 15:58:42 +0200 Subject: [PATCH 60/95] Added migration from static to dynamic lanes for AssetHubs --- bridges/modules/messages/src/lib.rs | 9 -- bridges/modules/xcm-bridge-hub/src/lib.rs | 57 ++++--- .../modules/xcm-bridge-hub/src/migration.rs | 146 ++++++++++++++++++ 3 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 bridges/modules/xcm-bridge-hub/src/migration.rs diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index b1ac27386380..d3368657182b 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -649,15 +649,6 @@ pub mod pallet { Ok(()) } } - - /// Get-parameter that returns number of active outbound lanes that the pallet maintains. - pub struct MaybeOutboundLanesCount(PhantomData<(T, I)>); - - impl, I: 'static> Get> for MaybeOutboundLanesCount { - fn get() -> Option { - Some(OutboundLanes::::iter().count() as u32) - } - } } /// Structure, containing a validated message payload and all the info required diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index b71d5032a8c8..edd83d09269d 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -158,6 +158,7 @@ pub use pallet::*; mod dispatcher; mod exporter; +pub mod migration; mod mock; /// The target that will be used when publishing logs related to this pallet. @@ -251,6 +252,7 @@ pub mod pallet { pallet_bridge_messages::LanesManager>::BridgeMessagesPalletInstance>; #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] @@ -300,7 +302,7 @@ pub mod pallet { Error::::BridgeLocations(e) })?; - Self::do_open_bridge(locations, lane_id) + Self::do_open_bridge(locations, lane_id, true) } /// Try to close the bridge. @@ -442,24 +444,39 @@ pub mod pallet { } impl, I: 'static> Pallet { - fn do_open_bridge( + pub(crate) fn do_open_bridge( locations: Box, lane_id: LaneId, + create_lanes: bool, ) -> Result<(), DispatchError> { - // reserve balance on the origin's sovereign account + // reserve balance on the origin's sovereign account (if needed) + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + locations.bridge_origin_relative_location(), + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; let deposit = if T::AllowWithoutBridgeDeposit::contains( locations.bridge_origin_relative_location(), ) { BalanceOf::>::zero() } else { - T::BridgeDeposit::get() + let deposit = T::BridgeDeposit::get(); + T::Currency::hold( + &HoldReason::BridgeDeposit.into(), + &bridge_owner_account, + deposit, + ) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Failed to hold bridge deposit: {deposit:?} \ + from bridge_owner_account: {bridge_owner_account:?} derived from \ + bridge_origin_relative_location: {:?} with error: {e:?}", + locations.bridge_origin_relative_location(), + ); + Error::::FailedToReserveBridgeDeposit + })?; + deposit }; - let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - locations.bridge_origin_relative_location(), - ) - .ok_or(Error::::InvalidBridgeOriginAccount)?; - T::Currency::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit) - .map_err(|_| Error::::FailedToReserveBridgeDeposit)?; // save bridge metadata Bridges::::try_mutate(locations.bridge_id(), |bridge| match bridge { @@ -492,14 +509,16 @@ pub mod pallet { }, })?; - // create new lanes. Under normal circumstances, following calls shall never fail - let lanes_manager = LanesManagerOf::::new(); - lanes_manager - .create_inbound_lane(lane_id) - .map_err(Error::::LanesManager)?; - lanes_manager - .create_outbound_lane(lane_id) - .map_err(Error::::LanesManager)?; + if create_lanes { + // create new lanes. Under normal circumstances, following calls shall never fail + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .create_inbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + lanes_manager + .create_outbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + } // write something to log log::trace!( @@ -988,7 +1007,7 @@ mod tests { run_test(|| { assert_noop!( XcmOverBridge::open_bridge( - OpenBridgeOrigin::parent_relay_chain_origin(), + OpenBridgeOrigin::sibling_parachain_origin(), Box::new(bridged_asset_hub_universal_location().into()), ), Error::::FailedToReserveBridgeDeposit, diff --git a/bridges/modules/xcm-bridge-hub/src/migration.rs b/bridges/modules/xcm-bridge-hub/src/migration.rs new file mode 100644 index 000000000000..c9d8b67176a5 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/migration.rs @@ -0,0 +1,146 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::{Config, Pallet, LOG_TARGET}; +use bp_messages::LaneId; +use frame_support::{ + traits::{Get, OnRuntimeUpgrade, StorageVersion}, + weights::Weight, +}; +use xcm::prelude::{InteriorLocation, Location}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + +/// This migration does not modify storage but can be used to open a bridge and link it to the +/// specified LaneId. This is useful when we want to open a bridge and use a custom LaneId instead +/// of the pre-calculated one provided by the `fn open_bridge extrinsic`. +/// Or perhaps if you want to ensure that your runtime (e.g., for testing) always has an open +/// bridge. +pub struct OpenBridgeForLane< + T, + I, + Lane, + CreateLane, + SourceRelativeLocation, + BridgedUniversalLocation, +>( + core::marker::PhantomData<( + T, + I, + Lane, + CreateLane, + SourceRelativeLocation, + BridgedUniversalLocation, + )>, +); +impl< + T: Config, + I: 'static, + Lane: Get, + CreateLane: Get, + SourceRelativeLocation: Get, + BridgedUniversalLocation: Get, + > OnRuntimeUpgrade + for OpenBridgeForLane +{ + fn on_runtime_upgrade() -> Weight { + let bridge_origin_relative_location = SourceRelativeLocation::get(); + let bridge_destination_universal_location = BridgedUniversalLocation::get(); + let lane_id = Lane::get(); + let create_lane = CreateLane::get(); + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - going to open bridge with lane_id: {lane_id:?} (create_lane: {create_lane:?}) \ + between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?}", + ); + + let locations = match Pallet::::bridge_locations( + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone(), + ) { + Ok(locations) => locations, + Err(e) => { + log::error!( + target: LOG_TARGET, + "OpenBridgeForLane - on_runtime_upgrade failed to construct bridge_locations with error: {e:?}" + ); + return T::DbWeight::get().reads(0) + }, + }; + + // check if already exists + if let Some((bridge_id, bridge)) = Pallet::::bridge_by_lane_id(&lane_id) { + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - bridge: {bridge:?} with bridge_id: {bridge_id:?} already exist for lane_id: {lane_id:?}!" + ); + if &bridge_id != locations.bridge_id() { + log::warn!( + target: LOG_TARGET, + "OpenBridgeForLane - check you parameters, because a different bridge: {bridge:?} \ + with bridge_id: {bridge_id:?} exist for lane_id: {lane_id:?} for requested \ + bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?} !", + ); + } + + return T::DbWeight::get().reads(2) + } + + if let Err(e) = Pallet::::do_open_bridge(locations, lane_id, create_lane) { + log::error!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge failed with error: {e:?}"); + T::DbWeight::get().reads(6) + } else { + log::info!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge passed!"); + T::DbWeight::get().reads_writes(6, 4) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + let bridge_origin_relative_location = SourceRelativeLocation::get(); + let bridge_destination_universal_location = BridgedUniversalLocation::get(); + let lane_id = Lane::get(); + + // check that requested bridge is stored + let Ok(locations) = Pallet::::bridge_locations( + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone(), + ) else { + return Err(sp_runtime::DispatchError::Other("Invalid locations!")) + }; + let Some((bridge_id, _)) = Pallet::::bridge_by_lane_id(&lane_id) else { + return Err(sp_runtime::DispatchError::Other("Missing bridge!")) + }; + frame_support::ensure!( + locations.bridge_id() == &bridge_id, + "Bridge is not stored correctly!" + ); + + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - post_upgrade found opened bridge with lane_id: {lane_id:?} \ + between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?}", + ); + + Ok(()) + } +} From 2f57da98ae60df3c548591a268839cac73a327c3 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 00:11:19 +0200 Subject: [PATCH 61/95] Added migrations to the BridgeHub testnets --- .../src/bridge_to_bulletin_config.rs | 72 ++++++------------- .../src/bridge_to_westend_config.rs | 71 ++++++------------ .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 28 +++++++- .../src/bridge_to_rococo_config.rs | 70 ++++++------------ .../bridge-hubs/bridge-hub-westend/src/lib.rs | 17 ++++- 5 files changed, 105 insertions(+), 153 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index c4ddd4583a1e..5b9076f18ae7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -274,58 +274,26 @@ pub(crate) fn open_bridge_for_benchmarks( universal_source } -// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI -pub mod migration_for_bridges_v2 { +/// Contains the migration for the PeopleRococo<>RococoBulletin bridge. +pub mod migration { use super::*; - - // /// A pair of sending chain location and message lane, used by this chain to send messages - // /// over the bridge. - // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] - // pub struct SenderAndLane { - // /// Sending chain relative location. - // pub location: Location, - // /// Message lane, used by the sending chain. - // pub lane: LaneId, - // } - // - // impl SenderAndLane { - // /// Create new object using provided location and lane. - // pub fn new(location: Location, lane: LaneId) -> Self { - // SenderAndLane { location, lane } - // } - // } - // - // pub const XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN: LaneId = LaneId([0, 0, 0, 0]); - // - // parameter_types! { - // pub RococoPeopleParaId: cumulus_primitives_core::ParaId = - // rococo_runtime_constants::system_parachain::PEOPLE_ID.into(); // Lanes - // /// All active lanes that the current bridge supports. - // pub ActiveOutboundLanesToRococoBulletin: &'static [bp_messages::LaneId] - // = &[XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN]; - // /// Lane identifier, used to connect Rococo People and Rococo Bulletin chain. - // pub const RococoPeopleToRococoBulletinMessagesLane: bp_messages::LaneId - // = XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN; - // /// Identifier of the sibling Rococo People parachain. - // /// A route (XCM location and bridge lane) that the Rococo People Chain -> Rococo Bulletin - // Chain /// message is following. - // pub FromRococoPeopleToRococoBulletinRoute: SenderAndLane = SenderAndLane::new( - // ParentThen(Parachain(RococoPeopleParaId::get().into()).into()).into(), - // XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - // ); - // /// All active routes and their destinations. - // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = - // alloc::vec![ ( - // FromRococoPeopleToRococoBulletinRoute::get(), - // (RococoBulletinGlobalConsensusNetwork::get(), Here) - // ) - // ]; - // } - - pub struct StaticToDynamicLanes; - impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { - fn on_runtime_upgrade() -> Weight { - Weight::zero() - } + use bp_messages::LaneId; + use frame_support::traits::ConstBool; + use sp_runtime::Either; + + parameter_types! { + pub RococoPeopleToRococoBulletinMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 0])); + pub PeopleRococoLocation: Location = Location::new(1, [Parachain(rococo_runtime_constants::system_parachain::PEOPLE_ID)]); + pub BulletinRococoLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); } + + /// Ensure that the existing lanes for the People<>Bulletin bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverPolkadotBulletinInstance, + RococoPeopleToRococoBulletinMessagesLane, + ConstBool, + PeopleRococoLocation, + BulletinRococoLocation, + >; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index ecc6522a533c..66dd9dff8b42 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -324,55 +324,28 @@ mod tests { } } -// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI -pub mod migration_for_bridges_v2 { +/// Contains the migration for the AssetHubRococo<>AssetHubWestend bridge. +pub mod migration { use super::*; - - // /// A pair of sending chain location and message lane, used by this chain to send messages - // /// over the bridge. - // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] - // pub struct SenderAndLane { - // /// Sending chain relative location. - // pub location: Location, - // /// Message lane, used by the sending chain. - // pub lane: LaneId, - // } - // - // impl SenderAndLane { - // /// Create new object using provided location and lane. - // pub fn new(location: Location, lane: LaneId) -> Self { - // SenderAndLane { location, lane } - // } - // } - // - // pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); - // parameter_types! { - // pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = - // bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); pub AssetHubWestendParaId: - // cumulus_primitives_core::ParaId = - // bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); - // - // // Lanes - // pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = - // &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; pub const - // AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = - // XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; - // pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( - // ParentThen([Parachain(AssetHubRococoParaId::get().into())].into()).into(), - // XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - // ); - // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = - // alloc::vec![ ( - // FromAssetHubRococoToAssetHubWestendRoute::get(), - // (WestendGlobalConsensusNetwork::get(), - // [Parachain(AssetHubWestendParaId::get().into())].into()) ) - // ]; - // } - - pub struct StaticToDynamicLanes; - impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { - fn on_runtime_upgrade() -> Weight { - Weight::zero() - } + use bp_messages::LaneId; + use frame_support::traits::ConstBool; + use sp_runtime::Either; + + parameter_types! { + pub AssetHubRococoToAssetHubWestendMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 2])); + pub AssetHubRococoLocation: Location = Location::new(1, [Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)]); + pub AssetHubWestendUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)].into(); } + + /// Ensure that the existing lanes for the AHR<>AHW bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverBridgeHubWestendInstance, + AssetHubRococoToAssetHubWestendMessagesLane, + // the lanes are already created for AHR<>AHW, but we need to link them to the bridge + // structs + ConstBool, + AssetHubRococoLocation, + AssetHubWestendUniversalLocation, + >; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index b4b2414c1395..100bff5a0705 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -162,12 +162,36 @@ pub type Migrations = ( ConstU32, ConstU32, >, - bridge_to_westend_config::migration_for_bridges_v2::StaticToDynamicLanes, - bridge_to_bulletin_config::migration_for_bridges_v2::StaticToDynamicLanes, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, + >, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, + >, + bridge_to_westend_config::migration::StaticToDynamicLanes, + bridge_to_bulletin_config::migration::StaticToDynamicLanes, + frame_support::migrations::RemoveStorage< + BridgeWestendMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, + frame_support::migrations::RemoveStorage< + BridgePolkadotBulletinMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); +parameter_types! { + pub const BridgeWestendMessagesPalletName: &'static str = "BridgeWestendMessages"; + pub const BridgePolkadotBulletinMessagesPalletName: &'static str = "BridgePolkadotBulletinMessages"; + pub const OutboundLanesCongestedSignalsKey: &'static str = "OutboundLanesCongestedSignals"; +} + /// Migration to initialize storage versions for pallets added after genesis. /// /// Ideally this would be done automatically (see diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 532f556e5ae2..76121af452a4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -354,54 +354,28 @@ mod tests { } } -// TODO:(bridges-v2) - migration from static to dynamic lanes - FAIL-CI -pub mod migration_for_bridges_v2 { +/// Contains the migration for the AssetHubWestend<>AssetHubRococo bridge. +pub mod migration { use super::*; - - // /// A pair of sending chain location and message lane, used by this chain to send messages - // /// over the bridge. - // #[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] - // pub struct SenderAndLane { - // /// Sending chain relative location. - // pub location: Location, - // /// Message lane, used by the sending chain. - // pub lane: LaneId, - // } - // - // impl SenderAndLane { - // /// Create new object using provided location and lane. - // pub fn new(location: Location, lane: LaneId) -> Self { - // SenderAndLane { location, lane } - // } - // } - // - // pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); - // parameter_types! { - // pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = - // bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); pub AssetHubRococoParaId: - // cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - // - // // Lanes - // pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = - // &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; pub const - // AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = - // XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; - // pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( - // ParentThen([Parachain(AssetHubWestendParaId::get().into())].into()).into(), - // XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - // ); - // pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = - // alloc::vec![ ( - // FromAssetHubWestendToAssetHubRococoRoute::get(), - // (RococoGlobalConsensusNetwork::get(), [Parachain(AssetHubRococoParaId::get().into())].into()) - // ) - // ]; - // } - - pub struct StaticToDynamicLanes; - impl frame_support::traits::OnRuntimeUpgrade for StaticToDynamicLanes { - fn on_runtime_upgrade() -> Weight { - Weight::zero() - } + use bp_messages::LaneId; + use frame_support::traits::ConstBool; + use sp_runtime::Either; + + parameter_types! { + pub AssetHubWestendToAssetHubRococoMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 2])); + pub AssetHubWestendLocation: Location = Location::new(1, [Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)]); + pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into(); } + + /// Ensure that the existing lanes for the AHW<>AHR bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverBridgeHubRococoInstance, + AssetHubWestendToAssetHubRococoMessagesLane, + // the lanes are already created for AHR<>AHW, but we need to link them to the bridge + // structs + ConstBool, + AssetHubWestendLocation, + AssetHubRococoUniversalLocation, + >; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 40fc8b6e3db1..5717db456a77 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -81,7 +81,6 @@ use xcm_runtime_apis::{ }; use bp_runtime::HeaderId; - #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -141,11 +140,25 @@ pub type Migrations = ( // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, - bridge_to_rococo_config::migration_for_bridges_v2::StaticToDynamicLanes, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >, + bridge_to_rococo_config::migration::StaticToDynamicLanes, + frame_support::migrations::RemoveStorage< + BridgeRococoMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); +parameter_types! { + pub const BridgeRococoMessagesPalletName: &'static str = "BridgeRococoMessages"; + pub const OutboundLanesCongestedSignalsKey: &'static str = "OutboundLanesCongestedSignals"; +} + /// Migration to initialize storage versions for pallets added after genesis. /// /// Ideally this would be done automatically (see From a4905d16ae15cd19c5cab1a18e331e4cca038093 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 01:24:07 +0200 Subject: [PATCH 62/95] Fix `craft_valid_storage_proof` --- bridges/primitives/runtime/Cargo.toml | 6 +++--- bridges/primitives/runtime/src/lib.rs | 6 ++++-- bridges/primitives/runtime/src/storage_proof.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 18ecb789e1e1..7528f2e5d6ca 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -25,14 +25,13 @@ frame-system = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } -sp-state-machine = { optional = true, workspace = true } +sp-state-machine = { workspace = true } sp-std = { workspace = true } sp-trie = { workspace = true } trie-db = { workspace = true } [dev-dependencies] hex-literal = { workspace = true, default-features = true } -sp-state-machine = { workspace = true } [features] default = ["std"] @@ -48,8 +47,9 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", + "sp-state-machine/std", "sp-std/std", "sp-trie/std", "trie-db/std", ] -test-helpers = ["sp-state-machine"] +test-helpers = [] diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index efa8e659b368..bf0be6e62ba4 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -40,10 +40,12 @@ pub use chain::{ }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; +#[cfg(any(feature = "test-helpers", feature = "std"))] +pub use storage_proof::craft_valid_storage_proof; #[cfg(feature = "test-helpers")] pub use storage_proof::{ - craft_valid_storage_proof, grow_storage_proof, grow_storage_value, - record_all_keys as record_all_trie_keys, UnverifiedStorageProofParams, + grow_storage_proof, grow_storage_value, record_all_keys as record_all_trie_keys, + UnverifiedStorageProofParams, }; pub use storage_proof::{ raw_storage_proof_size, RawStorageProof, StorageProofChecker, StorageProofError, diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 1cf4987aa730..1f0498119867 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -281,7 +281,7 @@ where /// Return valid storage proof and state root. /// /// Note: This should only be used for **testing**. -#[cfg(any(feature = "test-helpers", test))] +#[cfg(any(feature = "test-helpers", feature = "std", test))] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; From 40b20ff8ec354dc0700bcd19fba9d79c00477b03 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 06:48:55 +0200 Subject: [PATCH 63/95] Actually, just revert for `craft_valid_storage_proof` --- bridges/primitives/runtime/src/lib.rs | 2 +- bridges/primitives/runtime/src/storage_proof.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index bf0be6e62ba4..8f5040ad9a1b 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -40,7 +40,7 @@ pub use chain::{ }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; -#[cfg(any(feature = "test-helpers", feature = "std"))] +#[cfg(feature = "std")] pub use storage_proof::craft_valid_storage_proof; #[cfg(feature = "test-helpers")] pub use storage_proof::{ diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 1f0498119867..8bd9001f2b6c 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -281,7 +281,7 @@ where /// Return valid storage proof and state root. /// /// Note: This should only be used for **testing**. -#[cfg(any(feature = "test-helpers", feature = "std", test))] +#[cfg(feature = "std")] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; From ab2b4beac78afe3180ebfedba218d67ba1ed0a12 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:08:49 +0000 Subject: [PATCH 64/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_parachains --- .../src/weights/pallet_bridge_parachains.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs index b4748f141705..87c5057cf9b8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -61,13 +61,15 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 34_177_000 picoseconds. - Weight::from_parts(35_662_308, 0) + // Minimum execution time: 39_518_000 picoseconds. + Weight::from_parts(40_461_018, 0) .saturating_add(Weight::from_parts(0, 2543)) + // Standard Error: 98_154 + .saturating_add(Weight::from_parts(479_640, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -87,8 +89,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 35_975_000 picoseconds. - Weight::from_parts(36_510_000, 0) + // Minimum execution time: 41_243_000 picoseconds. + Weight::from_parts(42_293_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -109,8 +111,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 62_837_000 picoseconds. - Weight::from_parts(63_562_000, 0) + // Minimum execution time: 70_926_000 picoseconds. + Weight::from_parts(71_681_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) From d6f0f069cf0613f9c8c188474ba802b287bd8d08 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:09:28 +0000 Subject: [PATCH 65/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_parachains --- .../src/weights/pallet_bridge_parachains.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index 8eb291ea1452..3629d8797bf7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -65,11 +65,11 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 34_889_000 picoseconds. - Weight::from_parts(36_100_759, 0) + // Minimum execution time: 41_810_000 picoseconds. + Weight::from_parts(42_952_442, 0) .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 102_466 - .saturating_add(Weight::from_parts(178_820, 0).saturating_mul(p.into())) + // Standard Error: 108_155 + .saturating_add(Weight::from_parts(340_328, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -89,8 +89,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 36_501_000 picoseconds. - Weight::from_parts(37_266_000, 0) + // Minimum execution time: 43_567_000 picoseconds. + Weight::from_parts(44_746_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -111,8 +111,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 66_059_000 picoseconds. - Weight::from_parts(67_139_000, 0) + // Minimum execution time: 70_654_000 picoseconds. + Weight::from_parts(72_314_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) From 6f204396b260f336a6c4c6bb0be8b59847b5623b Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:09:54 +0000 Subject: [PATCH 66/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_relayers --- .../src/weights/pallet_bridge_relayers.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index f8bb983e80aa..b7318361c7d9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -49,15 +49,15 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_bridge_relayers::WeightInfo for WeightInfo { /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `278` + // Measured: `306` // Estimated: `3593` - // Minimum execution time: 44_224_000 picoseconds. - Weight::from_parts(44_905_000, 0) + // Minimum execution time: 53_924_000 picoseconds. + Weight::from_parts(54_736_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -72,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `131` // Estimated: `4714` - // Minimum execution time: 23_902_000 picoseconds. - Weight::from_parts(24_702_000, 0) + // Minimum execution time: 28_608_000 picoseconds. + Weight::from_parts(29_081_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `231` // Estimated: `4714` - // Minimum execution time: 24_469_000 picoseconds. - Weight::from_parts(25_176_000, 0) + // Minimum execution time: 29_738_000 picoseconds. + Weight::from_parts(30_242_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -102,21 +102,21 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `334` // Estimated: `4714` - // Minimum execution time: 27_518_000 picoseconds. - Weight::from_parts(28_068_000, 0) + // Minimum execution time: 33_174_000 picoseconds. + Weight::from_parts(33_992_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `3538` - // Minimum execution time: 5_484_000 picoseconds. - Weight::from_parts(5_718_000, 0) - .saturating_add(Weight::from_parts(0, 3538)) + // Estimated: `3567` + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(8_123_000, 0) + .saturating_add(Weight::from_parts(0, 3567)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } From 1837a23e072a099ba6730d2422950e35374267c8 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:10:21 +0000 Subject: [PATCH 67/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_grandpa --- .../src/weights/pallet_bridge_grandpa.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index 4ce57b2e5016..a9cc2411a9c6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yaoqqom-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -68,13 +68,13 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_grandpa::WeightInfo for WeightInfo Date: Thu, 15 Aug 2024 06:12:06 +0000 Subject: [PATCH 68/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_relayers --- .../src/weights/pallet_bridge_relayers.rs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs index 60d81dc3082a..74be73df1403 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -49,15 +49,15 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_bridge_relayers::WeightInfo for WeightInfo { /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `207` + // Measured: `272` // Estimated: `3593` - // Minimum execution time: 43_132_000 picoseconds. - Weight::from_parts(43_923_000, 0) + // Minimum execution time: 52_499_000 picoseconds. + Weight::from_parts(53_659_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -70,10 +70,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `61` + // Measured: `97` // Estimated: `4714` - // Minimum execution time: 22_765_000 picoseconds. - Weight::from_parts(23_576_000, 0) + // Minimum execution time: 28_706_000 picoseconds. + Weight::from_parts(29_434_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,10 +84,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `160` + // Measured: `197` // Estimated: `4714` - // Minimum execution time: 24_013_000 picoseconds. - Weight::from_parts(24_460_000, 0) + // Minimum execution time: 29_563_000 picoseconds. + Weight::from_parts(30_222_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -100,23 +100,23 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn slash_and_deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `263` + // Measured: `300` // Estimated: `4714` - // Minimum execution time: 26_946_000 picoseconds. - Weight::from_parts(27_485_000, 0) + // Minimum execution time: 32_618_000 picoseconds. + Weight::from_parts(33_528_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3538` - // Minimum execution time: 4_658_000 picoseconds. - Weight::from_parts(4_902_000, 0) - .saturating_add(Weight::from_parts(0, 3538)) + // Measured: `42` + // Estimated: `3567` + // Minimum execution time: 7_521_000 picoseconds. + Weight::from_parts(7_844_000, 0) + .saturating_add(Weight::from_parts(0, 3567)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } From 6d15dd4a6525d2e86e85c4ff2c0e7b1b3186b7b3 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:12:19 +0000 Subject: [PATCH 69/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_messages --- .../src/weights/pallet_bridge_messages.rs | 184 ++++++++++-------- 1 file changed, 104 insertions(+), 80 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs index 1033387b527e..492226d3ec2b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -50,88 +50,96 @@ pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 40_289_000 picoseconds. - Weight::from_parts(42_150_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 62_015_000 picoseconds. + Weight::from_parts(63_891_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 40_572_000 picoseconds. - Weight::from_parts(41_033_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 12_000 - .saturating_add(Weight::from_parts(11_710_588, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 62_034_000 picoseconds. + Weight::from_parts(63_355_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 8_231 + .saturating_add(Weight::from_parts(14_096_117, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 46_655_000 picoseconds. - Weight::from_parts(49_576_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 65_063_000 picoseconds. + Weight::from_parts(67_125_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 40_245_000 picoseconds. - Weight::from_parts(43_461_320, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 21 - .saturating_add(Weight::from_parts(2_246, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 58_688_000 picoseconds. + Weight::from_parts(61_404_716, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_249, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -139,21 +147,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3822` - // Minimum execution time: 32_001_000 picoseconds. - Weight::from_parts(32_842_000, 0) - .saturating_add(Weight::from_parts(0, 3822)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `710` + // Estimated: `5383` + // Minimum execution time: 53_123_000 picoseconds. + Weight::from_parts(54_417_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -161,21 +173,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3822` - // Minimum execution time: 33_287_000 picoseconds. - Weight::from_parts(33_769_000, 0) - .saturating_add(Weight::from_parts(0, 3822)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `710` + // Estimated: `5383` + // Minimum execution time: 55_140_000 picoseconds. + Weight::from_parts(56_456_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -183,31 +199,37 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `6086` - // Minimum execution time: 37_136_000 picoseconds. - Weight::from_parts(38_294_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `710` + // Estimated: `6144` + // Minimum execution time: 60_415_000 picoseconds. + Weight::from_parts(62_057_000, 0) + .saturating_add(Weight::from_parts(0, 6144)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -220,19 +242,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `653` - // Estimated: `52645` - // Minimum execution time: 55_942_000 picoseconds. - Weight::from_parts(60_615_769, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 14 - .saturating_add(Weight::from_parts(7_225, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `965` + // Estimated: `52674` + // Minimum execution time: 84_340_000 picoseconds. + Weight::from_parts(89_615_003, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 15 + .saturating_add(Weight::from_parts(7_574, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } From 8d09b620f04278cfbb400eb092c1a2bdd48232ff Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 06:17:15 +0000 Subject: [PATCH 70/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_grandpa --- .../src/weights/pallet_bridge_grandpa.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs index fa7efc260489..74bf144ac712 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yaoqqom-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,17 +64,15 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { + fn submit_finality_proof(p: u32, _v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `268 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 294_381_000 picoseconds. - Weight::from_parts(21_868_057, 0) + // Minimum execution time: 361_133_000 picoseconds. + Weight::from_parts(406_081_000, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 14_649 - .saturating_add(Weight::from_parts(40_681_012, 0).saturating_mul(p.into())) - // Standard Error: 48_883 - .saturating_add(Weight::from_parts(2_466_672, 0).saturating_mul(v.into())) + // Standard Error: 26_551 + .saturating_add(Weight::from_parts(40_356_046, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -92,8 +90,8 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Date: Thu, 15 Aug 2024 06:19:10 +0000 Subject: [PATCH 71/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_bridge_messages --- ...idge_messages_rococo_to_rococo_bulletin.rs | 166 +++++++++------- ...allet_bridge_messages_rococo_to_westend.rs | 184 ++++++++++-------- 2 files changed, 203 insertions(+), 147 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs index d0a7ed25363d..cde511fc749d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_rococo_bulletin.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -53,17 +53,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 36_836_000 picoseconds. - Weight::from_parts(37_858_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 61_893_000 picoseconds. + Weight::from_parts(63_358_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -71,21 +75,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 36_587_000 picoseconds. - Weight::from_parts(37_516_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 8_655 - .saturating_add(Weight::from_parts(11_649_169, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 61_612_000 picoseconds. + Weight::from_parts(62_758_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 13_521 + .saturating_add(Weight::from_parts(14_530_846, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -93,17 +101,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 42_157_000 picoseconds. - Weight::from_parts(43_105_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 66_862_000 picoseconds. + Weight::from_parts(69_531_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -111,21 +123,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 35_536_000 picoseconds. - Weight::from_parts(37_452_828, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(2_269, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 58_971_000 picoseconds. + Weight::from_parts(62_999_984, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_050, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -133,17 +149,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 25_800_000 picoseconds. - Weight::from_parts(26_666_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 43_066_000 picoseconds. + Weight::from_parts(43_878_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -151,17 +171,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 27_262_000 picoseconds. - Weight::from_parts(27_997_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 44_120_000 picoseconds. + Weight::from_parts(45_914_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -169,17 +193,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 26_992_000 picoseconds. - Weight::from_parts(27_921_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 44_930_000 picoseconds. + Weight::from_parts(46_111_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -187,7 +215,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -208,14 +240,14 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `813` - // Estimated: `52645` - // Minimum execution time: 55_509_000 picoseconds. - Weight::from_parts(59_826_763, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(7_565, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `1092` + // Estimated: `52674` + // Minimum execution time: 81_911_000 picoseconds. + Weight::from_parts(88_170_136, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 9 + .saturating_add(Weight::from_parts(7_233, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs index dc6c917c6d00..b27bbf4ff6c6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -50,90 +50,98 @@ pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 40_198_000 picoseconds. - Weight::from_parts(42_079_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 62_750_000 picoseconds. + Weight::from_parts(65_328_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_381_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 8_459 - .saturating_add(Weight::from_parts(11_710_167, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 62_275_000 picoseconds. + Weight::from_parts(63_714_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 13_139 + .saturating_add(Weight::from_parts(14_630_892, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 45_940_000 picoseconds. - Weight::from_parts(47_753_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 68_950_000 picoseconds. + Weight::from_parts(71_420_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 39_067_000 picoseconds. - Weight::from_parts(41_787_019, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 60_477_000 picoseconds. + Weight::from_parts(64_935_758, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_008, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -141,21 +149,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `3966` - // Minimum execution time: 33_107_000 picoseconds. - Weight::from_parts(34_364_000, 0) - .saturating_add(Weight::from_parts(0, 3966)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `779` + // Estimated: `5383` + // Minimum execution time: 52_939_000 picoseconds. + Weight::from_parts(54_637_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -163,21 +175,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `3966` - // Minimum execution time: 34_826_000 picoseconds. - Weight::from_parts(35_563_000, 0) - .saturating_add(Weight::from_parts(0, 3966)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `779` + // Estimated: `5383` + // Minimum execution time: 54_645_000 picoseconds. + Weight::from_parts(57_391_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -185,31 +201,37 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) - /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `6086` - // Minimum execution time: 38_725_000 picoseconds. - Weight::from_parts(39_727_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `779` + // Estimated: `6144` + // Minimum execution time: 59_581_000 picoseconds. + Weight::from_parts(61_657_000, 0) + .saturating_add(Weight::from_parts(0, 6144)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -222,20 +244,22 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `789` - // Estimated: `52645` - // Minimum execution time: 56_892_000 picoseconds. - Weight::from_parts(61_941_659, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(7_580, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `1140` + // Estimated: `52674` + // Minimum execution time: 83_530_000 picoseconds. + Weight::from_parts(91_297_344, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 11 + .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } From ffa8cdf1efc04ba737fdb0f0c885ce59adec4126 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:17:13 +0000 Subject: [PATCH 72/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=bridge-hub-westend --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_xcm_benchmarks::generic --- .../xcm/pallet_xcm_benchmarks_generic.rs | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index ba434ff29629..16c483a21817 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 58_505_000 picoseconds. - Weight::from_parts(60_437_000, 6196) + // Minimum execution time: 70_715_000 picoseconds. + Weight::from_parts(72_211_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 510_000 picoseconds. - Weight::from_parts(569_000, 0) + // Minimum execution time: 968_000 picoseconds. + Weight::from_parts(1_022_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 5_597_000 picoseconds. - Weight::from_parts(5_884_000, 3497) + // Minimum execution time: 7_718_000 picoseconds. + Weight::from_parts(7_894_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_320_000 picoseconds. - Weight::from_parts(5_594_000, 0) + // Minimum execution time: 7_662_000 picoseconds. + Weight::from_parts(7_937_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_164_000 picoseconds. - Weight::from_parts(1_227_000, 0) + // Minimum execution time: 1_699_000 picoseconds. + Weight::from_parts(1_783_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 528_000 picoseconds. - Weight::from_parts(586_000, 0) + // Minimum execution time: 977_000 picoseconds. + Weight::from_parts(1_045_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 509_000 picoseconds. - Weight::from_parts(571_000, 0) + // Minimum execution time: 971_000 picoseconds. + Weight::from_parts(1_030_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(546_000, 0) + // Minimum execution time: 958_000 picoseconds. + Weight::from_parts(996_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 560_000 picoseconds. - Weight::from_parts(600_000, 0) + // Minimum execution time: 992_000 picoseconds. + Weight::from_parts(1_056_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 514_000 picoseconds. - Weight::from_parts(558_000, 0) + // Minimum execution time: 975_000 picoseconds. + Weight::from_parts(1_026_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 55_871_000 picoseconds. - Weight::from_parts(57_172_000, 6196) + // Minimum execution time: 67_236_000 picoseconds. + Weight::from_parts(68_712_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_487_000 picoseconds. - Weight::from_parts(8_800_000, 3555) + // Minimum execution time: 10_890_000 picoseconds. + Weight::from_parts(11_223_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 528_000 picoseconds. - Weight::from_parts(569_000, 0) + // Minimum execution time: 959_000 picoseconds. + Weight::from_parts(1_018_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 19_803_000 picoseconds. - Weight::from_parts(20_368_000, 3503) + // Minimum execution time: 25_162_000 picoseconds. + Weight::from_parts(25_621_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_185_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 2_949_000 picoseconds. + Weight::from_parts(3_119_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822_000 picoseconds. - Weight::from_parts(928_000, 0) + // Minimum execution time: 1_329_000 picoseconds. + Weight::from_parts(1_410_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 603_000 picoseconds. - Weight::from_parts(643_000, 0) + // Minimum execution time: 1_063_000 picoseconds. + Weight::from_parts(1_101_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 503_000 picoseconds. - Weight::from_parts(580_000, 0) + // Minimum execution time: 991_000 picoseconds. + Weight::from_parts(1_041_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 534_000 picoseconds. - Weight::from_parts(577_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(998_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 694_000 picoseconds. - Weight::from_parts(745_000, 0) + // Minimum execution time: 1_100_000 picoseconds. + Weight::from_parts(1_180_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 61_083_000 picoseconds. - Weight::from_parts(62_214_000, 6196) + // Minimum execution time: 71_203_000 picoseconds. + Weight::from_parts(73_644_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_261_000 picoseconds. - Weight::from_parts(3_483_000, 0) + // Minimum execution time: 4_018_000 picoseconds. + Weight::from_parts(4_267_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 56_270_000 picoseconds. - Weight::from_parts(57_443_000, 6196) + // Minimum execution time: 67_893_000 picoseconds. + Weight::from_parts(69_220_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,44 +311,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 565_000 picoseconds. - Weight::from_parts(628_000, 0) + // Minimum execution time: 980_000 picoseconds. + Weight::from_parts(1_043_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 496_000 picoseconds. - Weight::from_parts(563_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(981_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 518_000 picoseconds. - Weight::from_parts(557_000, 0) + // Minimum execution time: 930_000 picoseconds. + Weight::from_parts(962_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeRococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `225` - // Estimated: `6165` - // Minimum execution time: 36_288_000 picoseconds. - Weight::from_parts(37_707_751, 6165) - // Standard Error: 124 - .saturating_add(Weight::from_parts(51_290, 0).saturating_mul(x.into())) + // Measured: `552` + // Estimated: `6492` + // Minimum execution time: 56_762_000 picoseconds. + Weight::from_parts(58_320_046, 6492) + // Standard Error: 162 + .saturating_add(Weight::from_parts(51_730, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 485_000 picoseconds. - Weight::from_parts(540_000, 0) + // Minimum execution time: 971_000 picoseconds. + Weight::from_parts(1_018_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 542_000 picoseconds. - Weight::from_parts(586_000, 0) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(1_026_000, 0) } } From 57e45ee9e4553baecddabbab51b1354a21851345 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:17:42 +0000 Subject: [PATCH 73/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=asset-hub-rococo --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_bridge_hub_router --- .../weights/pallet_xcm_bridge_hub_router.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 4a29ea81f5c1..00ecf239428f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `ToWestendXcmRouter::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `154` + // Measured: `153` // Estimated: `5487` - // Minimum execution time: 8_078_000 picoseconds. - Weight::from_parts(8_455_000, 0) + // Minimum execution time: 12_993_000 picoseconds. + Weight::from_parts(13_428_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `5487` - // Minimum execution time: 4_291_000 picoseconds. - Weight::from_parts(4_548_000, 0) + // Minimum execution time: 6_305_000 picoseconds. + Weight::from_parts(6_536_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } From c6efc1f79fd0f3e4cc8a3dd56781b25ee7352cb8 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:17:45 +0000 Subject: [PATCH 74/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=asset-hub-westend --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_bridge_hub_router --- .../weights/pallet_xcm_bridge_hub_router.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 5326173691aa..c0898012e9f3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `ToRococoXcmRouter::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `226` + // Measured: `225` // Estimated: `5487` - // Minimum execution time: 8_363_000 picoseconds. - Weight::from_parts(8_620_000, 0) + // Minimum execution time: 13_483_000 picoseconds. + Weight::from_parts(13_862_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `111` // Estimated: `5487` - // Minimum execution time: 3_436_000 picoseconds. - Weight::from_parts(3_586_000, 0) + // Minimum execution time: 5_078_000 picoseconds. + Weight::from_parts(5_233_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } From 6074e6282668d204c7c3ee653f42a82af7ae9b93 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:18:08 +0000 Subject: [PATCH 75/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=bridge-hub-rococo --runtime_dir=bridge-hubs --target_dir=cumulus --pallet=pallet_xcm_benchmarks::generic --- .../xcm/pallet_xcm_benchmarks_generic.rs | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 9c58072d402c..9a9137c18093 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_119_000 picoseconds. - Weight::from_parts(61_871_000, 6196) + // Minimum execution time: 70_133_000 picoseconds. + Weight::from_parts(71_765_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 998_000 picoseconds. - Weight::from_parts(1_038_000, 0) + // Minimum execution time: 959_000 picoseconds. + Weight::from_parts(996_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 6_327_000 picoseconds. - Weight::from_parts(6_520_000, 3497) + // Minimum execution time: 7_537_000 picoseconds. + Weight::from_parts(7_876_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_783_000 picoseconds. - Weight::from_parts(7_117_000, 0) + // Minimum execution time: 7_774_000 picoseconds. + Weight::from_parts(7_895_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_589_000 picoseconds. - Weight::from_parts(1_655_000, 0) + // Minimum execution time: 1_577_000 picoseconds. + Weight::from_parts(1_622_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_013_000 picoseconds. - Weight::from_parts(1_045_000, 0) + // Minimum execution time: 973_000 picoseconds. + Weight::from_parts(1_008_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_005_000 picoseconds. - Weight::from_parts(1_044_000, 0) + // Minimum execution time: 1_027_000 picoseconds. + Weight::from_parts(1_052_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 964_000 picoseconds. - Weight::from_parts(1_011_000, 0) + // Minimum execution time: 953_000 picoseconds. + Weight::from_parts(992_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_005_000 picoseconds. - Weight::from_parts(1_027_000, 0) + // Minimum execution time: 949_000 picoseconds. + Weight::from_parts(1_020_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 980_000 picoseconds. - Weight::from_parts(1_009_000, 0) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(1_032_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_726_000 picoseconds. - Weight::from_parts(59_300_000, 6196) + // Minimum execution time: 66_663_000 picoseconds. + Weight::from_parts(67_728_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_962_000 picoseconds. - Weight::from_parts(9_519_000, 3555) + // Minimum execution time: 11_074_000 picoseconds. + Weight::from_parts(11_439_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 999_000 picoseconds. - Weight::from_parts(1_035_000, 0) + // Minimum execution time: 943_000 picoseconds. + Weight::from_parts(1_021_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 20_313_000 picoseconds. - Weight::from_parts(21_000_000, 3503) + // Minimum execution time: 25_123_000 picoseconds. + Weight::from_parts(25_687_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_820_000 picoseconds. - Weight::from_parts(2_949_000, 0) + // Minimum execution time: 2_868_000 picoseconds. + Weight::from_parts(3_124_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_293_000 picoseconds. - Weight::from_parts(1_354_000, 0) + // Minimum execution time: 1_378_000 picoseconds. + Weight::from_parts(1_458_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_076_000 picoseconds. - Weight::from_parts(1_114_000, 0) + // Minimum execution time: 1_036_000 picoseconds. + Weight::from_parts(1_105_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_014_000 picoseconds. - Weight::from_parts(1_055_000, 0) + // Minimum execution time: 945_000 picoseconds. + Weight::from_parts(1_021_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 979_000 picoseconds. - Weight::from_parts(1_019_000, 0) + // Minimum execution time: 931_000 picoseconds. + Weight::from_parts(1_006_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_161_000 picoseconds. - Weight::from_parts(1_208_000, 0) + // Minimum execution time: 1_139_000 picoseconds. + Weight::from_parts(1_206_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 62_250_000 picoseconds. - Weight::from_parts(64_477_000, 6196) + // Minimum execution time: 72_884_000 picoseconds. + Weight::from_parts(74_331_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_286_000 picoseconds. - Weight::from_parts(4_476_000, 0) + // Minimum execution time: 4_432_000 picoseconds. + Weight::from_parts(4_542_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 58_253_000 picoseconds. - Weight::from_parts(59_360_000, 6196) + // Minimum execution time: 67_102_000 picoseconds. + Weight::from_parts(68_630_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,44 +311,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_026_000 picoseconds. - Weight::from_parts(1_065_000, 0) + // Minimum execution time: 995_000 picoseconds. + Weight::from_parts(1_057_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 993_000 picoseconds. - Weight::from_parts(1_015_000, 0) + // Minimum execution time: 956_000 picoseconds. + Weight::from_parts(1_021_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 966_000 picoseconds. - Weight::from_parts(999_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(986_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeWestendMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeWestendMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `190` - // Estimated: `6130` - // Minimum execution time: 37_014_000 picoseconds. - Weight::from_parts(38_096_655, 6130) - // Standard Error: 61 - .saturating_add(Weight::from_parts(45_146, 0).saturating_mul(x.into())) + // Measured: `589` + // Estimated: `6529` + // Minimum execution time: 58_111_000 picoseconds. + Weight::from_parts(59_123_071, 6529) + // Standard Error: 167 + .saturating_add(Weight::from_parts(43_658, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 996_000 picoseconds. - Weight::from_parts(1_025_000, 0) + // Minimum execution time: 950_000 picoseconds. + Weight::from_parts(1_002_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_001_000 picoseconds. - Weight::from_parts(1_044_000, 0) + // Minimum execution time: 963_000 picoseconds. + Weight::from_parts(1_012_000, 0) } } From 048955fea6486fbb8e77e76ca2fb1dbe4c796c7f Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:19:23 +0000 Subject: [PATCH 76/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=asset-hub-westend --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_benchmarks::fungible --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index f7891aedc496..0aeae3184627 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 32_612_000 picoseconds. - Weight::from_parts(33_359_000, 3593) + // Minimum execution time: 32_651_000 picoseconds. + Weight::from_parts(33_225_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 41_144_000 picoseconds. - Weight::from_parts(41_788_000, 6196) + // Minimum execution time: 41_059_000 picoseconds. + Weight::from_parts(41_730_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 101_340_000 picoseconds. - Weight::from_parts(103_686_000, 8799) + // Minimum execution time: 102_780_000 picoseconds. + Weight::from_parts(105_302_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -99,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_682_000 picoseconds. - Weight::from_parts(1_734_000, 0) + // Minimum execution time: 1_124_000 picoseconds. + Weight::from_parts(1_201_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 107_335_000 picoseconds. - Weight::from_parts(109_665_000, 6196) + // Minimum execution time: 109_024_000 picoseconds. + Weight::from_parts(111_406_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -131,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_345_000 picoseconds. - Weight::from_parts(3_548_000, 0) + // Minimum execution time: 2_887_000 picoseconds. + Weight::from_parts(3_081_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -140,8 +140,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_560_000 picoseconds. - Weight::from_parts(26_779_000, 3593) + // Minimum execution time: 25_234_000 picoseconds. + Weight::from_parts(25_561_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 84_453_000 picoseconds. - Weight::from_parts(86_755_000, 6196) + // Minimum execution time: 83_416_000 picoseconds. + Weight::from_parts(85_683_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -190,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 50_463_000 picoseconds. - Weight::from_parts(51_587_000, 3610) + // Minimum execution time: 49_271_000 picoseconds. + Weight::from_parts(51_019_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } From e7c5d9dc8c924504c595c7ded0e5bf91c6bc3ff5 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:20:22 +0000 Subject: [PATCH 77/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=asset-hub-rococo --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_benchmarks::generic --- .../xcm/pallet_xcm_benchmarks_generic.rs | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index bee6bcdf21cf..f6a883c03e9d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 440_298_000 picoseconds. - Weight::from_parts(446_508_000, 6196) + // Minimum execution time: 99_552_000 picoseconds. + Weight::from_parts(101_720_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_313_000 picoseconds. - Weight::from_parts(3_422_000, 0) + // Minimum execution time: 659_000 picoseconds. + Weight::from_parts(706_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 9_691_000 picoseconds. - Weight::from_parts(9_948_000, 3568) + // Minimum execution time: 9_665_000 picoseconds. + Weight::from_parts(9_878_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(11_085_000, 0) + // Minimum execution time: 6_959_000 picoseconds. + Weight::from_parts(7_111_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_438_000 picoseconds. - Weight::from_parts(3_577_000, 0) + // Minimum execution time: 2_682_000 picoseconds. + Weight::from_parts(2_799_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_126_000 picoseconds. - Weight::from_parts(2_243_000, 0) + // Minimum execution time: 656_000 picoseconds. + Weight::from_parts(683_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_126_000 picoseconds. - Weight::from_parts(2_207_000, 0) + // Minimum execution time: 687_000 picoseconds. + Weight::from_parts(719_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_105_000 picoseconds. - Weight::from_parts(2_193_000, 0) + // Minimum execution time: 588_000 picoseconds. + Weight::from_parts(653_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_999_000 picoseconds. - Weight::from_parts(3_056_000, 0) + // Minimum execution time: 690_000 picoseconds. + Weight::from_parts(714_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_091_000 picoseconds. - Weight::from_parts(2_176_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(710_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 55_728_000 picoseconds. - Weight::from_parts(56_704_000, 6196) + // Minimum execution time: 67_374_000 picoseconds. + Weight::from_parts(68_899_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_839_000 picoseconds. - Weight::from_parts(13_457_000, 3625) + // Minimum execution time: 12_896_000 picoseconds. + Weight::from_parts(13_191_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_116_000 picoseconds. - Weight::from_parts(2_219_000, 0) + // Minimum execution time: 634_000 picoseconds. + Weight::from_parts(677_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_891_000 picoseconds. - Weight::from_parts(25_583_000, 3610) + // Minimum execution time: 28_197_000 picoseconds. + Weight::from_parts(28_752_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_968_000 picoseconds. - Weight::from_parts(4_122_000, 0) + // Minimum execution time: 2_678_000 picoseconds. + Weight::from_parts(2_803_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 136_220_000 picoseconds. - Weight::from_parts(137_194_000, 0) + // Minimum execution time: 22_806_000 picoseconds. + Weight::from_parts(23_217_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_343_000 picoseconds. - Weight::from_parts(12_635_000, 0) + // Minimum execution time: 6_221_000 picoseconds. + Weight::from_parts(6_347_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_237_000 picoseconds. - Weight::from_parts(2_315_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(676_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_094_000 picoseconds. - Weight::from_parts(2_231_000, 0) + // Minimum execution time: 621_000 picoseconds. + Weight::from_parts(678_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_379_000 picoseconds. - Weight::from_parts(2_455_000, 0) + // Minimum execution time: 770_000 picoseconds. + Weight::from_parts(829_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 60_734_000 picoseconds. - Weight::from_parts(61_964_000, 6196) + // Minimum execution time: 71_654_000 picoseconds. + Weight::from_parts(73_329_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_500_000 picoseconds. - Weight::from_parts(5_720_000, 0) + // Minimum execution time: 3_999_000 picoseconds. + Weight::from_parts(4_179_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 55_767_000 picoseconds. - Weight::from_parts(56_790_000, 6196) + // Minimum execution time: 66_722_000 picoseconds. + Weight::from_parts(68_812_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_201_000 picoseconds. - Weight::from_parts(2_291_000, 0) + // Minimum execution time: 718_000 picoseconds. + Weight::from_parts(745_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_164_000 picoseconds. - Weight::from_parts(2_241_000, 0) + // Minimum execution time: 623_000 picoseconds. + Weight::from_parts(682_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_127_000 picoseconds. - Weight::from_parts(2_236_000, 0) + // Minimum execution time: 664_000 picoseconds. + Weight::from_parts(696_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -334,22 +334,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 4_275_000 picoseconds. - Weight::from_parts(4_381_000, 1489) + // Minimum execution time: 2_495_000 picoseconds. + Weight::from_parts(2_604_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_132_000 picoseconds. - Weight::from_parts(2_216_000, 0) + // Minimum execution time: 645_000 picoseconds. + Weight::from_parts(673_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_265_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 643_000 picoseconds. + Weight::from_parts(701_000, 0) } } From b30bd992efb68e5f7f015616365d57df25fb6344 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:20:51 +0000 Subject: [PATCH 78/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=asset-hub-rococo --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_benchmarks::fungible --- .../xcm/pallet_xcm_benchmarks_fungible.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 3d6ae6ddd1d2..7478ba8893c1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 34_180_000 picoseconds. - Weight::from_parts(34_745_000, 3593) + // Minimum execution time: 34_364_000 picoseconds. + Weight::from_parts(35_040_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_638_000 picoseconds. - Weight::from_parts(43_454_000, 6196) + // Minimum execution time: 42_755_000 picoseconds. + Weight::from_parts(43_650_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 102_916_000 picoseconds. - Weight::from_parts(105_699_000, 8799) + // Minimum execution time: 103_037_000 picoseconds. + Weight::from_parts(105_732_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -99,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_805_000 picoseconds. - Weight::from_parts(1_901_000, 0) + // Minimum execution time: 1_095_000 picoseconds. + Weight::from_parts(1_220_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 108_018_000 picoseconds. - Weight::from_parts(110_310_000, 6196) + // Minimum execution time: 108_117_000 picoseconds. + Weight::from_parts(110_416_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -131,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_507_000 picoseconds. - Weight::from_parts(3_724_000, 0) + // Minimum execution time: 2_907_000 picoseconds. + Weight::from_parts(3_050_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -140,8 +140,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 26_269_000 picoseconds. - Weight::from_parts(26_706_000, 3593) + // Minimum execution time: 24_965_000 picoseconds. + Weight::from_parts(25_687_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 84_759_000 picoseconds. - Weight::from_parts(86_157_000, 6196) + // Minimum execution time: 83_312_000 picoseconds. + Weight::from_parts(85_463_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -190,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 50_876_000 picoseconds. - Weight::from_parts(51_512_000, 3610) + // Minimum execution time: 49_874_000 picoseconds. + Weight::from_parts(51_165_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } From fc57334ab27c1c698731db94dfd19bacce34c25d Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 15 Aug 2024 08:23:08 +0000 Subject: [PATCH 79/95] ".git/.scripts/commands/bench/bench.sh" --subcommand=xcm --runtime=asset-hub-westend --runtime_dir=assets --target_dir=cumulus --pallet=pallet_xcm_benchmarks::generic --- .../xcm/pallet_xcm_benchmarks_generic.rs | 147 +++++++++--------- 1 file changed, 74 insertions(+), 73 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 127bc173c103..98ecd7bd3092 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -1,24 +1,25 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -67,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 415_033_000 picoseconds. - Weight::from_parts(429_573_000, 6196) + // Minimum execution time: 100_823_000 picoseconds. + Weight::from_parts(103_071_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -76,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_193_000 picoseconds. - Weight::from_parts(3_620_000, 0) + // Minimum execution time: 600_000 picoseconds. + Weight::from_parts(686_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -85,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 8_045_000 picoseconds. - Weight::from_parts(8_402_000, 3568) + // Minimum execution time: 8_226_000 picoseconds. + Weight::from_parts(8_650_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_827_000 picoseconds. - Weight::from_parts(10_454_000, 0) + // Minimum execution time: 7_131_000 picoseconds. + Weight::from_parts(7_600_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_330_000 picoseconds. - Weight::from_parts(3_677_000, 0) + // Minimum execution time: 2_589_000 picoseconds. + Weight::from_parts(2_705_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_947_000 picoseconds. - Weight::from_parts(2_083_000, 0) + // Minimum execution time: 667_000 picoseconds. + Weight::from_parts(744_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_993_000, 0) + // Minimum execution time: 646_000 picoseconds. + Weight::from_parts(720_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_048_000, 0) + // Minimum execution time: 633_000 picoseconds. + Weight::from_parts(669_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_683_000 picoseconds. - Weight::from_parts(3_064_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(726_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_893_000 picoseconds. - Weight::from_parts(2_159_000, 0) + // Minimum execution time: 615_000 picoseconds. + Weight::from_parts(675_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -158,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 53_116_000 picoseconds. - Weight::from_parts(54_154_000, 6196) + // Minimum execution time: 67_236_000 picoseconds. + Weight::from_parts(69_899_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -169,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_381_000 picoseconds. - Weight::from_parts(12_693_000, 3625) + // Minimum execution time: 12_976_000 picoseconds. + Weight::from_parts(13_357_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -178,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_933_000 picoseconds. - Weight::from_parts(1_983_000, 0) + // Minimum execution time: 633_000 picoseconds. + Weight::from_parts(685_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -199,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_251_000 picoseconds. - Weight::from_parts(24_890_000, 3610) + // Minimum execution time: 28_707_000 picoseconds. + Weight::from_parts(31_790_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -210,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_850_000 picoseconds. - Weight::from_parts(4_082_000, 0) + // Minimum execution time: 2_670_000 picoseconds. + Weight::from_parts(2_833_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_248_000 picoseconds. - Weight::from_parts(124_454_000, 0) + // Minimum execution time: 23_459_000 picoseconds. + Weight::from_parts(23_817_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_457_000 picoseconds. - Weight::from_parts(12_060_000, 0) + // Minimum execution time: 6_197_000 picoseconds. + Weight::from_parts(6_338_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_959_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(715_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(694_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_149_000 picoseconds. - Weight::from_parts(2_394_000, 0) + // Minimum execution time: 810_000 picoseconds. + Weight::from_parts(858_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -269,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 58_011_000 picoseconds. - Weight::from_parts(59_306_000, 6196) + // Minimum execution time: 73_136_000 picoseconds. + Weight::from_parts(75_314_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -278,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_031_000 picoseconds. - Weight::from_parts(5_243_000, 0) + // Minimum execution time: 4_515_000 picoseconds. + Weight::from_parts(4_768_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -301,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 53_078_000 picoseconds. - Weight::from_parts(54_345_000, 6196) + // Minimum execution time: 68_072_000 picoseconds. + Weight::from_parts(69_866_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -310,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_936_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(736_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 618_000 picoseconds. + Weight::from_parts(681_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_882_000 picoseconds. - Weight::from_parts(1_977_000, 0) + // Minimum execution time: 647_000 picoseconds. + Weight::from_parts(672_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -333,22 +334,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 3_912_000 picoseconds. - Weight::from_parts(4_167_000, 1489) + // Minimum execution time: 2_496_000 picoseconds. + Weight::from_parts(2_617_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_911_000 picoseconds. - Weight::from_parts(1_971_000, 0) + // Minimum execution time: 637_000 picoseconds. + Weight::from_parts(675_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_990_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 607_000 picoseconds. + Weight::from_parts(683_000, 0) } } From f57769f9a3ff525277d829fd19db770fbe38fd0d Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 22:12:39 +0200 Subject: [PATCH 80/95] Update bridges/modules/xcm-bridge-hub-router/src/lib.rs Co-authored-by: Francisco Aguirre --- bridges/modules/xcm-bridge-hub-router/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 2cf98fd180b8..39ea504fbb3e 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -165,7 +165,7 @@ pub mod pallet { /// to detect congestion: /// /// ```nocompile - /// ThisChain --- Local XCM chanel --> Sibling Bridge Hub ------ + /// ThisChain --- Local XCM channel --> Sibling Bridge Hub ------ /// | | /// | | /// | | From afc560d6f3ed9ed76c40573a59d5afa93c605ed7 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 22:13:25 +0200 Subject: [PATCH 81/95] Update bridges/modules/xcm-bridge-hub/src/exporter.rs Co-authored-by: Francisco Aguirre --- bridges/modules/xcm-bridge-hub/src/exporter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index e31b47a8297e..b42ae1e267f4 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -214,7 +214,7 @@ impl, I: 'static> Pallet { // hard limit for that like other XCM queues have // check if the lane is already suspended. If it is, do nothing. We still accept new - // messages to the suspended bridge, hoping that it'll be actually suspended soon + // messages to the suspended bridge, hoping that it'll be actually resumed soon if bridge.state == BridgeState::Suspended { return } From c408b615e2f009b307b869a6bd80201de8b1f143 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 22:14:44 +0200 Subject: [PATCH 82/95] Update bridges/modules/xcm-bridge-hub/src/lib.rs Co-authored-by: Francisco Aguirre --- bridges/modules/xcm-bridge-hub/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index edd83d09269d..90249c70e135 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -716,7 +716,7 @@ pub mod pallet { pub struct GenesisConfig, I: 'static = ()> { /// Opened bridges. /// - /// Keep in mind that we are **NOT** reserving any amount for the bridges, opened at + /// Keep in mind that we are **NOT** reserving any amount for the bridges opened at /// genesis. We are **NOT** opening lanes, used by this bridge. It all must be done using /// other pallets genesis configuration or some other means. pub opened_bridges: Vec<(Location, InteriorLocation)>, From 507d99360aeac846f850efd74095c247266d1d90 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 23:07:52 +0200 Subject: [PATCH 83/95] Doc nit --- bridges/modules/grandpa/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index c62951b74656..dff4b98fd919 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -117,7 +117,7 @@ pub mod pallet { /// /// However, if the bridged chain gets compromised, its validators may generate as many /// "free" headers as they want. And they may fill the whole block (at this chain) for - /// free. This constants limits number of calls that we may refund in a single block. + /// free. This constant limits number of calls that we may refund in a single block. /// All calls above this limit are accepted, but are not refunded. #[pallet::constant] type MaxFreeHeadersPerBlock: Get; From ede990bf3912275b04029d9bf1dfb100360c05f3 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 15 Aug 2024 23:31:09 +0200 Subject: [PATCH 84/95] Added `#[serde(skip)]` for phantom --- bridges/modules/messages/src/lib.rs | 1 + bridges/modules/parachains/src/lib.rs | 1 + bridges/modules/xcm-bridge-hub/src/lib.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index d3368657182b..c82da9424236 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -536,6 +536,7 @@ pub mod pallet { /// Opened lanes. pub opened_lanes: Vec, /// Dummy marker. + #[serde(skip)] pub phantom: sp_std::marker::PhantomData, } diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index f30af9c482c5..3dd5be47a41c 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -735,6 +735,7 @@ pub mod pallet { /// Initial pallet owner. pub owner: Option, /// Dummy marker. + #[serde(skip)] pub phantom: sp_std::marker::PhantomData, } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 90249c70e135..a39f0a3dabfc 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -721,6 +721,7 @@ pub mod pallet { /// other pallets genesis configuration or some other means. pub opened_bridges: Vec<(Location, InteriorLocation)>, /// Dummy marker. + #[serde(skip)] pub phantom: sp_std::marker::PhantomData<(T, I)>, } From 617c365a7eaf12a6d2f10082f9ccb9e8a53c95c7 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 16 Aug 2024 00:26:27 +0200 Subject: [PATCH 85/95] Update bridges/modules/xcm-bridge-hub/src/lib.rs Co-authored-by: Francisco Aguirre --- bridges/modules/xcm-bridge-hub/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index a39f0a3dabfc..5b91660a33c8 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -722,7 +722,7 @@ pub mod pallet { pub opened_bridges: Vec<(Location, InteriorLocation)>, /// Dummy marker. #[serde(skip)] - pub phantom: sp_std::marker::PhantomData<(T, I)>, + _phantom: sp_std::marker::PhantomData<(T, I)>, } #[pallet::genesis_build] From ea9adbb3d3d717fbb38c66a8bfb675a64bf1e399 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 16 Aug 2024 00:05:32 +0200 Subject: [PATCH 86/95] Removed `#[pallet::getter(fn lane_to_bridge)]` --- bridges/modules/xcm-bridge-hub/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 5b91660a33c8..4eddb5bb7d8d 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -634,7 +634,7 @@ pub mod pallet { // check `BridgeId` points to the same `LaneId` and vice versa. ensure!( - Some(bridge_id) == Self::lane_to_bridge(bridge.lane_id), + Some(bridge_id) == LaneToBridge::::get(bridge.lane_id), "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!" ); @@ -682,7 +682,7 @@ pub mod pallet { for lane_id in pallet_bridge_messages::InboundLanes::::iter_keys() { log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `InboundLanes`'s lane_id: {lane_id:?}..."); ensure!( - Self::lane_to_bridge(lane_id).is_some(), + LaneToBridge::::get(lane_id).is_some(), "Found `LaneToBridge` inconsistency for `InboundLanes`'s lane_id - missing mapping!" ); } @@ -691,7 +691,7 @@ pub mod pallet { for lane_id in pallet_bridge_messages::OutboundLanes::::iter_keys() { log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `OutboundLanes`'s lane_id: {lane_id:?}..."); ensure!( - Self::lane_to_bridge(lane_id).is_some(), + LaneToBridge::::get(lane_id).is_some(), "Found `LaneToBridge` inconsistency for `OutboundLanes`'s lane_id - missing mapping!" ); } @@ -707,7 +707,6 @@ pub mod pallet { StorageMap<_, Identity, BridgeId, BridgeOf>; /// All registered `lane_id` and `bridge_id` mappings. #[pallet::storage] - #[pallet::getter(fn lane_to_bridge)] pub type LaneToBridge, I: 'static = ()> = StorageMap<_, Identity, LaneId, BridgeId>; From fa60d262f4580cb0802dadefc079ed1508ec6d92 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 16 Aug 2024 00:29:54 +0200 Subject: [PATCH 87/95] Apply _phantom --- bridges/modules/messages/src/lib.rs | 2 +- bridges/modules/parachains/src/lib.rs | 2 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index c82da9424236..10ad6bbdd79f 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -537,7 +537,7 @@ pub mod pallet { pub opened_lanes: Vec, /// Dummy marker. #[serde(skip)] - pub phantom: sp_std::marker::PhantomData, + _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 3dd5be47a41c..227171ba25a6 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -736,7 +736,7 @@ pub mod pallet { pub owner: Option, /// Dummy marker. #[serde(skip)] - pub phantom: sp_std::marker::PhantomData, + _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 4eddb5bb7d8d..7890d4c7d1cb 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -721,7 +721,7 @@ pub mod pallet { pub opened_bridges: Vec<(Location, InteriorLocation)>, /// Dummy marker. #[serde(skip)] - _phantom: sp_std::marker::PhantomData<(T, I)>, + _phantom: sp_std::marker::PhantomData<(T, I)>, } #[pallet::genesis_build] From afa2956dc91472dc4b714a642e5350840562de9f Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 16 Aug 2024 09:47:39 +0200 Subject: [PATCH 88/95] Apply _phantom - revert pub --- bridges/modules/messages/src/lib.rs | 2 +- bridges/modules/parachains/src/lib.rs | 2 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 10ad6bbdd79f..a2c44ed7c432 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -537,7 +537,7 @@ pub mod pallet { pub opened_lanes: Vec, /// Dummy marker. #[serde(skip)] - _phantom: sp_std::marker::PhantomData, + pub _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 227171ba25a6..bbf6a6600d56 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -736,7 +736,7 @@ pub mod pallet { pub owner: Option, /// Dummy marker. #[serde(skip)] - _phantom: sp_std::marker::PhantomData, + pub _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 7890d4c7d1cb..5c657d82dc19 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -721,7 +721,7 @@ pub mod pallet { pub opened_bridges: Vec<(Location, InteriorLocation)>, /// Dummy marker. #[serde(skip)] - _phantom: sp_std::marker::PhantomData<(T, I)>, + pub _phantom: sp_std::marker::PhantomData<(T, I)>, } #[pallet::genesis_build] From b974795ba8984471cb76b254ee41e485c8d0ce0e Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 16 Aug 2024 10:00:30 +0200 Subject: [PATCH 89/95] Updated doc example --- bridges/modules/xcm-bridge-hub/src/lib.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 5c657d82dc19..532426c1765a 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -113,24 +113,29 @@ //! //! Example of opening a bridge between some random parachains from Polkadot and Kusama: //! -//! 1. The local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs to its -//! sovereign account on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, and the -//! existential deposit. +//! 0. Let's have: +//! - BridgeHubPolkadot with `UniversalLocation` = `[GlobalConsensus(Polkadot), Parachain(1002)]` +//! - BridgeHubKusama with `UniversalLocation` = `[GlobalConsensus(Kusama), Parachain(1002)]` +//! 1. The Polkadot local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs +//! to its sovereign account on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, +//! and the existential deposit. //! 2. Send a call to the BridgeHubPolkadot from the local sibling parachain: `Location::new(1, //! Parachain(1234))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, //! XcmOverBridgeHubKusama::open_bridge( VersionedInteriorLocation::V4([GlobalConsensus(Kusama), //! Parachain(4567)].into()), ); ) ``` //! 3. Check the stored bridge metadata and generated `LaneId`. -//! 4. The local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to its -//! sovereign account +//! 4. The Kusama local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to +//! its sovereign account //! on BridgeHubKusama to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. //! 5. Send a call to the BridgeHubKusama from the local sibling parachain: `Location::new(1, //! Parachain(4567))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, //! XcmOverBridgeHubKusama::open_bridge( //! VersionedInteriorLocation::V4([GlobalConsensus(Polkadot), Parachain(1234)].into()), ); ) ``` //! 6. Check the stored bridge metadata and generated `LaneId`. -//! 7. Run the bridge messages relayer for `LaneId`. -//! 8. Send messages from both sides. +//! 7. Both `LaneId`s from steps 3 and 6 must be the same (see above _Concept of `lane` and +//! `LaneId`_). +//! 8. Run the bridge messages relayer for `LaneId`. +//! 9. Send messages from both sides. //! //! The opening bridge holds the configured `BridgeDeposit` from the origin's sovereign account, but //! this deposit is returned when the bridge is closed with `fn close_bridge`. From 351ae31d993475524afdc89a78a194065313a194 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 16:04:55 +0200 Subject: [PATCH 90/95] prdoc draft --- prdoc/pr_4949.prdoc | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 prdoc/pr_4949.prdoc diff --git a/prdoc/pr_4949.prdoc b/prdoc/pr_4949.prdoc new file mode 100644 index 000000000000..583cbc52fa9f --- /dev/null +++ b/prdoc/pr_4949.prdoc @@ -0,0 +1,64 @@ +title: "[bridges-v2] Permissionless lanes" + +doc: +- audience: Runtime Dev + description: | + This PR adds support for opening and closing dynamic, also known as permissionless, lanes. + This means that authorized origins (relay chain, sibling parachains) + can open and close bridges with other bridged (substrate-like) consensuses supported by Bridge Hubs. + The Bridge Hubs, particularly the `pallet-xcm-bridge-hub`, introduce new extrinsics `open_bridge` and `close_bridge`, + which can be called using `xcm::Transact`. + +crates: +- name: bridge-runtime-common + bump: major +- name: bp-bridge-hub-rococo + bump: minor +- name: bp-bridge-hub-westend + bump: minor +- name: pallet-bridge-grandpa + bump: major +- name: pallet-bridge-messages + bump: major +- name: pallet-bridge-parachains + bump: major +- name: pallet-bridge-relayers + bump: major +- name: pallet-xcm-bridge-hub + bump: major +- name: pallet-xcm-bridge-hub-router + bump: major +- name: bp-header-chain + bump: major +- name: bp-messages + bump: major +- name: bp-polkadot-core + bump: none +- name: bp-relayers + bump: major +- name: bp-runtime + bump: minor +- name: bp-xcm-bridge-hub-router + bump: major +- name: bp-xcm-bridge-hub + bump: major +- name: relay-substrate-client + bump: none +- name: substrate-relay-helper + bump: major +- name: messages-relay + bump: major +- name: parachains-relay + bump: none +- name: cumulus-pallet-xcmp-queue + bump: patch +- name: parachains-relay + bump: none +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch From 01344b8d3ef0f0d494e61e430dcc6ba9bfcaa40d Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 16:27:48 +0200 Subject: [PATCH 91/95] Removed `FAIL-CI` for unused `BridgeHubOrigin` --- bridges/modules/xcm-bridge-hub-router/src/lib.rs | 3 --- bridges/modules/xcm-bridge-hub-router/src/mock.rs | 3 --- bridges/modules/xcm-bridge-hub/src/mock.rs | 3 +-- .../runtimes/assets/asset-hub-rococo/src/lib.rs | 13 +------------ .../runtimes/assets/asset-hub-westend/src/lib.rs | 15 ++------------- 5 files changed, 4 insertions(+), 33 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 39ea504fbb3e..860c1a83878c 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -98,9 +98,6 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; - /// TODO:(bridges-v2) - FAIL-CI - we dont use it, remove? - /// Origin of the sibling bridge hub that is allowed to report bridge status. - type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. type ToBridgeHubSender: SendXcm + InspectMessageQueues; /// Local XCM channel manager. diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 6eab168698f6..f4806eb55b2a 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -24,13 +24,11 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{Contains, Equals}, }; -use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; use sp_std::cell::RefCell; use xcm::prelude::*; use xcm_builder::{InspectMessageQueues, NetworkExportTable, NetworkExportTableItem}; -pub type AccountId = u64; type Block = frame_system::mocking::MockBlock; /// HRMP fee. @@ -82,7 +80,6 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type DestinationVersion = LatestOrNoneForLocationVersionChecker>; - type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; type LocalXcmChannelManager = TestLocalXcmChannelManager; diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 2b90c5fa77e8..d32e0989dfd8 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -27,7 +27,7 @@ use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{EnsureOrigin, Equals, Everything, NeverEnsureOrigin, OriginTrait}, + traits::{EnsureOrigin, Equals, Everything, OriginTrait}, weights::RuntimeDbWeight, }; use polkadot_parachain_primitives::primitives::Sibling; @@ -214,7 +214,6 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type Bridges = NetworkExportTable; type DestinationVersion = AlwaysLatest; - type BridgeHubOrigin = NeverEnsureOrigin; type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; type LocalXcmChannelManager = TestLocalXcmChannelManager; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index a09207d746d0..2f3fb6b68c4a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -63,8 +63,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, - ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, - TransformOrigin, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -926,16 +925,6 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - #[cfg(not(feature = "runtime-benchmarks"))] - type BridgeHubOrigin = EnsureXcm>; - #[cfg(feature = "runtime-benchmarks")] - type BridgeHubOrigin = EitherOfDiverse< - // for running benchmarks - EnsureRoot, - // for running tests with `--feature runtime-benchmarks` - EnsureXcm>, - >; - type ToBridgeHubSender = XcmpQueue; type LocalXcmChannelManager = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 196dfd03a64d..97dbe7c361c1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -45,8 +45,8 @@ use frame_support::{ traits::{ fungible, fungibles, tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Equals, - InstanceFilter, TransformOrigin, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -57,7 +57,6 @@ use frame_system::{ }; use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; -use pallet_xcm::EnsureXcm; use parachains_common::{ impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, @@ -917,16 +916,6 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - #[cfg(not(feature = "runtime-benchmarks"))] - type BridgeHubOrigin = EnsureXcm>; - #[cfg(feature = "runtime-benchmarks")] - type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< - // for running benchmarks - EnsureRoot, - // for running tests with `--feature runtime-benchmarks` - EnsureXcm>, - >; - type ToBridgeHubSender = XcmpQueue; type LocalXcmChannelManager = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; From cf5bc064c32b67b9fe403841534f6de0afe15cc1 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 16:31:27 +0200 Subject: [PATCH 92/95] Removed `FAIL-CI` for missing benchmarks and replaced with github issue --- bridges/modules/xcm-bridge-hub/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 532426c1765a..02d578386a75 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -290,7 +290,7 @@ pub mod pallet { /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane /// is `Opened`. #[pallet::call_index(0)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl pub fn open_bridge( origin: OriginFor, bridge_destination_universal_location: Box, @@ -328,7 +328,7 @@ pub mod pallet { /// The states after this call: everything is either `Closed`, or purged from the /// runtime storage. #[pallet::call_index(1)] - #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/polkadot-sdk/pull/4949 - add benchmarks impl - FAIL-CI + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl pub fn close_bridge( origin: OriginFor, bridge_destination_universal_location: Box, From 935e87ad34644a8a892b3c42c3889c6c80e610b6 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 16:39:59 +0200 Subject: [PATCH 93/95] Removed `FAIL-CI` for congestion and replaced with github issue https://github.com/paritytech/parity-bridges-common/issues/3047 --- .../src/bridge_to_westend_config.rs | 32 +------------------ .../src/bridge_to_rococo_config.rs | 32 +------------------ 2 files changed, 2 insertions(+), 62 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 66dd9dff8b42..fc52413a909f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -30,7 +30,6 @@ use bp_messages::{ use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; use pallet_xcm_bridge_hub::XcmAsPlainPayload; -use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; use frame_system::EnsureRoot; use pallet_bridge_relayers::extension::{ @@ -62,11 +61,6 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); - pub BridgeHubWestendLocation: Location = Location::new( 2, [ @@ -78,26 +72,6 @@ parameter_types! { pub storage BridgeDeposit: Balance = 5 * ROC; } -// TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI -fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { - alloc::vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested, - } - ) - .encode() - .into(), - } - ] -} - /// Proof of messages, coming from Westend. pub type FromWestendBridgeHubMessagesProof = FromBridgedChainMessagesProof; @@ -177,11 +151,7 @@ impl pallet_xcm_bridge_hub::Config for Runtime type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: - // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - // AssetHubRococoParaId, - // Runtime, - // >, + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 type LocalXcmChannelManager = (); type BlobDispatcher = FromWestendMessageBlobDispatcher; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 76121af452a4..2d9e8f664276 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -29,7 +29,6 @@ use bp_parachains::SingleParaStoredHeaderDataBuilder; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; use pallet_xcm_bridge_hub::XcmAsPlainPayload; -use codec::Encode; use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, @@ -70,11 +69,6 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - // TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); - pub BridgeHubRococoLocation: Location = Location::new( 2, [ @@ -86,26 +80,6 @@ parameter_types! { pub storage BridgeDeposit: Balance = 10 * WND; } -// TODO:(bridges-v2) - check with `LocalXcmChannelManager` if we need - FAIL-CI -fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { - alloc::vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested, - } - ) - .encode() - .into(), - } - ] -} - /// Proof of messages, coming from Rococo. pub type FromRococoBridgeHubMessagesProof = FromBridgedChainMessagesProof; @@ -208,11 +182,7 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - FAIL-CI - something like this: - // cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - // AssetHubWestendParaId, - // Runtime, - // > + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 type LocalXcmChannelManager = (); type BlobDispatcher = FromRococoMessageBlobDispatcher; } From 513aa6aeecdb7ebd7e8531cdca76ad8b36781f33 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 16:46:13 +0200 Subject: [PATCH 94/95] Only PeopleRococo can manage channel to the bulletin --- .../src/bridge_to_bulletin_config.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 5b9076f18ae7..00d902486c85 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -30,16 +30,16 @@ use bp_messages::{ }; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; -use frame_support::{parameter_types, traits::PalletInfoAccess}; +use frame_support::{ + parameter_types, + traits::{Equals, PalletInfoAccess}, +}; use frame_system::EnsureRoot; use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; use pallet_xcm::EnsureXcm; use pallet_xcm_bridge_hub::XcmAsPlainPayload; -use parachains_common::xcm_config::{ - AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, -}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ @@ -71,6 +71,9 @@ parameter_types! { /// meaning of this value. pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; + /// PeopleRococo location + pub PeopleRococoLocation: Location = Location::new(1, [Parachain(rococo_runtime_constants::system_parachain::PEOPLE_ID)]); + pub storage BridgeDeposit: Balance = 5 * ROC; } @@ -137,8 +140,8 @@ impl pallet_xcm_bridge_hub::Config for Runtime XcmVersionOfDestAndRemoteBridge; type AdminOrigin = EnsureRoot; - // Only allow calls from relay chains and sibling parachains to directly open the bridge. - type OpenBridgeOrigin = EnsureXcm; + // Only allow calls from sibling People parachain to directly open the bridge. + type OpenBridgeOrigin = EnsureXcm>; // Converter aligned with `OpenBridgeOrigin`. type BridgeOriginAccountIdConverter = (ParentIsPreset, SiblingParachainConvertsVia); @@ -146,9 +149,8 @@ impl pallet_xcm_bridge_hub::Config for Runtime type BridgeDeposit = BridgeDeposit; type Currency = Balances; type RuntimeHoldReason = RuntimeHoldReason; - // Do not require deposit from system parachains or relay chain - type AllowWithoutBridgeDeposit = - RelayOrOtherSystemParachains; + // Do not require deposit from People parachains. + type AllowWithoutBridgeDeposit = Equals; type LocalXcmChannelManager = (); type BlobDispatcher = FromRococoBulletinMessageBlobDispatcher; @@ -283,7 +285,6 @@ pub mod migration { parameter_types! { pub RococoPeopleToRococoBulletinMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 0])); - pub PeopleRococoLocation: Location = Location::new(1, [Parachain(rococo_runtime_constants::system_parachain::PEOPLE_ID)]); pub BulletinRococoLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); } From a0837d93f2194bb476cf33d7f3564d00b1eec1c2 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 2 Sep 2024 17:22:31 +0200 Subject: [PATCH 95/95] prdoc fixes --- prdoc/pr_4949.prdoc | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/prdoc/pr_4949.prdoc b/prdoc/pr_4949.prdoc index 583cbc52fa9f..4a5c09c6fa8d 100644 --- a/prdoc/pr_4949.prdoc +++ b/prdoc/pr_4949.prdoc @@ -29,9 +29,11 @@ crates: - name: pallet-xcm-bridge-hub-router bump: major - name: bp-header-chain - bump: major + bump: patch - name: bp-messages bump: major +- name: bp-parachains + bump: major - name: bp-polkadot-core bump: none - name: bp-relayers @@ -39,7 +41,7 @@ crates: - name: bp-runtime bump: minor - name: bp-xcm-bridge-hub-router - bump: major + bump: patch - name: bp-xcm-bridge-hub bump: major - name: relay-substrate-client @@ -55,10 +57,22 @@ crates: - name: parachains-relay bump: none - name: asset-hub-rococo-runtime - bump: patch + bump: major - name: asset-hub-westend-runtime - bump: patch + bump: major - name: bridge-hub-rococo-runtime - bump: patch + bump: major - name: bridge-hub-westend-runtime + bump: major +- name: emulated-integration-tests-common + bump: minor +- name: asset-test-utils bump: patch +- name: parachains-runtimes-test-utils + bump: minor +- name: bridge-hub-common + bump: minor +- name: bridge-hub-test-utils + bump: major +- name: xcm-emulator + bump: major