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

Commit

Permalink
Companions fee market (#113)
Browse files Browse the repository at this point in the history
* Companion for 96, fix benchmark

* Check order capacity when relayer enroll (#93)

* Add check logic

* Update test file

* Add necessary reward event (#89)

* Refactor the total reward cal

* Code Clean

* Fix test

* Add OrderCreated event

* Self review

* Update comment

* Update OrderCreate event to include relayers

* Fix review
  • Loading branch information
boundless-forest committed Jun 13, 2022
1 parent c6b374e commit 69b33c7
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 98 deletions.
20 changes: 20 additions & 0 deletions modules/fee-market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use sp_runtime::{
};
use sp_std::vec::Vec;
// --- darwinia-network ---
use s2s::RewardItem;
use types::{Order, Relayer, SlashReport};

pub type AccountId<T> = <T as frame_system::Config>::AccountId;
Expand Down Expand Up @@ -107,6 +108,17 @@ pub mod pallet {
UpdateAssignedRelayersNumber(u32),
/// Slash report
FeeMarketSlash(SlashReport<T::AccountId, T::BlockNumber, BalanceOf<T, I>>),
/// Create new order. \[lane_id, message_nonce, order_fee, assigned_relayers,
/// out_of_slots_time\]
OrderCreated(
LaneId,
MessageNonce,
BalanceOf<T, I>,
Vec<T::AccountId>,
Option<T::BlockNumber>,
),
/// Reward distribute of the order. \[lane_id, message_nonce, rewards\]
OrderReward(LaneId, MessageNonce, RewardItem<T::AccountId, BalanceOf<T, I>>),
}

#[pallet::error]
Expand All @@ -117,6 +129,8 @@ pub mod pallet {
AlreadyEnrolled,
/// This relayer doesn't enroll ever.
NotEnrolled,
/// Locked collateral is too low to cover one order.
CollateralTooLow,
/// Update locked collateral is not allow since some orders are not confirm.
StillHasOrdersNotConfirmed,
/// The fee is lower than MinimumRelayFee.
Expand Down Expand Up @@ -206,6 +220,12 @@ pub mod pallet {
T::Currency::free_balance(&who) >= lock_collateral,
<Error<T, I>>::InsufficientBalance
);

ensure!(
Self::collateral_to_order_capacity(lock_collateral) > 0,
<Error<T, I>>::CollateralTooLow
);

if let Some(fee) = relay_fee {
ensure!(fee >= T::MinimumRelayFee::get(), <Error<T, I>>::RelayFeeTooLow);
}
Expand Down
19 changes: 14 additions & 5 deletions modules/fee-market/src/s2s/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,25 @@ impl<T: Config<I>, I: 'static> OnMessageAccepted for FeeMarketMessageAcceptedHan
*message,
now,
T::CollateralPerOrder::get(),
assigned_relayers,
assigned_relayers.clone(),
T::Slot::get(),
);
// Store the create order
<Orders<T, I>>::insert((order.lane, order.message), order.clone());

let ids: Vec<T::AccountId> = assigned_relayers.iter().map(|r| r.id.clone()).collect();
Pallet::<T, I>::deposit_event(Event::OrderCreated(
order.lane,
order.message,
order.fee(),
ids,
order.range_end(),
));
}

// one read for assigned relayers
// one write for store order
// Storage: FeeMarket AssignedRelayers (r:1 w:0)
// Storage: FeeMarket Orders (r:0 w:1)
// Storage: System Events (r:0 w:1)
<T as frame_system::Config>::DbWeight::get().reads_writes(1, 1)
}
}
Expand All @@ -66,8 +76,7 @@ impl<T: Config<I>, I: 'static> OnDeliveryConfirmed for FeeMarketMessageConfirmed
}
}

// one db read for get order
// one db write for update order confirm time
// Storage: FeeMarket Orders (r:1 w:1)
<T as frame_system::Config>::DbWeight::get().reads_writes(1, 1)
}
}
2 changes: 1 addition & 1 deletion modules/fee-market/src/s2s/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// along with Darwinia. If not, see <https://www.gnu.org/licenses/>.

pub mod payment;
pub use payment::FeeMarketPayment;
pub use payment::{FeeMarketPayment, RewardItem};

pub mod callbacks;
pub use callbacks::{FeeMarketMessageAcceptedHandler, FeeMarketMessageConfirmedHandler};
165 changes: 105 additions & 60 deletions modules/fee-market/src/s2s/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use sp_std::{
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
ops::RangeInclusive,
};
use scale_info::TypeInfo;
// --- darwinia-network ---
use crate::{Config, Orders, Pallet, *};

