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

Fee-market companions for the darwinia v0.12.5 #214

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix slash base value (#215)
* Fix slash

* Self review

* Update test

* Update out of slot calc

* Update docs

Co-authored-by: HackFisher <hackfisher@gmail.com>
  • Loading branch information
boundless-forest and hackfisher committed Oct 31, 2022
commit 8e6a88877403b0355c4937967854dae8417b049b
8 changes: 4 additions & 4 deletions modules/fee-market/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ After a user sends a cross-chain transaction, the fee market system calculates t

As long as the order is confirmed before the last block of the nth slot, we consider it to be delivered on time, and the calculation of rewards and penalties varies depending on when the message is confirmed.

Suppose the cross-chain message has n slots, the message is confirmed at the m-th slot, and `Pm` denotes the quote price of m-th slot. At this point, the assigned relayers from 0 to m slots will be penalized, and the penalty will be calculated as `AssignedRelayerSlashRatio * collateral`, while the assigned relayers from m to n slots will receive a reward for ensuring the message is completed on time `(DutyRelayersRewardRatio * (fee - Pm)) / (n - m)`. `Pm` plus the penalties for the other assigned relayers mentioned above will be distributed as new rewards to the message delivery relayer and the message confirm relayer, where the message delivery relayer receive the `MessageRelayersRewardRatio` of this reward, the message confirm relayer gets the `ConfirmRelayersRewardRatio` of this reward. The rest of the fee will be given to treasury.
Suppose the cross-chain message has n slots, the message is confirmed at the m-th slot, and `Pm` denotes the quote price of m-th slot. At this point, the assigned relayers from 0 to m slots will be penalized, and the penalty will be calculated as `AssignedRelayerSlashRatio * CollateralPerOrder`, while the assigned relayers from m to n slots will receive a reward for ensuring the message is completed on time `(DutyRelayersRewardRatio * (fee - Pm)) / (n - m)`. `Pm` plus the penalties for the other assigned relayers mentioned above will be distributed as new rewards to the message delivery relayer and the message confirm relayer, where the message delivery relayer receive the `MessageRelayersRewardRatio` of this reward, the message confirm relayer gets the `ConfirmRelayersRewardRatio` of this reward. The rest of the fee will be given to treasury.

- The cross-chain transaction is confirmed after the last block of the n slot.

We believe that this cross-chain transaction is severely delayed, in which case all assigned relayers will be heavily penalized by deducting the `AssignedRelayerSlashRatio` of the collateral and calculating an additional penalty amount based on the delay time. These penalty amounts, plus the cross-chain fees paid by users, will be distributed as new rewards to the message delivery relayer and the message confirm relayer, where the message delivery relayer receive the `MessageRelayersRewardRatio` of this reward, the message confirm relayer gets the `ConfirmRelayersRewardRatio` of this reward.
We believe that this cross-chain transaction is severely delayed, in which case all assigned relayers will be heavily penalized by deducting the `AssignedRelayerSlashRatio` of the `CollateralPerOrder` and calculating an additional penalty amount based on the delay time. These penalty amounts, plus the cross-chain fees paid by users, will be distributed as new rewards to the message delivery relayer and the message confirm relayer, where the message delivery relayer receive the `MessageRelayersRewardRatio` of this reward, the message confirm relayer gets the `ConfirmRelayersRewardRatio` of this reward.


The following diagram shows how rewards are distributed:
Expand All @@ -67,9 +67,9 @@ message fee -

### An example

1. Assume that relayers `R1`, `R2`, `R3`, `R4` and `R5` have registered with the fee market and are all running relayer clients capable of delivering messages with quote prices of `P1=10`, `P2=20`, `P3=30`, `P4=4`0 and `P5=50` and are registered with a locked asset of `100`.
1. Assume that relayers `R1`, `R2`, `R3`, `R4` and `R5` have registered with the fee market and are all running relayer clients capable of delivering messages with quote prices of `P1=10`, `P2=20`, `P3=30`, `P4=4`0 and `P5=50` and are registered with a locked asset of `300`.
2. Assume that the total number of assigned relayers specified by the fee market system is `3` (default). In this case, the fee market will generate a cross-chain fee of `30` (10 < 20 < 30 < 40 < 50) and the set of assigned relayers is `R1, R2, R3`.
3. Assume that the slot value in the fee market runtime is equal to `50` blocks.
3. Assume that the slot value is equal to `50` blocks and `CollateralPerOrder` is equal to `100` in the fee market runtime.

In this case, suppose the source chain receives a cross-chain message at height `100` and the user pays a cross-chain fee of `30`. After the source chain receives the message, the fee market assigns `R1, R2 and R3` as the assigned relayers for the message, respectively, and their corresponding time slots are `(100, 150)`, `(150, 200)`, `(200, 250)`

Expand Down
4 changes: 2 additions & 2 deletions modules/fee-market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
{
count += 1;
orders_locked_collateral =
orders_locked_collateral.saturating_add(order.locked_collateral);
orders_locked_collateral.saturating_add(order.collateral_per_assigned_relayer);
}
}

