Skip to content

Commit

Permalink
Move calculation relayer reward into `MessageDeliveryAndDispatchPayme…
Browse files Browse the repository at this point in the history
…nt` (paritytech#1153)

* Refactor logic

* Thanks svyatonik help, it compile

* Fix failed unit test

* Remove compile warning

* Rename

* Return result in pay_relayers_rewards

* Fix runtime compile issue

* Use MessageNonce

* Fix review issue

* Missing u64 replacement

* Revert return type changes

* Fix merge issue

* Remove useless clone
  • Loading branch information
boundless-forest authored and serban300 committed Apr 9, 2024
1 parent b9b385a commit 9dcfac4
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 58 deletions.
1 change: 1 addition & 0 deletions bridges/bin/millau/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
type MessageDeliveryAndDispatchPayment =
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
Runtime,
(),
pallet_balances::Pallet<Runtime>,
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
Expand Down
1 change: 1 addition & 0 deletions bridges/bin/rialto/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
type MessageDeliveryAndDispatchPayment =
pallet_bridge_messages::instant_payments::InstantCurrencyPayments<
Runtime,
(),
pallet_balances::Pallet<Runtime>,
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
Expand Down
71 changes: 55 additions & 16 deletions bridges/modules/messages/src/instant_payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
//! The payment is first transferred to a special `relayers-fund` account and only transferred
//! to the actual relayer in case confirmation is received.

use crate::OutboundMessages;

use bp_messages::{
source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards, Sender},
MessageNonce,
LaneId, MessageKey, MessageNonce, UnrewardedRelayer,
};
use codec::Encode;
use frame_support::traits::{Currency as CurrencyT, ExistenceRequirement, Get};
use num_traits::Zero;
use num_traits::{SaturatingAdd, Zero};
use sp_runtime::traits::Saturating;
use sp_std::fmt::Debug;
use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, ops::RangeInclusive};

/// Instant message payments made in given currency.
///
Expand All @@ -42,16 +44,17 @@ use sp_std::fmt::Debug;
/// to the relayer account.
/// NOTE It's within relayer's interest to keep their balance above ED as well, to make sure they
/// can receive the payment.
pub struct InstantCurrencyPayments<T, Currency, GetConfirmationFee, RootAccount> {
_phantom: sp_std::marker::PhantomData<(T, Currency, GetConfirmationFee, RootAccount)>,
pub struct InstantCurrencyPayments<T, I, Currency, GetConfirmationFee, RootAccount> {
_phantom: sp_std::marker::PhantomData<(T, I, Currency, GetConfirmationFee, RootAccount)>,
}

impl<T, Currency, GetConfirmationFee, RootAccount>
impl<T, I, Currency, GetConfirmationFee, RootAccount>
MessageDeliveryAndDispatchPayment<T::AccountId, Currency::Balance>
for InstantCurrencyPayments<T, Currency, GetConfirmationFee, RootAccount>
for InstantCurrencyPayments<T, I, Currency, GetConfirmationFee, RootAccount>
where
T: frame_system::Config,
Currency: CurrencyT<T::AccountId>,
T: frame_system::Config + crate::Config<I>,
I: 'static,
Currency: CurrencyT<T::AccountId, Balance = T::OutboundMessageFee>,
Currency::Balance: From<MessageNonce>,
GetConfirmationFee: Get<Currency::Balance>,
RootAccount: Get<Option<T::AccountId>>,
Expand Down Expand Up @@ -86,17 +89,53 @@ where
}

fn pay_relayers_rewards(
lane_id: LaneId,
messages_relayers: VecDeque<UnrewardedRelayer<T::AccountId>>,
confirmation_relayer: &T::AccountId,
relayers_rewards: RelayersRewards<T::AccountId, Currency::Balance>,
received_range: &RangeInclusive<MessageNonce>,
relayer_fund_account: &T::AccountId,
) {
pay_relayers_rewards::<Currency, _>(
confirmation_relayer,
relayers_rewards,
relayer_fund_account,
GetConfirmationFee::get(),
);
let relayers_rewards =
cal_relayers_rewards::<T, I>(lane_id, messages_relayers, received_range);
if !relayers_rewards.is_empty() {
pay_relayers_rewards::<Currency, _>(
confirmation_relayer,
relayers_rewards,
relayer_fund_account,
GetConfirmationFee::get(),
);
}
}
}

/// Calculate the relayers rewards
pub(crate) fn cal_relayers_rewards<T, I>(
lane_id: LaneId,
messages_relayers: VecDeque<UnrewardedRelayer<T::AccountId>>,
received_range: &RangeInclusive<MessageNonce>,
) -> RelayersRewards<T::AccountId, T::OutboundMessageFee>
where
T: frame_system::Config + crate::Config<I>,
I: 'static,
{
// remember to reward relayers that have delivered messages
// this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain
let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> = RelayersRewards::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());

// loop won't proceed if current entry is ahead of received range (begin > end).
// this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain
let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default();
for nonce in nonce_begin..nonce_end + 1 {
let message_data = OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce })
.expect("message was just confirmed; we never prune unconfirmed messages; qed");
relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee);
relayer_reward.messages += 1;
}
}
relayers_rewards
}