Expand Down Expand Up @@ -77,61 +78,54 @@ where
received_range: &RangeInclusive<MessageNonce>,
relayer_fund_account: &T::AccountId,
) {
let RewardsBook {
messages_relayers_rewards,
confirmation_relayer_rewards,
assigned_relayers_rewards,
treasury_total_rewards,
} = slash_and_calculate_rewards::<T, I>(
lane_id,
messages_relayers,
received_range,
relayer_fund_account,
);
let RewardsBook { deliver_sum, confirm_sum, assigned_relayers_sum, treasury_sum } =
slash_and_calculate_rewards::<T, I>(
lane_id,
messages_relayers,
confirmation_relayer.clone(),
received_range,
relayer_fund_account,
);

// Pay confirmation relayer rewards
do_reward::<T, I>(relayer_fund_account, confirmation_relayer, confirmation_relayer_rewards);
do_reward::<T, I>(relayer_fund_account, confirmation_relayer, confirm_sum);
// Pay messages relayers rewards
for (relayer, reward) in messages_relayers_rewards {
for (relayer, reward) in deliver_sum {
do_reward::<T, I>(relayer_fund_account, &relayer, reward);
}
// Pay assign relayer reward
for (relayer, reward) in assigned_relayers_rewards {
for (relayer, reward) in assigned_relayers_sum {
do_reward::<T, I>(relayer_fund_account, &relayer, reward);
}
// Pay treasury reward
// Pay treasury_sum reward
do_reward::<T, I>(
relayer_fund_account,
&T::TreasuryPalletId::get().into_account(),
treasury_total_rewards,
treasury_sum,
);
}
}

/// Slash and calculate rewards for messages_relayers, confirmation relayers, treasury,
/// Slash and calculate rewards for messages_relayers, confirmation relayers, treasury_sum,
/// assigned_relayers
pub fn slash_and_calculate_rewards<T, I>(
lane_id: LaneId,
messages_relayers: VecDeque<UnrewardedRelayer<T::AccountId>>,
confirm_relayer: T::AccountId,
received_range: &RangeInclusive<MessageNonce>,
relayer_fund_account: &T::AccountId,
) -> RewardsBook<T::AccountId, BalanceOf<T, I>>
) -> RewardsBook<T, I>
where
T: frame_system::Config + Config<I>,
I: 'static,
{
let mut confirmation_rewards = BalanceOf::<T, I>::zero();
let mut messages_rewards = BTreeMap::<T::AccountId, BalanceOf<T, I>>::new();
let mut assigned_relayers_rewards = BTreeMap::<T::AccountId, BalanceOf<T, I>>::new();
let mut treasury_total_rewards = BalanceOf::<T, I>::zero();

let mut rewards_book = RewardsBook::new();
for entry in messages_relayers {
let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start());
let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end());

for message_nonce in nonce_begin..nonce_end + 1 {
// The order created when message was accepted, so we can always get the order info
// below.
// 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)) {
// The confirm_time of the order is set in the `OnDeliveryConfirmed` callback. And
// the callback function was called as source chain received message delivery proof,
Expand All @@ -140,31 +134,29 @@ where
order.confirm_time.unwrap_or_else(|| frame_system::Pallet::<T>::block_number());
let message_fee = order.fee();

let mut reward_item = RewardItem::new();
let message_reward;
let confirm_reward;

if let Some((who, base_fee)) =
order.required_delivery_relayer_for_time(order_confirm_time)
{
// message fee - base fee => treasury
let treasury_reward = message_fee.saturating_sub(base_fee);
treasury_total_rewards = treasury_total_rewards.saturating_add(treasury_reward);
// message fee - base fee => treasury_sum
reward_item.to_treasury = Some(message_fee.saturating_sub(base_fee));

// 60% * base fee => assigned_relayers_rewards
let assigned_relayers_reward = T::AssignedRelayersRewardRatio::get() * base_fee;
assigned_relayers_rewards
.entry(who)
.and_modify(|r| *r = r.saturating_add(assigned_relayers_reward))
.or_insert(assigned_relayers_reward);
// AssignedRelayersRewardRatio * base fee => slot relayer
let slot_relayer_reward = T::AssignedRelayersRewardRatio::get() * base_fee;
reward_item.to_slot_relayer = Some((who, slot_relayer_reward));

let bridger_relayers_reward = base_fee.saturating_sub(assigned_relayers_reward);

// 80% * (1 - 60%) * base_fee => message relayer
let bridger_relayers_reward = base_fee.saturating_sub(slot_relayer_reward);
// MessageRelayersRewardRatio * (1 - AssignedRelayersRewardRatio) * base_fee =>
// message relayer
message_reward = T::MessageRelayersRewardRatio::get() * bridger_relayers_reward;
// 20% * (1 - 60%) * base_fee => confirm relayer
// ConfirmRelayersRewardRatio * (1 - AssignedRelayersRewardRatio) * base_fee =>
// confirm relayer
confirm_reward = T::ConfirmRelayersRewardRatio::get() * bridger_relayers_reward;
} else {
// The order delivery is delay
// The order delivery is delay, slash occurs.
let mut total_slash = message_fee;

// calculate slash amount
Expand All @@ -190,29 +182,26 @@ where
}
total_slash += assigned_relayers_slash;

// 80% total slash => confirm relayer
// MessageRelayersRewardRatio total slash => message relayer
message_reward = T::MessageRelayersRewardRatio::get() * total_slash;
// 20% total slash => confirm relayer
// ConfirmRelayersRewardRatio total slash => confirm relayer
confirm_reward = T::ConfirmRelayersRewardRatio::get() * total_slash;
}