Expand Down Expand Up @@ -578,7 +578,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {

/// The assigned relayers slash trait
pub trait Slasher<T: Config<I>, I: 'static> {
fn cal_slash_amount(
fn calc_amount(
collateral_per_order: BalanceOf<T, I>,
timeout: T::BlockNumber,
) -> BalanceOf<T, I>;
Expand Down
2 changes: 1 addition & 1 deletion modules/fee-market/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ frame_support::parameter_types! {

pub struct TestSlasher;
impl<T: Config<I>, I: 'static> Slasher<T, I> for TestSlasher {
fn cal_slash_amount(
fn calc_amount(
collateral_per_order: BalanceOf<T, I>,
timeout: T::BlockNumber,
) -> BalanceOf<T, I> {
Expand Down
52 changes: 21 additions & 31 deletions modules/fee-market/src/s2s/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ where
// The order created when message was accepted, so we can always get the order info.
if let Some(order) = <Orders<T, I>>::get(&(lane_id, message_nonce)) {
let mut reward_item = RewardItem::new();
let order_collater = order.collateral_per_assigned_relayer;

let (message_reward, treasury_reward) = match order.confirmed_info() {
// When the order is confirmed at the first slot, no assigned relayers will be
Expand Down Expand Up @@ -218,8 +219,7 @@ where
&order,
&r,
relayer_fund_account,
T::AssignedRelayerSlashRatio::get()
* Pallet::<T, I>::relayer_locked_collateral(&r),
T::AssignedRelayerSlashRatio::get() * order_collater,
);
slot_offensive_slash += amount;
}
Expand All @@ -242,35 +242,27 @@ where
_ => {
let mut slot_offensive_slash = BalanceOf::<T, I>::zero();
for r in order.assigned_relayers_slice() {
// 1. For the fixed part
let mut slash_amount = T::AssignedRelayerSlashRatio::get()
* Pallet::<T, I>::relayer_locked_collateral(&r.id);

// 2. For the dynamic part
slash_amount += T::Slasher::cal_slash_amount(
order.locked_collateral,
// The fixed part
let mut total = T::AssignedRelayerSlashRatio::get() * order_collater;
// The dynamic part
total += T::Slasher::calc_amount(
order_collater,
order.comfirm_delay().unwrap_or_default(),
);

// The total_slash_amount can't be greater than the slash_protect.
if let Some(slash_protect) = Pallet::<T, I>::collateral_slash_protect()
{
// slash_amount = sp_std::cmp::min(slash_amount, slash_protect);
slash_amount = slash_amount.min(slash_protect);
total = total.min(slash_protect);
}

// The total_slash_amount can't be greater than the locked_collateral.
let locked_collateral =
Pallet::<T, I>::relayer_locked_collateral(&r.id);
slash_amount = sp_std::cmp::min(slash_amount, locked_collateral);

let amount = slash_assigned_relayer::<T, I>(
let actual_amount = slash_assigned_relayer::<T, I>(
&order,
&r.id,
relayer_fund_account,
slash_amount,
total,
);
slot_offensive_slash += amount;
slot_offensive_slash += actual_amount;
}

(order.fee().saturating_add(slot_offensive_slash), None)
Expand Down Expand Up @@ -310,33 +302,31 @@ pub(crate) fn slash_assigned_relayer<T: Config<I>, I: 'static>(
fund_account: &T::AccountId,
amount: BalanceOf<T, I>,
) -> BalanceOf<T, I> {
let locked_collateral = Pallet::<T, I>::relayer_locked_collateral(who);
T::Currency::remove_lock(T::LockId::get(), who);
debug_assert!(
locked_collateral >= amount,
"The locked collateral must alway greater than slash max"
);
let slash_amount = amount.min(order.collateral_per_assigned_relayer);

T::Currency::remove_lock(T::LockId::get(), who);
let pay_result = <T as Config<I>>::Currency::transfer(
who,
fund_account,
amount,
slash_amount,
ExistenceRequirement::AllowDeath,
);
let report = SlashReport::new(order, who.clone(), amount);

let locked_collateral = Pallet::<T, I>::relayer_locked_collateral(who);
let report = SlashReport::new(order, who.clone(), slash_amount);
match pay_result {
Ok(_) => {
crate::Pallet::<T, I>::update_relayer_after_slash(
who,
locked_collateral.saturating_sub(amount),
locked_collateral.saturating_sub(slash_amount),
report,
);
log::trace!("Slash {:?} amount: {:?}", who, amount);
return amount;
log::trace!("Slash {:?} slash_amount: {:?}", who, slash_amount);
return slash_amount;
},
Err(e) => {
crate::Pallet::<T, I>::update_relayer_after_slash(who, locked_collateral, report);
log::error!("Slash {:?} amount {:?}, err {:?}", who, amount, e)
log::error!("Slash {:?} amount {:?}, err {:?}", who, slash_amount, e)
},
}

Expand Down
Loading