From a2f1d134b079633219d6296f9a550faa441ce143 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 5 Feb 2025 00:46:26 -0300 Subject: [PATCH 1/4] Add reward processor in snowbridge inbound queue --- .../pallets/inbound-queue/src/lib.rs | 38 ++++++-------- .../pallets/inbound-queue/src/mock.rs | 52 ++++++++++++++----- .../pallets/inbound-queue/src/test.rs | 39 ++------------ .../src/bridge_to_ethereum_config.rs | 34 ++++++------ .../src/bridge_to_ethereum_config.rs | 32 ++++++------ 5 files changed, 94 insertions(+), 101 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 614330221aa9e..495ee81579e4c 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -37,17 +37,14 @@ pub mod xcm_message_processor; use codec::{Decode, Encode}; use frame_support::{ - traits::{ - fungible::{Inspect, Mutate}, - tokens::{Fortitude, Preservation}, - }, + pallet_prelude::DispatchResult, + traits::fungible::{Inspect, Mutate}, weights::WeightToFee, PalletError, }; use frame_system::ensure_signed; use scale_info::TypeInfo; use sp_core::{H160, H256}; -use sp_runtime::traits::Zero; use sp_std::vec; use xcm::prelude::{ send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash, @@ -56,8 +53,7 @@ use xcm_executor::traits::TransactAsset; use snowbridge_core::{ inbound::{Message, VerificationError, Verifier}, - sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, - StaticLookup, + BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, StaticLookup, }; use snowbridge_router_primitives::inbound::{ envelope::Envelope, ConvertMessage, ConvertMessageError, MessageProcessor, VersionedXcmMessage, @@ -76,6 +72,16 @@ pub use pallet::*; pub const LOG_TARGET: &str = "snowbridge-inbound-queue"; +pub trait RewardProcessor { + fn process_reward(who: T::AccountId, message: Message) -> DispatchResult; +} + +impl RewardProcessor for () { + fn process_reward(_who: T::AccountId, _message: Message) -> DispatchResult { + Ok(()) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -139,6 +145,9 @@ pub mod pallet { /// Process the message that was submitted type MessageProcessor: MessageProcessor; + + /// Process the reward to the relayer + type RewardProcessor: RewardProcessor; } #[pallet::hooks] @@ -263,20 +272,7 @@ pub mod pallet { } })?; - // Reward relayer from the sovereign account of the destination parachain, only if funds - // are available - let sovereign_account = sibling_sovereign_account::(channel.para_id); - let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32); - let amount = T::Token::reducible_balance( - &sovereign_account, - Preservation::Preserve, - Fortitude::Polite, - ) - .min(delivery_cost); - if !amount.is_zero() { - T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; - } - + T::RewardProcessor::process_reward(who, message)?; T::MessageProcessor::process_message(channel, envelope) } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index cecda7251e633..42f97b549711f 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -2,6 +2,9 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; +use frame_support::storage::Key; +use frame_support::traits::tokens::Fortitude; +use frame_support::traits::tokens::Preservation; use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::IdentityFee}; use hex_literal::hex; use snowbridge_beacon_primitives::{ @@ -14,9 +17,11 @@ use snowbridge_core::{ }; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_core::{H160, H256}; +use sp_keyring::AccountKeyring as Keyring; +use sp_runtime::traits::Zero; use sp_runtime::{ traits::{IdentifyAccount, IdentityLookup, MaybeEquivalence, Verify}, - BuildStorage, FixedU128, MultiSignature, DispatchError, + BuildStorage, DispatchError, FixedU128, MultiSignature, }; use sp_std::{convert::From, default::Default}; use xcm::{latest::SendXcm, prelude::*}; @@ -24,6 +29,7 @@ use xcm_executor::AssetsInHolding; use crate::xcm_message_processor::XcmMessageProcessor; use crate::{self as inbound_queue}; +use sp_core::Get; type Block = frame_system::mocking::MockBlock; @@ -243,6 +249,38 @@ impl MessageProcessor for DummySuffix { } } +pub struct DeliveryCostReward(sp_std::marker::PhantomData); + +impl RewardProcessor for DeliveryCostReward +where + T: inbound_queue::Config, + T::AccountId: From, +{ + fn process_reward(who: T::AccountId, message: Message) -> DispatchResult { + let length = message.encode().len() as u32; + let weight_fee = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit()); + let len_fee = T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0)); + let delivery_cost = weight_fee + .saturating_add(len_fee) + .saturating_add(T::PricingParameters::get().rewards.local); + + let sovereign_account: T::AccountId = + sp_runtime::AccountId32::from(Keyring::Alice.public()).into(); + + let amount = T::Token::reducible_balance( + &sovereign_account, + Preservation::Preserve, + Fortitude::Polite, + ) + .min(delivery_cost); + if !amount.is_zero() { + T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; + } + + Ok(()) + } +} + impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; @@ -269,6 +307,7 @@ impl inbound_queue::Config for Test { type MaxMessageSize = ConstU32<1024>; type AssetTransactor = SuccessfulTransactor; type MessageProcessor = (DummyPrefix, XcmMessageProcessor, DummySuffix); // We are passively testing if implementation of MessageProcessor trait works correctly for tuple + type RewardProcessor = DeliveryCostReward; } pub fn last_events(n: usize) -> Vec { @@ -287,16 +326,6 @@ pub fn expect_events(e: Vec) { pub fn setup() { System::set_block_number(1); - Balances::mint_into( - &sibling_sovereign_account::(ASSET_HUB_PARAID.into()), - InitialFund::get(), - ) - .unwrap(); - Balances::mint_into( - &sibling_sovereign_account::(TEMPLATE_PARAID.into()), - InitialFund::get(), - ) - .unwrap(); } pub fn new_tester() -> sp_io::TestExternalities { @@ -383,4 +412,3 @@ pub fn mock_execution_proof() -> ExecutionProof { } pub const ASSET_HUB_PARAID: u32 = 1000u32; -pub const TEMPLATE_PARAID: u32 = 1001u32; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 41c38460aabf1..1881bdb5a17dd 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -17,10 +17,11 @@ use crate::mock::*; fn test_submit_happy_path() { new_tester().execute_with(|| { let relayer: AccountId = Keyring::Bob.into(); - let channel_sovereign = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - let origin = RuntimeOrigin::signed(relayer.clone()); + // Add funds to reward relayers + let _ = Balances::mint_into(&AccountId::from(Keyring::Alice), 1e20 as u128); + // Submit message let message = Message { event_log: mock_event_log(), @@ -30,9 +31,7 @@ fn test_submit_happy_path() { }, }; - let initial_fund = InitialFund::get(); assert_eq!(Balances::balance(&relayer), 0); - assert_eq!(Balances::balance(&channel_sovereign), initial_fund); assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); expect_events(vec![InboundQueueEvent::MessageReceived { @@ -54,10 +53,6 @@ fn test_submit_happy_path() { ); assert_eq!(Balances::balance(&relayer), delivery_cost, "relayer was rewarded"); - assert!( - Balances::balance(&channel_sovereign) <= initial_fund - delivery_cost, - "sovereign account paid reward" - ); }); } @@ -67,11 +62,6 @@ fn test_submit_xcm_invalid_channel() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Deposit funds into sovereign account of parachain 1001 - let sovereign_account = sibling_sovereign_account::(TEMPLATE_PARAID.into()); - println!("account: {}", sovereign_account); - let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit message let message = Message { event_log: mock_event_log_invalid_channel(), @@ -93,10 +83,6 @@ fn test_submit_with_invalid_gateway() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Deposit funds into sovereign account of Asset Hub (Statemint) - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit message let message = Message { event_log: mock_event_log_invalid_gateway(), @@ -118,10 +104,6 @@ fn test_submit_with_invalid_nonce() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Deposit funds into sovereign account of Asset Hub (Statemint) - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit message let message = Message { event_log: mock_event_log(), @@ -151,10 +133,6 @@ fn test_submit_no_funds_to_reward_relayers_just_ignore() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Reset balance of sovereign_account to zero first - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - Balances::set_balance(&sovereign_account, 0); - // Submit message let message = Message { event_log: mock_event_log(), @@ -209,10 +187,6 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Reset balance of sovereign account to (ED+1) first - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - Balances::set_balance(&sovereign_account, ExistentialDeposit::get() + 1); - // Submit message successfully let message = Message { event_log: mock_event_log(), @@ -223,10 +197,6 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); - // Check balance of sovereign account to ED - let amount = Balances::balance(&sovereign_account); - assert_eq!(amount, ExistentialDeposit::get()); - // Submit another message with nonce set as 2 let mut event_log = mock_event_log(); event_log.data[31] = 2; @@ -238,8 +208,5 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { }, }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); - // Check balance of sovereign account as ED does not change - let amount = Balances::balance(&sovereign_account); - assert_eq!(amount, ExistentialDeposit::get()); }); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index ffa293308bbf8..0aff0bfb2e443 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use crate::xcm_config::RelayNetwork; #[cfg(not(feature = "runtime-benchmarks"))] use crate::XcmRouter; use crate::{ @@ -21,27 +22,26 @@ use crate::{ EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, TreasuryAccount, }; +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; +use bridge_hub_common::AggregateMessageOrigin; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; -use sp_runtime::traits::Convert; use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; use sp_core::H160; +use sp_runtime::traits::Convert; +use sp_runtime::{ + traits::{ConstU32, ConstU8, Keccak256}, + FixedU128, +}; use testnet_parachains_constants::rococo::{ currency::*, fee::WeightToFee, snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, }; -use bridge_hub_common::AggregateMessageOrigin; -use crate::xcm_config::RelayNetwork; -#[cfg(feature = "runtime-benchmarks")] -use benchmark_helpers::DoNothingRouter; -use frame_support::{parameter_types, weights::ConstantMultiplier}; -use pallet_xcm::EnsureXcm; -use sp_runtime::{ - traits::{ConstU32, ConstU8, Keccak256}, - FixedU128, -}; use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, Parachain}; /// Exports message to the Ethereum Gateway contract. @@ -99,19 +99,19 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type AssetTransactor = ::AssetTransactor; - type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type MessageProcessor = + snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type RewardProcessor = (); } - pub struct GetAggregateMessageOrigin; impl Convert for GetAggregateMessageOrigin { - fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { - AggregateMessageOrigin::Snowbridge(channel_id) - } + fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Snowbridge(channel_id) + } } - impl snowbridge_pallet_outbound_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Hashing = Keccak256; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index 0cfdc49e67d05..25bb8606613e0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use crate::xcm_config::RelayNetwork; #[cfg(not(feature = "runtime-benchmarks"))] use crate::XcmRouter; use crate::{ @@ -22,27 +23,26 @@ use crate::{ Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, }; +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; +use bridge_hub_common::AggregateMessageOrigin; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; use sp_core::H160; -use testnet_parachains_constants::westend::{ - currency::*, - fee::WeightToFee, - snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, -}; use sp_runtime::traits::Convert; -use bridge_hub_common::AggregateMessageOrigin; -use crate::xcm_config::RelayNetwork; -#[cfg(feature = "runtime-benchmarks")] -use benchmark_helpers::DoNothingRouter; -use frame_support::{parameter_types, weights::ConstantMultiplier}; -use pallet_xcm::EnsureXcm; use sp_runtime::{ traits::{ConstU32, ConstU8, Keccak256}, FixedU128, }; +use testnet_parachains_constants::westend::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, Parachain}; pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32; @@ -101,15 +101,17 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type AssetTransactor = ::AssetTransactor; - type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type MessageProcessor = + snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type RewardProcessor = (); } pub struct GetAggregateMessageOrigin; impl Convert for GetAggregateMessageOrigin { - fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { - AggregateMessageOrigin::Snowbridge(channel_id) - } + fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Snowbridge(channel_id) + } } impl snowbridge_pallet_outbound_queue::Config for Runtime { From 52b86b477b1db2ae6087780c8ef1d8898f319394 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 5 Feb 2025 10:48:58 -0300 Subject: [PATCH 2/4] Revert some changes and move default processor to pallet lib --- .../pallets/inbound-queue/src/lib.rs | 32 +++++++++++- .../pallets/inbound-queue/src/mock.rs | 51 +++++-------------- .../pallets/inbound-queue/src/test.rs | 39 ++++++++++++-- .../src/bridge_to_ethereum_config.rs | 3 +- .../src/bridge_to_ethereum_config.rs | 2 +- 5 files changed, 82 insertions(+), 45 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 495ee81579e4c..59a22a746a39c 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -36,6 +36,8 @@ mod test; pub mod xcm_message_processor; use codec::{Decode, Encode}; +use frame_support::traits::tokens::Fortitude; +use frame_support::traits::tokens::Preservation; use frame_support::{ pallet_prelude::DispatchResult, traits::fungible::{Inspect, Mutate}, @@ -45,6 +47,7 @@ use frame_support::{ use frame_system::ensure_signed; use scale_info::TypeInfo; use sp_core::{H160, H256}; +use sp_runtime::traits::Zero; use sp_std::vec; use xcm::prelude::{ send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash, @@ -53,7 +56,8 @@ use xcm_executor::traits::TransactAsset; use snowbridge_core::{ inbound::{Message, VerificationError, Verifier}, - BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, StaticLookup, + sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, + StaticLookup, }; use snowbridge_router_primitives::inbound::{ envelope::Envelope, ConvertMessage, ConvertMessageError, MessageProcessor, VersionedXcmMessage, @@ -82,6 +86,32 @@ impl RewardProcessor for () { } } +pub struct DeliveryCostReward(sp_std::marker::PhantomData); + +impl RewardProcessor for DeliveryCostReward { + fn process_reward(who: T::AccountId, message: Message) -> DispatchResult { + let length = message.encode().len() as u32; + let delivery_cost = pallet::Pallet::::calculate_delivery_cost(length); + + let envelope = + Envelope::try_from(&message.event_log).map_err(|_| Error::::InvalidEnvelope)?; + let channel = + T::ChannelLookup::lookup(envelope.channel_id).ok_or(Error::::InvalidChannel)?; + let sovereign_account: T::AccountId = sibling_sovereign_account::(channel.para_id); + + let amount = T::Token::reducible_balance( + &sovereign_account, + Preservation::Preserve, + Fortitude::Polite, + ) + .min(delivery_cost); + if !amount.is_zero() { + T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; + } + + Ok(()) + } +} #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 42f97b549711f..c469e61e77de8 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -2,9 +2,6 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; -use frame_support::storage::Key; -use frame_support::traits::tokens::Fortitude; -use frame_support::traits::tokens::Preservation; use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::IdentityFee}; use hex_literal::hex; use snowbridge_beacon_primitives::{ @@ -17,8 +14,6 @@ use snowbridge_core::{ }; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_core::{H160, H256}; -use sp_keyring::AccountKeyring as Keyring; -use sp_runtime::traits::Zero; use sp_runtime::{ traits::{IdentifyAccount, IdentityLookup, MaybeEquivalence, Verify}, BuildStorage, DispatchError, FixedU128, MultiSignature, @@ -29,7 +24,6 @@ use xcm_executor::AssetsInHolding; use crate::xcm_message_processor::XcmMessageProcessor; use crate::{self as inbound_queue}; -use sp_core::Get; type Block = frame_system::mocking::MockBlock; @@ -249,38 +243,6 @@ impl MessageProcessor for DummySuffix { } } -pub struct DeliveryCostReward(sp_std::marker::PhantomData); - -impl RewardProcessor for DeliveryCostReward -where - T: inbound_queue::Config, - T::AccountId: From, -{ - fn process_reward(who: T::AccountId, message: Message) -> DispatchResult { - let length = message.encode().len() as u32; - let weight_fee = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit()); - let len_fee = T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0)); - let delivery_cost = weight_fee - .saturating_add(len_fee) - .saturating_add(T::PricingParameters::get().rewards.local); - - let sovereign_account: T::AccountId = - sp_runtime::AccountId32::from(Keyring::Alice.public()).into(); - - let amount = T::Token::reducible_balance( - &sovereign_account, - Preservation::Preserve, - Fortitude::Polite, - ) - .min(delivery_cost); - if !amount.is_zero() { - T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; - } - - Ok(()) - } -} - impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; @@ -307,7 +269,7 @@ impl inbound_queue::Config for Test { type MaxMessageSize = ConstU32<1024>; type AssetTransactor = SuccessfulTransactor; type MessageProcessor = (DummyPrefix, XcmMessageProcessor, DummySuffix); // We are passively testing if implementation of MessageProcessor trait works correctly for tuple - type RewardProcessor = DeliveryCostReward; + type RewardProcessor = DeliveryCostReward; } pub fn last_events(n: usize) -> Vec { @@ -326,6 +288,16 @@ pub fn expect_events(e: Vec) { pub fn setup() { System::set_block_number(1); + Balances::mint_into( + &sibling_sovereign_account::(ASSET_HUB_PARAID.into()), + InitialFund::get(), + ) + .unwrap(); + Balances::mint_into( + &sibling_sovereign_account::(TEMPLATE_PARAID.into()), + InitialFund::get(), + ) + .unwrap(); } pub fn new_tester() -> sp_io::TestExternalities { @@ -412,3 +384,4 @@ pub fn mock_execution_proof() -> ExecutionProof { } pub const ASSET_HUB_PARAID: u32 = 1000u32; +pub const TEMPLATE_PARAID: u32 = 1001u32; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 1881bdb5a17dd..41c38460aabf1 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -17,10 +17,9 @@ use crate::mock::*; fn test_submit_happy_path() { new_tester().execute_with(|| { let relayer: AccountId = Keyring::Bob.into(); - let origin = RuntimeOrigin::signed(relayer.clone()); + let channel_sovereign = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - // Add funds to reward relayers - let _ = Balances::mint_into(&AccountId::from(Keyring::Alice), 1e20 as u128); + let origin = RuntimeOrigin::signed(relayer.clone()); // Submit message let message = Message { @@ -31,7 +30,9 @@ fn test_submit_happy_path() { }, }; + let initial_fund = InitialFund::get(); assert_eq!(Balances::balance(&relayer), 0); + assert_eq!(Balances::balance(&channel_sovereign), initial_fund); assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); expect_events(vec![InboundQueueEvent::MessageReceived { @@ -53,6 +54,10 @@ fn test_submit_happy_path() { ); assert_eq!(Balances::balance(&relayer), delivery_cost, "relayer was rewarded"); + assert!( + Balances::balance(&channel_sovereign) <= initial_fund - delivery_cost, + "sovereign account paid reward" + ); }); } @@ -62,6 +67,11 @@ fn test_submit_xcm_invalid_channel() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); + // Deposit funds into sovereign account of parachain 1001 + let sovereign_account = sibling_sovereign_account::(TEMPLATE_PARAID.into()); + println!("account: {}", sovereign_account); + let _ = Balances::mint_into(&sovereign_account, 10000); + // Submit message let message = Message { event_log: mock_event_log_invalid_channel(), @@ -83,6 +93,10 @@ fn test_submit_with_invalid_gateway() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); + // Deposit funds into sovereign account of Asset Hub (Statemint) + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + let _ = Balances::mint_into(&sovereign_account, 10000); + // Submit message let message = Message { event_log: mock_event_log_invalid_gateway(), @@ -104,6 +118,10 @@ fn test_submit_with_invalid_nonce() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); + // Deposit funds into sovereign account of Asset Hub (Statemint) + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + let _ = Balances::mint_into(&sovereign_account, 10000); + // Submit message let message = Message { event_log: mock_event_log(), @@ -133,6 +151,10 @@ fn test_submit_no_funds_to_reward_relayers_just_ignore() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); + // Reset balance of sovereign_account to zero first + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + Balances::set_balance(&sovereign_account, 0); + // Submit message let message = Message { event_log: mock_event_log(), @@ -187,6 +209,10 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); + // Reset balance of sovereign account to (ED+1) first + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + Balances::set_balance(&sovereign_account, ExistentialDeposit::get() + 1); + // Submit message successfully let message = Message { event_log: mock_event_log(), @@ -197,6 +223,10 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + // Check balance of sovereign account to ED + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); + // Submit another message with nonce set as 2 let mut event_log = mock_event_log(); event_log.data[31] = 2; @@ -208,5 +238,8 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { }, }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + // Check balance of sovereign account as ED does not change + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); }); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index 0aff0bfb2e443..1a0a3ae0d797f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -30,6 +30,7 @@ use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; +use snowbridge_pallet_inbound_queue::DeliveryCostReward; use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; use sp_core::H160; use sp_runtime::traits::Convert; @@ -101,7 +102,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type AssetTransactor = ::AssetTransactor; type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; - type RewardProcessor = (); + type RewardProcessor = DeliveryCostReward; } pub struct GetAggregateMessageOrigin; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index 25bb8606613e0..dfdc5db10d572 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -103,7 +103,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type AssetTransactor = ::AssetTransactor; type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; - type RewardProcessor = (); + type RewardProcessor = DeliveryCostReward; } pub struct GetAggregateMessageOrigin; From a0b8e95f18b2c97475a212cb07a9ac9063862213 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 6 Feb 2025 15:52:58 -0300 Subject: [PATCH 3/4] Rename processor --- bridges/snowbridge/pallets/inbound-queue/src/lib.rs | 4 ++-- bridges/snowbridge/pallets/inbound-queue/src/mock.rs | 2 +- .../bridge-hub-rococo/src/bridge_to_ethereum_config.rs | 4 ++-- .../bridge-hub-westend/src/bridge_to_ethereum_config.rs | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 59a22a746a39c..8f7851f39b4f7 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -86,9 +86,9 @@ impl RewardProcessor for () { } } -pub struct DeliveryCostReward(sp_std::marker::PhantomData); +pub struct RewardThroughSovereign(sp_std::marker::PhantomData); -impl RewardProcessor for DeliveryCostReward { +impl RewardProcessor for RewardThroughSovereign { fn process_reward(who: T::AccountId, message: Message) -> DispatchResult { let length = message.encode().len() as u32; let delivery_cost = pallet::Pallet::::calculate_delivery_cost(length); diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index c469e61e77de8..598b025499f69 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -269,7 +269,7 @@ impl inbound_queue::Config for Test { type MaxMessageSize = ConstU32<1024>; type AssetTransactor = SuccessfulTransactor; type MessageProcessor = (DummyPrefix, XcmMessageProcessor, DummySuffix); // We are passively testing if implementation of MessageProcessor trait works correctly for tuple - type RewardProcessor = DeliveryCostReward; + type RewardProcessor = RewardThroughSovereign; } pub fn last_events(n: usize) -> Vec { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index 1a0a3ae0d797f..3730191421ee1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -30,7 +30,7 @@ use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; -use snowbridge_pallet_inbound_queue::DeliveryCostReward; +use snowbridge_pallet_inbound_queue::RewardThroughSovereign; use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; use sp_core::H160; use sp_runtime::traits::Convert; @@ -102,7 +102,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type AssetTransactor = ::AssetTransactor; type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; - type RewardProcessor = DeliveryCostReward; + type RewardProcessor = RewardThroughSovereign; } pub struct GetAggregateMessageOrigin; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index dfdc5db10d572..1950d9ff87b89 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -31,6 +31,7 @@ use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; +use snowbridge_pallet_inbound_queue::RewardThroughSovereign; use snowbridge_router_primitives::{inbound::MessageToXcm, outbound::EthereumBlobExporter}; use sp_core::H160; use sp_runtime::traits::Convert; @@ -103,7 +104,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type AssetTransactor = ::AssetTransactor; type MessageProcessor = snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; - type RewardProcessor = DeliveryCostReward; + type RewardProcessor = RewardThroughSovereign; } pub struct GetAggregateMessageOrigin; From 167dda173d1d1fdff4505cd558ff86f3132d23a2 Mon Sep 17 00:00:00 2001 From: Diego Date: Fri, 7 Feb 2025 13:58:36 -0300 Subject: [PATCH 4/4] Add channel parameter as part of process_reward --- bridges/snowbridge/pallets/inbound-queue/src/lib.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 8f7851f39b4f7..88aacc7585126 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -77,11 +77,11 @@ pub use pallet::*; pub const LOG_TARGET: &str = "snowbridge-inbound-queue"; pub trait RewardProcessor { - fn process_reward(who: T::AccountId, message: Message) -> DispatchResult; + fn process_reward(who: T::AccountId, channel: Channel, message: Message) -> DispatchResult; } impl RewardProcessor for () { - fn process_reward(_who: T::AccountId, _message: Message) -> DispatchResult { + fn process_reward(_who: T::AccountId, _channel: Channel, _message: Message) -> DispatchResult { Ok(()) } } @@ -89,14 +89,9 @@ impl RewardProcessor for () { pub struct RewardThroughSovereign(sp_std::marker::PhantomData); impl RewardProcessor for RewardThroughSovereign { - fn process_reward(who: T::AccountId, message: Message) -> DispatchResult { + fn process_reward(who: T::AccountId, channel: Channel, message: Message) -> DispatchResult { let length = message.encode().len() as u32; let delivery_cost = pallet::Pallet::::calculate_delivery_cost(length); - - let envelope = - Envelope::try_from(&message.event_log).map_err(|_| Error::::InvalidEnvelope)?; - let channel = - T::ChannelLookup::lookup(envelope.channel_id).ok_or(Error::::InvalidChannel)?; let sovereign_account: T::AccountId = sibling_sovereign_account::(channel.para_id); let amount = T::Token::reducible_balance( @@ -302,7 +297,7 @@ pub mod pallet { } })?; - T::RewardProcessor::process_reward(who, message)?; + T::RewardProcessor::process_reward(who, channel.clone(), message)?; T::MessageProcessor::process_message(channel, envelope) }