Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Take send cost on BH into account #142

Closed
wants to merge 14 commits into from
Closed
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 19 additions & 10 deletions bridges/snowbridge/pallets/inbound-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use sp_runtime::traits::Zero;
use sp_std::vec;
use xcm::prelude::{
send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash,
*,
};
use xcm_executor::traits::TransactAsset;

Expand All @@ -61,9 +62,8 @@ use snowbridge_core::{
sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters,
StaticLookup,
};
use snowbridge_router_primitives::{
inbound,
inbound::{ConvertMessage, ConvertMessageError},
use snowbridge_router_primitives::inbound::{
ConvertMessage, ConvertMessageError, VersionedMessage,
};
use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError};

Expand Down Expand Up @@ -141,6 +141,9 @@ pub mod pallet {

/// To withdraw and deposit an asset.
type AssetTransactor: TransactAsset;

/// The most expensive xcm here only used to estimate send cost
type MaxSendCost: Get<BalanceOf<Self>>;
}

#[pallet::hooks]
Expand Down Expand Up @@ -278,12 +281,11 @@ pub mod pallet {
}

// Decode message into XCM
let (xcm, fee) =
match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) {
Ok(message) => T::MessageConverter::convert(envelope.message_id, message)
.map_err(|e| Error::<T>::ConvertMessage(e))?,
Err(_) => return Err(Error::<T>::InvalidPayload.into()),
};
let (xcm, fee) = match VersionedMessage::decode_all(&mut envelope.payload.as_ref()) {
Ok(message) => T::MessageConverter::convert(envelope.message_id, message)
.map_err(|e| Error::<T>::ConvertMessage(e))?,
Err(_) => return Err(Error::<T>::InvalidPayload.into()),
};

log::info!(
target: LOG_TARGET,
Expand Down Expand Up @@ -329,12 +331,20 @@ pub mod pallet {
Ok(xcm_hash)
}

pub fn calculate_send_cost(xcm: Xcm<()>, dest: ParaId) -> Result<Assets, Error<T>> {
let dest = Location::new(1, [Parachain(dest.into())]);
let (_, fee) = T::XcmSender::validate(&mut Some(dest), &mut Some(xcm))
.map_err(Error::<T>::from)?;
Ok(fee)
}

pub fn calculate_delivery_cost(length: u32) -> BalanceOf<T> {
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));
weight_fee
.saturating_add(len_fee)
.saturating_add(T::PricingParameters::get().rewards.local)
.saturating_add(T::MaxSendCost::get())
}

/// Burn the amount of the fee embedded into the XCM for teleports
Expand Down Expand Up @@ -365,7 +375,6 @@ pub mod pallet {
/// API for accessing the delivery cost of a message
impl<T: Config> Get<BalanceOf<T>> for Pallet<T> {
fn get() -> BalanceOf<T> {
// Cost here based on MaxMessagePayloadSize(the worst case)
Self::calculate_delivery_cost(T::MaxMessageSize::get())
}
}
Expand Down
3 changes: 3 additions & 0 deletions bridges/snowbridge/pallets/inbound-queue/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ parameter_types! {
rewards: Rewards { local: DOT, remote: meth(1) },
multiplier: FixedU128::from_rational(1, 1),
};
pub DefaultFee: Asset = (Parent, 1_000_000_000).into();
pub MaxSendCost: u128 = 1;
}

pub const DOT: u128 = 10_000_000_000;
Expand Down Expand Up @@ -226,6 +228,7 @@ impl inbound_queue::Config for Test {
type LengthToFee = IdentityFee<u128>;
type MaxMessageSize = ConstU32<1024>;
type AssetTransactor = SuccessfulTransactor;
type MaxSendCost = MaxSendCost;
}

