Per-lane rewards in pallet-bridge-relayers (#1665)

* per-lane rewards in pallet-bridge-relayers

* add lane id to RewardPaid event

* clippy

* fix benchmarks
This commit is contained in:
Svyatoslav Nikolsky
2022-11-28 16:49:05 +03:00
committed by Bastian Köcher
parent c03d99cd09
commit ea98118031
6 changed files with 147 additions and 72 deletions
+78 -28
View File
@@ -20,8 +20,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
use bp_messages::LaneId;
use bp_relayers::PaymentProcedure;
use sp_arithmetic::traits::AtLeast32BitUnsigned;
use frame_support::sp_runtime::Saturating;
use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
use sp_std::marker::PhantomData;
use weights::WeightInfo;
@@ -63,24 +65,54 @@ pub mod pallet {
impl<T: Config> Pallet<T> {
/// Claim accumulated rewards.
#[pallet::weight(T::WeightInfo::claim_rewards())]
pub fn claim_rewards(origin: OriginFor<T>) -> DispatchResult {
pub fn claim_rewards(origin: OriginFor<T>, lane_id: LaneId) -> DispatchResult {
let relayer = ensure_signed(origin)?;
RelayerRewards::<T>::try_mutate_exists(&relayer, |maybe_reward| -> DispatchResult {
let reward = maybe_reward.take().ok_or(Error::<T>::NoRewardForRelayer)?;
T::PaymentProcedure::pay_reward(&relayer, reward).map_err(|e| {
log::trace!(
target: LOG_TARGET,
"Failed to pay rewards to {:?}: {:?}",
relayer,
e,
);
Error::<T>::FailedToPayReward
})?;
RelayerRewards::<T>::try_mutate_exists(
&relayer,
lane_id,
|maybe_reward| -> DispatchResult {
let reward = maybe_reward.take().ok_or(Error::<T>::NoRewardForRelayer)?;
T::PaymentProcedure::pay_reward(&relayer, lane_id, reward).map_err(|e| {
log::trace!(
target: LOG_TARGET,
"Failed to pay {:?} rewards to {:?}: {:?}",
lane_id,
relayer,
e,
);
Error::<T>::FailedToPayReward
})?;
Self::deposit_event(Event::<T>::RewardPaid { relayer: relayer.clone(), reward });
Ok(())
})
Self::deposit_event(Event::<T>::RewardPaid {
relayer: relayer.clone(),
lane_id,
reward,
});
Ok(())
},
)
}
}
impl<T: Config> Pallet<T> {
/// Register reward for given relayer.
pub fn register_relayer_reward(lane_id: LaneId, relayer: &T::AccountId, reward: T::Reward) {
if reward.is_zero() {
return
}
RelayerRewards::<T>::mutate(relayer, lane_id, |old_reward: &mut Option<T::Reward>| {
let new_reward = old_reward.unwrap_or_else(Zero::zero).saturating_add(reward);
*old_reward = Some(new_reward);
log::trace!(
target: crate::LOG_TARGET,
"Relayer {:?} can now claim reward: {:?}",
relayer,
new_reward,
);
});
}
}
@@ -91,6 +123,8 @@ pub mod pallet {
RewardPaid {
/// Relayer account that has been rewarded.
relayer: T::AccountId,
/// Relayer has received reward for serving this lane.
lane_id: LaneId,
/// Reward amount.
reward: T::Reward,
},
@@ -106,8 +140,15 @@ pub mod pallet {
/// Map of the relayer => accumulated reward.
#[pallet::storage]
pub type RelayerRewards<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, T::Reward, OptionQuery>;
pub type RelayerRewards<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
T::AccountId,
Identity,
LaneId,
T::Reward,
OptionQuery,
>;
}
#[cfg(test)]
@@ -129,7 +170,7 @@ mod tests {
fn root_cant_claim_anything() {
run_test(|| {
assert_noop!(
Pallet::<TestRuntime>::claim_rewards(RuntimeOrigin::root()),
Pallet::<TestRuntime>::claim_rewards(RuntimeOrigin::root(), TEST_LANE_ID),
DispatchError::BadOrigin,
);
});
@@ -139,7 +180,10 @@ mod tests {
fn relayer_cant_claim_if_no_reward_exists() {
run_test(|| {
assert_noop!(
Pallet::<TestRuntime>::claim_rewards(RuntimeOrigin::signed(REGULAR_RELAYER)),
Pallet::<TestRuntime>::claim_rewards(
RuntimeOrigin::signed(REGULAR_RELAYER),
TEST_LANE_ID
),
Error::<TestRuntime>::NoRewardForRelayer,
);
});
@@ -148,9 +192,12 @@ mod tests {
#[test]
fn relayer_cant_claim_if_payment_procedure_fails() {
run_test(|| {
RelayerRewards::<TestRuntime>::insert(FAILING_RELAYER, 100);
RelayerRewards::<TestRuntime>::insert(FAILING_RELAYER, TEST_LANE_ID, 100);
assert_noop!(
Pallet::<TestRuntime>::claim_rewards(RuntimeOrigin::signed(FAILING_RELAYER)),
Pallet::<TestRuntime>::claim_rewards(
RuntimeOrigin::signed(FAILING_RELAYER),
TEST_LANE_ID
),
Error::<TestRuntime>::FailedToPayReward,
);
});
@@ -161,11 +208,12 @@ mod tests {
run_test(|| {
get_ready_for_events();
RelayerRewards::<TestRuntime>::insert(REGULAR_RELAYER, 100);
assert_ok!(Pallet::<TestRuntime>::claim_rewards(RuntimeOrigin::signed(
REGULAR_RELAYER
)));
assert_eq!(RelayerRewards::<TestRuntime>::get(REGULAR_RELAYER), None);
RelayerRewards::<TestRuntime>::insert(REGULAR_RELAYER, TEST_LANE_ID, 100);
assert_ok!(Pallet::<TestRuntime>::claim_rewards(
RuntimeOrigin::signed(REGULAR_RELAYER),
TEST_LANE_ID
));
assert_eq!(RelayerRewards::<TestRuntime>::get(REGULAR_RELAYER, TEST_LANE_ID), None);
//Check if the `RewardPaid` event was emitted.
assert_eq!(
@@ -174,6 +222,7 @@ mod tests {
phase: Phase::Initialization,
event: TestEvent::Relayers(RewardPaid {
relayer: REGULAR_RELAYER,
lane_id: TEST_LANE_ID,
reward: 100
}),
topics: vec![],
@@ -189,7 +238,8 @@ mod tests {
run_test(|| {
assert_eq!(Balances::balance(&1), 0);
assert_eq!(Balances::total_issuance(), 0);
bp_relayers::MintReward::<Balances, AccountId>::pay_reward(&1, 100).unwrap();
bp_relayers::MintReward::<Balances, AccountId>::pay_reward(&1, TEST_LANE_ID, 100)
.unwrap();
assert_eq!(Balances::balance(&1), 100);
assert_eq!(Balances::total_issuance(), 100);
});