Changed delivery and dispatch fee computation methods (#795)

* removed weight <-> fee mess

* updated documentation

Co-authored-by: Hernando Castano <castano.ha@gmail.com>
This commit is contained in:
Svyatoslav Nikolsky
2021-03-08 21:07:20 +03:00
committed by Bastian Köcher
parent f7c3bd4e08
commit 324e083cba
19 changed files with 437 additions and 354 deletions
+61 -68
View File
@@ -33,17 +33,63 @@ message lane module into your runtime. Basic prerequisites of these helpers are:
## `MessageBridge` Trait
The essence of your integration will be a struct that implements a `MessageBridge` trait. Let's
review every method and give some implementation hints here:
The essence of your integration will be a struct that implements a `MessageBridge` trait. It has
single method (`MessageBridge::bridged_balance_to_this_balance`), used to convert from bridged chain
tokens into this chain tokens. The bridge also requires two associated types to be specified -
`ThisChain` and `BridgedChain`.
- `MessageBridge::maximal_extrinsic_size_on_target_chain`: you will need to return the maximal
extrinsic size of the target chain from this function. This may be the constant that is updated
when your runtime is upgraded, or you may use the
[message lane parameters functionality](../../modules/message-lane/README.md#Non-Essential-Functionality)
to allow the pallet owner to update this value more frequently (you may also want to use this
functionality for all constants that are used in other methods described below).
Worth to say that if you're going to use hardcoded constant (conversion rate) in the
`MessageBridge::bridged_balance_to_this_balance` method (or in any other method of
`ThisChainWithMessageLanes` or `BridgedChainWithMessageLanes` traits), then you should take a
look at the
[message lane parameters functionality](../../modules/message-lane/README.md#Non-Essential-Functionality).
They allow pallet owner to update constants more frequently than runtime upgrade happens.
- `MessageBridge::weight_limits_of_message_on_bridged_chain`: you'll need to return a range of
## `ChainWithMessageLanes` Trait
The trait is quite simple and can easily be implemented - you just need to specify types used at the
corresponding chain. There is single exception, though (it may be changed in the future):
- `ChainWithMessageLanes::MessageLaneInstance`: this is used to compute runtime storage keys. There
may be several instances of message lane pallet, included in the Runtime. Every instance stores
messages and these messages stored under different keys. When we are verifying storage proofs from
the bridged chain, we should know which instance we're talking to. This is fine, but there's
significant inconvenience with that - this chain runtime must have the same message lane pallet
instance. This does not necessarily mean that we should use the same instance on both chains -
this instance may be used to bridge with another chain/instance, or may not be used at all.
## `ThisChainWithMessageLanes` Trait
This trait represents this chain from bridge point of view. Let's review every method of this trait:
- `ThisChainWithMessageLanes::is_outbound_lane_enabled`: is used to check whether given lane accepts
outbound messages.
- `ThisChainWithMessageLanes::maximal_pending_messages_at_outbound_lane`: you should return maximal
number of pending (undelivered) messages from this function. Returning small values would require
relayers to operate faster and could make message sending logic more complicated. On the other
hand, returning large values could lead to chain state growth.
- `ThisChainWithMessageLanes::estimate_delivery_confirmation_transaction`: you'll need to return
estimated size and dispatch weight of the delivery confirmation transaction (that happens on
this chain) from this function.
- `ThisChainWithMessageLanes::transaction_payment`: you'll need to return fee that the submitter
must pay for given transaction on this chain. Normally, you would use transaction payment pallet
for this. However, if your chain has non-zero fee multiplier set, this would mean that the
payment will be computed using current value of this multiplier. But since this transaction
will be submitted in the future, you may want to choose other value instead. Otherwise,
non-altruistic relayer may choose not to submit this transaction until number of transactions
will decrease.
## `BridgedChainWithMessageLanes` Trait
This trait represents this chain from bridge point of view. Let's review every method of this trait:
- `BridgedChainWithMessageLanes::maximal_extrinsic_size`: you will need to return the maximal
extrinsic size of the target chain from this function.
- `MessageBridge::message_weight_limits`: you'll need to return a range of
dispatch weights that the outbound message may take at the target chain. Please keep in mind that
our helpers assume that the message is an encoded call of the target chain. But we never decode
this call at the source chain. So you can't simply get dispatch weight from pre-dispatch
@@ -55,66 +101,13 @@ review every method and give some implementation hints here:
maximal weight of extrinsic at the target chain. In our test chains, we reject all messages that
have declared dispatch weight larger than 50% of the maximal bridged extrinsic weight.
- `MessageBridge::weight_of_delivery_transaction`: you will need to return the maximal weight of the
delivery transaction that delivers a given message to the target chain. There are three main
things to notice:
- `MessageBridge::estimate_delivery_transaction`: you will need to return estimated dispatch weight and
size of the delivery transaction that delivers a given message to the target chain.
1. weight, returned from this function is then used to compute the fee that the
message sender needs to pay for the delivery transaction. So it shall not be a simple dispatch
weight of delivery call - it should be the "weight" of the transaction itself, including per-byte
"weight", "weight" of signed extras and etc.
1. the delivery transaction brings storage proof of
the message, not the message itself. So your transaction will include extra bytes. We suggest
computing the size of single empty value storage proof at the source chain, increase this value a
bit and hardcode it in the source chain runtime code. This size then must be added to the size of
payload and included in the weight computation;
1. before implementing this function, please take
a look at the
[weight formula of delivery transaction](../../modules/message-lane/README.md#Weight-of-receive_messages_proof-call).
It adds some extra weight for every additional byte of the proof (everything above
`pallet_message_lane::EXPECTED_DEFAULT_MESSAGE_LENGTH`), so it's not trivial. Even better, please
refer to [our implementation](../millau/runtime/src/rialto_messages.rs) for test chains for
details.
- `MessageBridge::weight_of_delivery_confirmation_transaction_on_this_chain`: you'll need to return
the maximal weight of a single message delivery confirmation transaction on this chain. All points
from the previous paragraph are also relevant here.
- `MessageBridge::this_weight_to_this_balance`: this function needs to convert weight units into fee
units on this chain. Most probably this can be done by calling
`pallet_transaction_payment::Config::WeightToFee::calc()` for passed weight.
- `MessageBridge::bridged_weight_to_bridged_balance`: this function needs to convert weight units
into fee units on the target chain. The best case is when you have the same conversion formula on
both chains - then you may just call the same formula from the previous paragraph. Otherwise,
you'll need to hardcode this formula into your runtime.
- `MessageBridge::bridged_balance_to_this_balance`: this may be the easiest method to implement and
the hardest to maintain at the same time. If you don't have any automatic methods to determine
conversion rate, then you'll probably need to maintain it by yourself (by updating conversion
rate, stored in runtime storage). This means that if you're too late with an update, then you risk
to accept messages with lower-than-expected fee. So it may be wise to have some reserve in this
conversion rate, even if that means larger delivery and dispatch fees.
## `ChainWithMessageLanes` Trait
Apart from its methods, `MessageBridge` also has two associated types that are implementing the
`ChainWithMessageLanes` trait. One is for this chain and the other is for the bridged chain. The
trait is quite simple and can easily be implemented - you just need to specify types used at the
corresponding chain. There are two exceptions, though. Both may be changed in the future. Here they
are:
- `ChainWithMessageLanes::Call`: it isn't a good idea to reference bridged chain runtime from your
runtime (cyclic references + maintaining on upgrades). So you can't know the type of bridged chain
call in your runtime. This type isn't actually used at this chain, so you may use `()` instead.
- `ChainWithMessageLanes::MessageLaneInstance`: this is used to compute runtime storage keys. There
may be several instances of message lane pallet, included in the Runtime. Every instance stores
messages and these messages stored under different keys. When we are verifying storage proofs from
the bridged chain, we should know which instance we're talking to. This is fine, but there's
significant inconvenience with that - this chain runtime must have the same message lane pallet
instance. This does not necessarily mean that we should use the same instance on both chains -
this instance may be used to bridge with another chain/instance, or may not be used at all.
- `MessageBridge::transaction_payment`: you'll need to return fee that the submitter
must pay for given transaction on bridged chain. The best case is when you have the same conversion
formula on both chains - then you may just reuse the `ThisChainWithMessageLanes::transaction_payment`
implementation. Otherwise, you'll need to hardcode this formula into your runtime.
## Helpers for the Source Chain
+144 -113
View File
@@ -31,7 +31,7 @@ use codec::{Decode, Encode};
use frame_support::{traits::Instance, weights::Weight, RuntimeDebug};
use hash_db::Hasher;
use pallet_substrate_bridge::StorageProofChecker;
use sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedMul};
use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul};
use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive, vec::Vec};
use sp_trie::StorageProof;
@@ -46,37 +46,9 @@ pub trait MessageBridge {
/// This chain in context of message bridge.
type ThisChain: ThisChainWithMessageLanes;
/// Bridged chain in context of message bridge.
type BridgedChain: ChainWithMessageLanes;
type BridgedChain: BridgedChainWithMessageLanes;
/// Maximal extrinsic size on target chain.
fn maximal_extrinsic_size_on_target_chain() -> u32;
/// Returns feasible weights range for given message payload on the target chain.
///
/// If message is being sent with the weight that is out of this range, then it
/// should be rejected.
///
/// Weights returned from this function shall not include transaction overhead
/// (like weight of signature and signed extensions verification), because they're
/// already accounted by the `weight_of_delivery_transaction`. So this function should
/// return pure call dispatch weights range.
fn weight_limits_of_message_on_bridged_chain(
message_payload: &[u8],
) -> RangeInclusive<WeightOf<BridgedChain<Self>>>;
/// Maximal weight of single message delivery transaction on Bridged chain.
fn weight_of_delivery_transaction(message_payload: &[u8]) -> WeightOf<BridgedChain<Self>>;
/// Maximal weight of single message delivery confirmation transaction on This chain.
fn weight_of_delivery_confirmation_transaction_on_this_chain() -> WeightOf<ThisChain<Self>>;
/// Convert weight of This chain to the fee (paid in Balance) of This chain.
fn this_weight_to_this_balance(weight: WeightOf<ThisChain<Self>>) -> BalanceOf<ThisChain<Self>>;
/// Convert weight of the Bridged chain to the fee (paid in Balance) of the Bridged chain.
fn bridged_weight_to_bridged_balance(weight: WeightOf<BridgedChain<Self>>) -> BalanceOf<BridgedChain<Self>>;
/// Convert Bridged chain Balance into This chain Balance.
/// Convert Bridged chain balance into This chain balance.
fn bridged_balance_to_this_balance(bridged_balance: BalanceOf<BridgedChain<Self>>) -> BalanceOf<ThisChain<Self>>;
}
@@ -90,8 +62,6 @@ pub trait ChainWithMessageLanes {
type Signer: Decode;
/// Signature type used on the chain.
type Signature: Decode;
/// Call type on the chain.
type Call: Encode + Decode;
/// Type of weight that is used on the chain. This would almost always be a regular
/// `frame_support::weight::Weight`. But since the meaning of weight on different chains
/// may be different, the `WeightOf<>` construct is used to avoid confusion between
@@ -104,15 +74,59 @@ pub trait ChainWithMessageLanes {
type MessageLaneInstance: Instance;
}
/// Message-lane related transaction parameters estimation.
#[derive(RuntimeDebug)]
pub struct MessageLaneTransaction<Weight> {
/// The estimated dispatch weight of the transaction.
pub dispatch_weight: Weight,
/// The estimated size of the encoded transaction.
pub size: u32,
}
/// This chain that has `message-lane` and `call-dispatch` modules.
pub trait ThisChainWithMessageLanes: ChainWithMessageLanes {
/// Call type on the chain.
type Call: Encode + Decode;
/// Are we accepting any messages to the given lane?
fn is_outbound_lane_enabled(lane: &LaneId) -> bool;
/// Maximal number of pending (not yet delivered) messages at this chain.
/// Maximal number of pending (not yet delivered) messages at This chain.
///
/// Any messages over this limit, will be rejected.
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce;
/// Estimate size and weight of single message delivery confirmation transaction at This chain.
fn estimate_delivery_confirmation_transaction() -> MessageLaneTransaction<WeightOf<Self>>;
/// Returns minimal transaction fee that must be paid for given transaction at This chain.
fn transaction_payment(transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self>;
}
/// Bridged chain that has `message-lane` and `call-dispatch` modules.
pub trait BridgedChainWithMessageLanes: ChainWithMessageLanes {
/// Maximal extrinsic size at Bridged chain.
fn maximal_extrinsic_size() -> u32;
/// Returns feasible weights range for given message payload at the Bridged chain.
///
/// If message is being sent with the weight that is out of this range, then it
/// should be rejected.
///
/// Weights returned from this function shall not include transaction overhead
/// (like weight of signature and signed extensions verification), because they're
/// already accounted by the `weight_of_delivery_transaction`. So this function should
/// return pure call dispatch weights range.
fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive<Self::Weight>;
/// Estimate size and weight of single message delivery transaction at the Bridged chain.
fn estimate_delivery_transaction(
message_payload: &[u8],
message_dispatch_weight: WeightOf<Self>,
) -> MessageLaneTransaction<WeightOf<Self>>;
/// Returns minimal transaction fee that must be paid for given transaction at the Bridged chain.
fn transaction_payment(transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self>;
}
pub(crate) type ThisChain<B> = <B as MessageBridge>::ThisChain;
@@ -123,35 +137,35 @@ pub(crate) type SignerOf<C> = <C as ChainWithMessageLanes>::Signer;
pub(crate) type SignatureOf<C> = <C as ChainWithMessageLanes>::Signature;
pub(crate) type WeightOf<C> = <C as ChainWithMessageLanes>::Weight;
pub(crate) type BalanceOf<C> = <C as ChainWithMessageLanes>::Balance;
pub(crate) type CallOf<C> = <C as ChainWithMessageLanes>::Call;
pub(crate) type MessageLaneInstanceOf<C> = <C as ChainWithMessageLanes>::MessageLaneInstance;
pub(crate) type CallOf<C> = <C as ThisChainWithMessageLanes>::Call;
/// Raw storage proof type (just raw trie nodes).
type RawStorageProof = Vec<Vec<u8>>;
/// Compute weight of transaction at runtime where:
/// Compute fee of transaction at runtime where:
///
/// - transaction payment pallet is being used;
/// - fee multiplier is zero.
pub fn transaction_weight_without_multiplier(
base_weight: Weight,
payload_size: Weight,
dispatch_weight: Weight,
) -> Weight {
// non-adjustable per-byte weight is mapped 1:1 to tx weight
let per_byte_weight = payload_size;
pub fn transaction_payment_without_multiplier<Balance: AtLeast32BitUnsigned>(
base_extrinsic_weight: Weight,
per_byte_fee: Balance,
weight_to_fee: impl Fn(Weight) -> Balance,
transaction: MessageLaneTransaction<Weight>,
) -> Balance {
// base fee is charged for every tx
let base_fee = weight_to_fee(base_extrinsic_weight);
// we assume that adjustable per-byte weight is always zero
let adjusted_per_byte_weight = 0;
// non-adjustable per-byte fee
let len_fee = per_byte_fee.saturating_mul(Balance::from(transaction.size));
// we assume that transaction tip we use is also zero
let transaction_tip_weight = 0;
// the adjustable part of the fee
//
// here we assume that the fee multiplier is zero, so this part is also always zero
let adjusted_weight_fee = Balance::zero();
base_weight
.saturating_add(per_byte_weight)
.saturating_add(adjusted_per_byte_weight)
.saturating_add(transaction_tip_weight)
.saturating_add(dispatch_weight)
base_fee.saturating_add(len_fee).saturating_add(adjusted_weight_fee)
}
/// Sub-module that is declaring types required for processing This -> Bridged chain messages.
@@ -266,7 +280,7 @@ pub mod source {
/// Return maximal message size of This -> Bridged chain message.
pub fn maximal_message_size<B: MessageBridge>() -> u32 {
super::target::maximal_incoming_message_size(B::maximal_extrinsic_size_on_target_chain())
super::target::maximal_incoming_message_size(BridgedChain::<B>::maximal_extrinsic_size())
}
/// Do basic Bridged-chain specific verification of This -> Bridged chain message.
@@ -277,7 +291,7 @@ pub mod source {
pub fn verify_chain_message<B: MessageBridge>(
payload: &FromThisChainMessagePayload<B>,
) -> Result<(), &'static str> {
let weight_limits = B::weight_limits_of_message_on_bridged_chain(&payload.call);
let weight_limits = BridgedChain::<B>::message_weight_limits(&payload.call);
if !weight_limits.contains(&payload.weight.into()) {
return Err("Incorrect message weight declared");
}
@@ -308,18 +322,17 @@ pub mod source {
relayer_fee_percent: u32,
) -> Result<BalanceOf<ThisChain<B>>, &'static str> {
// the fee (in Bridged tokens) of all transactions that are made on the Bridged chain
let delivery_fee = B::bridged_weight_to_bridged_balance(B::weight_of_delivery_transaction(&payload.call));
let dispatch_fee = B::bridged_weight_to_bridged_balance(payload.weight.into());
let delivery_transaction =
BridgedChain::<B>::estimate_delivery_transaction(&payload.call, payload.weight.into());
let delivery_transaction_fee = BridgedChain::<B>::transaction_payment(delivery_transaction);
// the fee (in This tokens) of all transactions that are made on This chain
let delivery_confirmation_fee =
B::this_weight_to_this_balance(B::weight_of_delivery_confirmation_transaction_on_this_chain());
let confirmation_transaction = ThisChain::<B>::estimate_delivery_confirmation_transaction();
let confirmation_transaction_fee = ThisChain::<B>::transaction_payment(confirmation_transaction);
// minimal fee (in This tokens) is a sum of all required fees
let minimal_fee = delivery_fee
.checked_add(&dispatch_fee)
.map(B::bridged_balance_to_this_balance)
.and_then(|fee| fee.checked_add(&delivery_confirmation_fee));
let minimal_fee =
B::bridged_balance_to_this_balance(delivery_transaction_fee).checked_add(&confirmation_transaction_fee);
// before returning, add extra fee that is paid to the relayer (relayer interest)
minimal_fee
@@ -681,31 +694,6 @@ mod tests {
type ThisChain = ThisChain;
type BridgedChain = BridgedChain;
fn maximal_extrinsic_size_on_target_chain() -> u32 {
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
}
fn weight_limits_of_message_on_bridged_chain(message_payload: &[u8]) -> RangeInclusive<Weight> {
let begin = std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight);
begin..=BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
}
fn weight_of_delivery_transaction(_message_payload: &[u8]) -> Weight {
DELIVERY_TRANSACTION_WEIGHT
}
fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight {
DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT
}
fn this_weight_to_this_balance(weight: Weight) -> ThisChainBalance {
ThisChainBalance(weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
}
fn bridged_weight_to_bridged_balance(weight: Weight) -> BridgedChainBalance {
BridgedChainBalance(weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
}
fn bridged_balance_to_this_balance(bridged_balance: BridgedChainBalance) -> ThisChainBalance {
ThisChainBalance(bridged_balance.0 * BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE as u32)
}
@@ -722,30 +710,6 @@ mod tests {
type ThisChain = BridgedChain;
type BridgedChain = ThisChain;
fn maximal_extrinsic_size_on_target_chain() -> u32 {
unreachable!()
}
fn weight_limits_of_message_on_bridged_chain(_message_payload: &[u8]) -> RangeInclusive<Weight> {
unreachable!()
}
fn weight_of_delivery_transaction(_message_payload: &[u8]) -> Weight {
unreachable!()
}
fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight {
unreachable!()
}
fn this_weight_to_this_balance(_weight: Weight) -> BridgedChainBalance {
unreachable!()
}
fn bridged_weight_to_bridged_balance(_weight: Weight) -> ThisChainBalance {
unreachable!()
}
fn bridged_balance_to_this_balance(_this_balance: ThisChainBalance) -> BridgedChainBalance {
unreachable!()
}
@@ -845,7 +809,6 @@ mod tests {
type AccountId = ThisChainAccountId;
type Signer = ThisChainSigner;
type Signature = ThisChainSignature;
type Call = ThisChainCall;
type Weight = frame_support::weights::Weight;
type Balance = ThisChainBalance;
@@ -853,6 +816,8 @@ mod tests {
}
impl ThisChainWithMessageLanes for ThisChain {
type Call = ThisChainCall;
fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
lane == TEST_LANE_ID
}
@@ -860,6 +825,38 @@ mod tests {
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE
}
fn estimate_delivery_confirmation_transaction() -> MessageLaneTransaction<WeightOf<Self>> {
MessageLaneTransaction {
dispatch_weight: DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT,
size: 0,
}
}
fn transaction_payment(transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
ThisChainBalance(transaction.dispatch_weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
}
}
impl BridgedChainWithMessageLanes for ThisChain {
fn maximal_extrinsic_size() -> u32 {
unreachable!()
}
fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Self::Weight> {
unreachable!()
}
fn estimate_delivery_transaction(
_message_payload: &[u8],
_message_dispatch_weight: WeightOf<Self>,
) -> MessageLaneTransaction<WeightOf<Self>> {
unreachable!()
}
fn transaction_payment(_transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
unreachable!()
}
}
struct BridgedChain;
@@ -869,7 +866,6 @@ mod tests {
type AccountId = BridgedChainAccountId;
type Signer = BridgedChainSigner;
type Signature = BridgedChainSignature;
type Call = BridgedChainCall;
type Weight = frame_support::weights::Weight;
type Balance = BridgedChainBalance;
@@ -877,6 +873,8 @@ mod tests {
}
impl ThisChainWithMessageLanes for BridgedChain {
type Call = BridgedChainCall;
fn is_outbound_lane_enabled(_lane: &LaneId) -> bool {
unreachable!()
}
@@ -884,6 +882,39 @@ mod tests {
fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
unreachable!()
}
fn estimate_delivery_confirmation_transaction() -> MessageLaneTransaction<WeightOf<Self>> {
unreachable!()
}
fn transaction_payment(_transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
unreachable!()
}
}
impl BridgedChainWithMessageLanes for BridgedChain {
fn maximal_extrinsic_size() -> u32 {
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
}
fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive<Self::Weight> {
let begin = std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight);
begin..=BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
}
fn estimate_delivery_transaction(
_message_payload: &[u8],
message_dispatch_weight: WeightOf<Self>,
) -> MessageLaneTransaction<WeightOf<Self>> {
MessageLaneTransaction {
dispatch_weight: DELIVERY_TRANSACTION_WEIGHT + message_dispatch_weight,
size: 0,
}
}
fn transaction_payment(transaction: MessageLaneTransaction<WeightOf<Self>>) -> BalanceOf<Self> {
BridgedChainBalance(transaction.dispatch_weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32)
}
}
fn test_lane_outbound_data() -> OutboundLaneData {