pub fn last_events(n: usize) -> Vec<RuntimeEvent> {
Expand Down
2 changes: 1 addition & 1 deletion bridges/snowbridge/pallets/outbound-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ pub mod pallet {
}

/// The local component of the message processing fees in native currency
pub(crate) fn calculate_local_fee() -> T::Balance {
pub fn calculate_local_fee() -> T::Balance {
T::WeightToFee::weight_to_fee(
&T::WeightInfo::do_process_message().saturating_add(T::WeightInfo::commit_single()),
)
Expand Down
3 changes: 3 additions & 0 deletions bridges/snowbridge/runtime/test-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ parachains-runtimes-test-utils = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-pallet-ethereum-client = { workspace = true }
snowbridge-pallet-ethereum-client-fixtures = { workspace = true }
snowbridge-pallet-inbound-queue = { workspace = true }
snowbridge-pallet-outbound-queue = { workspace = true }
snowbridge-pallet-system = { workspace = true }

Expand All @@ -63,6 +64,7 @@ std = [
"snowbridge-core/std",
"snowbridge-pallet-ethereum-client-fixtures/std",
"snowbridge-pallet-ethereum-client/std",
"snowbridge-pallet-inbound-queue/std",
"snowbridge-pallet-outbound-queue/std",
"snowbridge-pallet-system/std",
"sp-core/std",
Expand All @@ -86,6 +88,7 @@ runtime-benchmarks = [
"snowbridge-core/runtime-benchmarks",
"snowbridge-pallet-ethereum-client-fixtures/runtime-benchmarks",
"snowbridge-pallet-ethereum-client/runtime-benchmarks",
"snowbridge-pallet-inbound-queue/runtime-benchmarks",
"snowbridge-pallet-outbound-queue/runtime-benchmarks",
"snowbridge-pallet-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
Expand Down
100 changes: 99 additions & 1 deletion bridges/snowbridge/runtime/test-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use parachains_runtimes_test_utils::{
};
use snowbridge_core::{ChannelId, ParaId};
use snowbridge_pallet_ethereum_client_fixtures::*;
use sp_core::{H160, U256};
use sp_core::{Get, H160, U256};
use sp_keyring::AccountKeyring::*;
use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating};
use xcm::{
Expand Down Expand Up @@ -561,3 +561,101 @@ pub fn ethereum_to_polkadot_message_extrinsics_work<Runtime>(
assert_ok!(sync_committee_outcome);
});
}

pub fn fetch_delivery_cost<Runtime, XcmConfig>(collator_session_key: CollatorSessionKeys<Runtime>)
where
Runtime: frame_system::Config
+ pallet_balances::Config
+ pallet_session::Config
+ pallet_xcm::Config
+ parachain_info::Config
+ pallet_collator_selection::Config
+ cumulus_pallet_parachain_system::Config
+ snowbridge_pallet_outbound_queue::Config
+ snowbridge_pallet_inbound_queue::Config
+ pallet_timestamp::Config,
XcmConfig: xcm_executor::Config,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
<Runtime as frame_system::Config>::AccountId: From<sp_runtime::AccountId32> + AsRef<[u8]>,
{
ExtBuilder::<Runtime>::default()
.with_collators(collator_session_key.collators())
.with_session_keys(collator_session_key.session_keys())
.with_para_id(1013.into())
.with_tracing()
.build()
.execute_with(|| {
let _ = <pallet_xcm::Pallet<Runtime>>::force_xcm_version(
RuntimeHelper::<Runtime>::root_origin(),
Box::new(Location { parents: 1, interior: [Parachain(1000)].into() }),
XCM_VERSION,
);
let inbound_delivery_cost =
<snowbridge_pallet_inbound_queue::Pallet<Runtime>>::calculate_delivery_cost(
<Runtime as snowbridge_pallet_inbound_queue::Config>::MaxMessageSize::get(),
);
let inbound_send_cost =
<Runtime as snowbridge_pallet_inbound_queue::Config>::MaxSendCost::get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably assert that the configured cost is greater than or equal to the xcm cost using the same method you used here:

8ad87ba#diff-832917c2fd6302a9f175210f7d9941ea82a1a7c5a35aa35e662380074d405203L370-L377

Probably not important for this test. But may be very important for the fellowship runtime.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let outbound_delivery_cost =
<snowbridge_pallet_outbound_queue::Pallet<Runtime>>::calculate_local_fee();

println!("inbound_delivery_cost:{:?}", inbound_delivery_cost);
println!("inbound_send_cost:{:?}", inbound_send_cost);
println!("outbound_delivery_cost:{:?}", outbound_delivery_cost);

const CHAIN_ID: u64 = 11155111;
const WETH: [u8; 20] = [1; 20];

let total_fee_amount: u32 = 2_000_000_000;
let asset_hub_fee_amount: u32 = 1_000_000_000;
let dest_fee_amount: u32 = total_fee_amount - asset_hub_fee_amount;

let total_fee_asset: Asset = (Location::parent(), total_fee_amount).into();
let asset_hub_fee_asset: Asset = (Location::parent(), asset_hub_fee_amount).into();
let dest_para_fee_asset: Asset = (Location::parent(), dest_fee_amount).into();

let weth_asset_id = Location::new(
2,
[
GlobalConsensus(Ethereum { chain_id: CHAIN_ID }),
AccountKey20 { network: None, key: WETH.into() },
],
);
let weth_asset = Asset::from((weth_asset_id.clone(), 1_000_000));

let xcm_worst_case = Xcm(vec![
ReceiveTeleportedAsset(total_fee_asset.into()),
BuyExecution { fees: asset_hub_fee_asset, weight_limit: Unlimited },
DescendOrigin(PalletInstance(80).into()),
UniversalOrigin(GlobalConsensus(Ethereum { chain_id: CHAIN_ID })),
ReserveAssetDeposited(weth_asset.clone().into()),
ClearOrigin,
DepositReserveAsset {
assets: Definite(vec![dest_para_fee_asset.clone(), weth_asset.clone()].into()),
dest: Location::new(1, [Parachain(2000)]),
xcm: vec![
BuyExecution { fees: dest_para_fee_asset, weight_limit: Unlimited },
DepositAsset {
assets: Definite(weth_asset.into()),
beneficiary: [1; 32].into(),
},
SetTopic([1; 32]),
]
.into(),
},
]);

let delivery_cost_worst_case =
<snowbridge_pallet_inbound_queue::Pallet<Runtime>>::calculate_send_cost(
xcm_worst_case,
ParaId::from(1000),
)
.unwrap()
.into_inner();
// println!("{:?}", delivery_cost_worst_case[0]);

let send_cost_max: Asset =
(Location::parent(), inbound_send_cost.saturated_into::<u128>()).into();
assert!(send_cost_max.gt(&delivery_cost_worst_case[0]))
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ parameter_types! {
rewards: Rewards { local: 1 * UNITS, remote: meth(1) },
multiplier: FixedU128::from_rational(1, 1),
};
pub MaxSendCost: Balance = UNITS / 10;
}

impl snowbridge_pallet_inbound_queue::Config for Runtime {
Expand Down Expand Up @@ -90,6 +91,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime {
type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo<Runtime>;
type PricingParameters = EthereumSystem;
type AssetTransactor = <xcm_config::XcmConfig as xcm_executor::Config>::AssetTransactor;
type MaxSendCost = MaxSendCost;
}

impl snowbridge_pallet_outbound_queue::Config for Runtime {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,10 @@ fn construct_and_apply_extrinsic(
let r = Executive::apply_extrinsic(xt);
r.unwrap()
}

#[test]
fn fetch_delivery_cost() {
snowbridge_runtime_test_common::fetch_delivery_cost::<Runtime, XcmConfig>(
collator_session_keys(),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ parameter_types! {
rewards: Rewards { local: 1 * UNITS, remote: meth(1) },
multiplier: FixedU128::from_rational(1, 1),
};
pub MaxSendCost: Balance = UNITS / 10;
}

impl snowbridge_pallet_inbound_queue::Config for Runtime {
Expand Down Expand Up @@ -91,6 +92,7 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime {
type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo<Runtime>;
type PricingParameters = EthereumSystem;
type AssetTransactor = <xcm_config::XcmConfig as xcm_executor::Config>::AssetTransactor;
type MaxSendCost = MaxSendCost;
}

impl snowbridge_pallet_outbound_queue::Config for Runtime {
Expand Down
Loading