/// Pay rewards to given relayers, optionally rewarding confirmation relayer.
Expand Down
46 changes: 12 additions & 34 deletions bridges/modules/messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use crate::{
use bp_messages::{
source_chain::{
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed,
OnMessageAccepted, RelayersRewards, TargetHeaderChain,
OnMessageAccepted, TargetHeaderChain,
},
target_chain::{
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
Expand Down Expand Up @@ -143,7 +143,13 @@ pub mod pallet {
/// Payload type of outbound messages. This payload is dispatched on the bridged chain.
type OutboundPayload: Parameter + Size;
/// Message fee type of outbound messages. This fee is paid on this chain.
type OutboundMessageFee: Default + From<u64> + PartialOrd + Parameter + SaturatingAdd + Zero;
type OutboundMessageFee: Default
+ From<u64>
+ PartialOrd
+ Parameter
+ SaturatingAdd
+ Zero
+ Copy;

/// Payload type of inbound messages. This payload is dispatched on this chain.
type InboundPayload: Decode;
Expand Down Expand Up @@ -548,8 +554,6 @@ pub mod pallet {

// mark messages as delivered
let mut lane = outbound_lane::<T, I>(lane_id);
let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> =
RelayersRewards::new();
let last_delivered_nonce = lane_data.last_delivered_nonce();
let confirmed_messages = match lane.confirm_delivery(
relayers_state.total_messages,
Expand Down Expand Up @@ -620,40 +624,14 @@ pub mod pallet {
let received_range = confirmed_messages.begin..=confirmed_messages.end;
Self::deposit_event(Event::MessagesDelivered(lane_id, confirmed_messages));

// remember to reward relayers that have delivered messages
// this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the
// bridged chain
for entry in lane_data.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());

// loop won't proceed if current entry is ahead of received range (begin > end).
// this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged
// chain
let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default();
for nonce in nonce_begin..nonce_end + 1 {
let message_data = OutboundMessages::<T, I>::get(MessageKey {
lane_id,
nonce,
})
.expect(
"message was just confirmed; we never prune unconfirmed messages; qed",
);
relayer_reward.reward =
relayer_reward.reward.saturating_add(&message_data.fee);
relayer_reward.messages += 1;
}
}
}

// if some new messages have been confirmed, reward relayers
if !relayers_rewards.is_empty() {
// if some new messages have been confirmed, reward relayers
let relayer_fund_account =
relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
<T as Config<I>>::MessageDeliveryAndDispatchPayment::pay_relayers_rewards(
lane_id,
lane_data.relayers,
&confirmation_relayer,
relayers_rewards,
&received_range,
&relayer_fund_account,
);
}
Expand Down
17 changes: 12 additions & 5 deletions bridges/modules/messages/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
// From construct_runtime macro
#![allow(clippy::from_over_into)]

use crate::Config;
use crate::{instant_payments::cal_relayers_rewards, Config};

use bitvec::prelude::*;
use bp_messages::{
source_chain::{
LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed,
OnMessageAccepted, RelayersRewards, Sender, TargetHeaderChain,
OnMessageAccepted, Sender, TargetHeaderChain,
},
target_chain::{
DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
Expand All @@ -43,7 +43,10 @@ use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
FixedU128, Perbill,
};
use std::collections::BTreeMap;
use std::{
collections::{BTreeMap, VecDeque},
ops::RangeInclusive,
};

pub type AccountId = u64;
pub type Balance = u64;
Expand Down Expand Up @@ -350,11 +353,15 @@ impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee>
}

fn pay_relayers_rewards(
lane_id: LaneId,
message_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
_confirmation_relayer: &AccountId,
relayers_rewards: RelayersRewards<AccountId, TestMessageFee>,
received_range: &RangeInclusive<MessageNonce>,
_relayer_fund_account: &AccountId,
) {
for (relayer, reward) in relayers_rewards {
let relayers_rewards =
cal_relayers_rewards::<TestRuntime, ()>(lane_id, message_relayers, received_range);
for (relayer, reward) in &relayers_rewards {
let key = (b":relayer-reward:", relayer, reward.reward).encode();
frame_support::storage::unhashed::put(&key, &true);
}
Expand Down
15 changes: 12 additions & 3 deletions bridges/primitives/messages/src/source_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@

use crate::{DeliveredMessages, InboundLaneData, LaneId, MessageNonce, OutboundLaneData};

use crate::UnrewardedRelayer;
use bp_runtime::Size;
use frame_support::{weights::Weight, Parameter, RuntimeDebug};
use sp_std::{collections::btree_map::BTreeMap, fmt::Debug};
use sp_std::{
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
fmt::Debug,
ops::RangeInclusive,
};

/// The sender of the message on the source chain.
pub type Sender<AccountId> = frame_system::RawOrigin<AccountId>;
Expand Down Expand Up @@ -122,8 +127,10 @@ pub trait MessageDeliveryAndDispatchPayment<AccountId, Balance> {
/// The implementation may also choose to pay reward to the `confirmation_relayer`, which is
/// a relayer that has submitted delivery confirmation transaction.
fn pay_relayers_rewards(
lane_id: LaneId,
messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
confirmation_relayer: &AccountId,
relayers_rewards: RelayersRewards<AccountId, Balance>,
received_range: &RangeInclusive<MessageNonce>,
relayer_fund_account: &AccountId,
);
}
Expand Down Expand Up @@ -240,8 +247,10 @@ impl<AccountId, Balance> MessageDeliveryAndDispatchPayment<AccountId, Balance>
}

fn pay_relayers_rewards(
_lane_id: LaneId,
_messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
_confirmation_relayer: &AccountId,
_relayers_rewards: RelayersRewards<AccountId, Balance>,
_received_range: &RangeInclusive<MessageNonce>,
_relayer_fund_account: &AccountId,
) {
}
Expand Down

0 comments on commit 9dcfac4

Please sign in to comment.