referrerpolicy=no-referrer-when-downgrade

pallet_bridge_relayers/
payment_adapter.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Code that allows relayers pallet to be used as a payment mechanism for
18//! the `pallet-bridge-messages` pallet using `RewardsAccountParams`.
19
20use crate::{Config, Pallet};
21
22use alloc::collections::vec_deque::VecDeque;
23use bp_messages::{
24	source_chain::{DeliveryConfirmationPayments, RelayersRewards},
25	MessageNonce,
26};
27pub use bp_relayers::PayRewardFromAccount;
28use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
29use bp_runtime::Chain;
30use core::{marker::PhantomData, ops::RangeInclusive};
31use frame_support::{sp_runtime::SaturatedConversion, traits::Get};
32use pallet_bridge_messages::LaneIdOf;
33use sp_arithmetic::traits::{Saturating, Zero};
34
35/// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism
36/// for the `pallet-bridge-messages` pallet and using `RewardsAccountParams`.
37pub struct DeliveryConfirmationPaymentsAdapter<T, MI, RI, DeliveryReward>(
38	PhantomData<(T, MI, RI, DeliveryReward)>,
39);
40
41impl<T, MI, RI, DeliveryReward> DeliveryConfirmationPayments<T::AccountId, LaneIdOf<T, MI>>
42	for DeliveryConfirmationPaymentsAdapter<T, MI, RI, DeliveryReward>
43where
44	T: Config<RI> + pallet_bridge_messages::Config<MI>,
45	MI: 'static,
46	RI: 'static,
47	DeliveryReward: Get<T::RewardBalance>,
48	<T as Config<RI>>::Reward: From<RewardsAccountParams<LaneIdOf<T, MI>>>,
49{
50	type Error = &'static str;
51
52	fn pay_reward(
53		lane_id: LaneIdOf<T, MI>,
54		messages_relayers: VecDeque<bp_messages::UnrewardedRelayer<T::AccountId>>,
55		confirmation_relayer: &T::AccountId,
56		received_range: &RangeInclusive<bp_messages::MessageNonce>,
57	) -> MessageNonce {
58		let relayers_rewards =
59			bp_messages::calc_relayers_rewards::<T::AccountId>(messages_relayers, received_range);
60		let rewarded_relayers = relayers_rewards.len();
61
62		register_relayers_rewards::<T, RI, MI>(
63			confirmation_relayer,
64			relayers_rewards,
65			RewardsAccountParams::new(
66				lane_id,
67				T::BridgedChain::ID,
68				RewardsAccountOwner::BridgedChain,
69			),
70			DeliveryReward::get(),
71		);
72
73		rewarded_relayers as _
74	}
75}
76
77// Update rewards to given relayers, optionally rewarding confirmation relayer.
78fn register_relayers_rewards<
79	T: Config<RI> + pallet_bridge_messages::Config<MI>,
80	RI: 'static,
81	MI: 'static,
82>(
83	confirmation_relayer: &T::AccountId,
84	relayers_rewards: RelayersRewards<T::AccountId>,
85	lane_id: RewardsAccountParams<LaneIdOf<T, MI>>,
86	delivery_fee: T::RewardBalance,
87) where
88	<T as Config<RI>>::Reward: From<RewardsAccountParams<LaneIdOf<T, MI>>>,
89{
90	// reward every relayer except `confirmation_relayer`
91	let mut confirmation_relayer_reward = T::RewardBalance::zero();
92	for (relayer, messages) in relayers_rewards {
93		// sane runtime configurations guarantee that the number of messages will be below
94		// `u32::MAX`
95		let relayer_reward =
96			T::RewardBalance::saturated_from(messages).saturating_mul(delivery_fee);
97
98		if relayer != *confirmation_relayer {
99			Pallet::<T, RI>::register_relayer_reward(lane_id.into(), &relayer, relayer_reward);
100		} else {
101			confirmation_relayer_reward =
102				confirmation_relayer_reward.saturating_add(relayer_reward);
103		}
104	}
105
106	// finally - pay reward to confirmation relayer
107	Pallet::<T, RI>::register_relayer_reward(
108		lane_id.into(),
109		confirmation_relayer,
110		confirmation_relayer_reward,
111	);
112}
113
114#[cfg(test)]
115mod tests {
116	use super::*;
117	use crate::{mock::*, RelayerRewards};
118	use bp_messages::LaneIdType;
119	use bp_relayers::PaymentProcedure;
120	use frame_support::{
121		assert_ok,
122		traits::fungible::{Inspect, Mutate},
123	};
124
125	const RELAYER_1: ThisChainAccountId = 1;
126	const RELAYER_2: ThisChainAccountId = 2;
127	const RELAYER_3: ThisChainAccountId = 3;
128
129	fn relayers_rewards() -> RelayersRewards<ThisChainAccountId> {
130		vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect()
131	}
132
133	#[test]
134	fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
135		run_test(|| {
136			register_relayers_rewards::<TestRuntime, (), ()>(
137				&RELAYER_2,
138				relayers_rewards(),
139				test_reward_account_param(),
140				50,
141			);
142
143			assert_eq!(
144				RelayerRewards::<TestRuntime>::get(RELAYER_1, test_reward_account_param()),
145				Some(100)
146			);
147			assert_eq!(
148				RelayerRewards::<TestRuntime>::get(RELAYER_2, test_reward_account_param()),
149				Some(150)
150			);
151		});
152	}
153
154	#[test]
155	fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() {
156		run_test(|| {
157			register_relayers_rewards::<TestRuntime, (), ()>(
158				&RELAYER_3,
159				relayers_rewards(),
160				test_reward_account_param(),
161				50,
162			);
163
164			assert_eq!(
165				RelayerRewards::<TestRuntime>::get(RELAYER_1, test_reward_account_param()),
166				Some(100)
167			);
168			assert_eq!(
169				RelayerRewards::<TestRuntime>::get(RELAYER_2, test_reward_account_param()),
170				Some(150)
171			);
172			assert_eq!(
173				RelayerRewards::<TestRuntime>::get(RELAYER_3, test_reward_account_param()),
174				None
175			);
176		});
177	}
178
179	#[test]
180	fn pay_reward_from_account_actually_pays_reward() {
181		type Balances = pallet_balances::Pallet<TestRuntime>;
182		type PayLaneRewardFromAccount =
183			PayRewardFromAccount<Balances, ThisChainAccountId, TestLaneIdType, RewardBalance>;
184
185		run_test(|| {
186			let in_lane_0 = RewardsAccountParams::new(
187				TestLaneIdType::try_new(1, 2).unwrap(),
188				*b"test",
189				RewardsAccountOwner::ThisChain,
190			);
191			let out_lane_1 = RewardsAccountParams::new(
192				TestLaneIdType::try_new(1, 3).unwrap(),
193				*b"test",
194				RewardsAccountOwner::BridgedChain,
195			);
196
197			let in_lane0_rewards_account = PayLaneRewardFromAccount::rewards_account(in_lane_0);
198			let out_lane1_rewards_account = PayLaneRewardFromAccount::rewards_account(out_lane_1);
199
200			assert_ok!(Balances::mint_into(&in_lane0_rewards_account, 200));
201			assert_ok!(Balances::mint_into(&out_lane1_rewards_account, 100));
202			assert_eq!(Balances::balance(&in_lane0_rewards_account), 200);
203			assert_eq!(Balances::balance(&out_lane1_rewards_account), 100);
204			assert_eq!(Balances::balance(&1), 0);
205			assert_eq!(Balances::balance(&2), 0);
206
207			assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100, 1_u64));
208			assert_eq!(Balances::balance(&in_lane0_rewards_account), 100);
209			assert_eq!(Balances::balance(&out_lane1_rewards_account), 100);
210			assert_eq!(Balances::balance(&1), 100);
211			assert_eq!(Balances::balance(&2), 0);
212
213			assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, out_lane_1, 100, 1_u64));
214			assert_eq!(Balances::balance(&in_lane0_rewards_account), 100);
215			assert_eq!(Balances::balance(&out_lane1_rewards_account), 0);
216			assert_eq!(Balances::balance(&1), 200);
217			assert_eq!(Balances::balance(&2), 0);
218
219			assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100, 2_u64));
220			assert_eq!(Balances::balance(&in_lane0_rewards_account), 0);
221			assert_eq!(Balances::balance(&out_lane1_rewards_account), 0);
222			assert_eq!(Balances::balance(&1), 200);
223			assert_eq!(Balances::balance(&2), 100);
224		});
225	}
226}