// Update confirmation relayer total rewards
confirmation_rewards = confirmation_rewards.saturating_add(confirm_reward);
// Update message relayers total rewards
messages_rewards
.entry(entry.relayer.clone())
.and_modify(|r| *r = r.saturating_add(message_reward))
.or_insert(message_reward);
reward_item.to_message_relayer = Some((entry.clone().relayer, message_reward));
reward_item.to_confirm_relayer = Some((confirm_relayer.clone(), confirm_reward));

Pallet::<T, I>::deposit_event(Event::OrderReward(
lane_id,
message_nonce,
reward_item.clone(),
));

rewards_book.add_reward_item(reward_item);
}
}
}

RewardsBook {
messages_relayers_rewards: messages_rewards,
confirmation_relayer_rewards: confirmation_rewards,
assigned_relayers_rewards,
treasury_total_rewards,
}
rewards_book
}

/// Do slash for absent assigned relayers
Expand Down Expand Up @@ -278,10 +267,66 @@ pub(crate) fn do_reward<T: Config<I>, I: 'static>(
}
}

/// Record the concrete reward distribution of certain order
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, TypeInfo)]
pub struct RewardItem<AccountId, Balance> {
pub to_slot_relayer: Option<(AccountId, Balance)>,
pub to_treasury: Option<Balance>,
pub to_message_relayer: Option<(AccountId, Balance)>,
pub to_confirm_relayer: Option<(AccountId, Balance)>,
}

impl<AccountId, Balance> RewardItem<AccountId, Balance> {
fn new() -> Self {
Self {
to_slot_relayer: None,
to_treasury: None,
to_message_relayer: None,
to_confirm_relayer: None,
}
}
}

/// Record the calculation rewards result
pub struct RewardsBook<AccountId, Balance> {
pub messages_relayers_rewards: BTreeMap<AccountId, Balance>,
pub confirmation_relayer_rewards: Balance,
pub assigned_relayers_rewards: BTreeMap<AccountId, Balance>,
pub treasury_total_rewards: Balance,
#[derive(Clone, Debug, Eq, PartialEq, TypeInfo)]
pub struct RewardsBook<T: Config<I>, I: 'static> {
pub deliver_sum: BTreeMap<T::AccountId, BalanceOf<T, I>>,
pub confirm_sum: BalanceOf<T, I>,
pub assigned_relayers_sum: BTreeMap<T::AccountId, BalanceOf<T, I>>,
pub treasury_sum: BalanceOf<T, I>,
}

impl<T: Config<I>, I: 'static> RewardsBook<T, I> {
fn new() -> Self {
Self {
deliver_sum: BTreeMap::new(),
confirm_sum: BalanceOf::<T, I>::zero(),
assigned_relayers_sum: BTreeMap::new(),
treasury_sum: BalanceOf::<T, I>::zero(),
}
}

fn add_reward_item(&mut self, item: RewardItem<T::AccountId, BalanceOf<T, I>>) {
if let Some((id, reward)) = item.to_slot_relayer {
self.assigned_relayers_sum
.entry(id)
.and_modify(|r| *r = r.saturating_add(reward))
.or_insert(reward);
}

if let Some(reward) = item.to_treasury {
self.treasury_sum = self.treasury_sum.saturating_add(reward);
}

if let Some((id, reward)) = item.to_message_relayer {
self.deliver_sum
.entry(id)
.and_modify(|r| *r = r.saturating_add(reward))
.or_insert(reward);
}

if let Some((_id, reward)) = item.to_confirm_relayer {
self.confirm_sum = self.confirm_sum.saturating_add(reward);
}
}
}
Loading

0 comments on commit 69b33c7

Please sign in to comment.