referrerpolicy=no-referrer-when-downgrade

pallet_bridge_relayers/
lib.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//! Runtime module that is used to store relayer rewards and (in the future) to
18//! coordinate relations between relayers.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24pub use bp_relayers::RewardLedger;
25use bp_relayers::{PaymentProcedure, Registration, RelayerRewardsKeyProvider, StakeAndSlash};
26use bp_runtime::StorageDoubleMapKeyProvider;
27use core::marker::PhantomData;
28use frame_support::{fail, traits::tokens::Balance};
29use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
30use sp_runtime::{
31	traits::{CheckedSub, IdentifyAccount},
32	Saturating,
33};
34
35pub use pallet::*;
36pub use payment_adapter::{DeliveryConfirmationPaymentsAdapter, PayRewardFromAccount};
37pub use stake_adapter::StakeAndSlashNamed;
38pub use weights::WeightInfo;
39pub use weights_ext::WeightInfoExt;
40
41mod mock;
42mod payment_adapter;
43mod stake_adapter;
44mod weights_ext;
45
46pub mod benchmarking;
47pub mod extension;
48pub mod migration;
49pub mod weights;
50
51/// The target that will be used when publishing logs related to this pallet.
52pub const LOG_TARGET: &str = "runtime::bridge-relayers";
53
54#[frame_support::pallet]
55pub mod pallet {
56	use super::*;
57	use frame_support::pallet_prelude::*;
58	use frame_system::pallet_prelude::*;
59
60	/// `RelayerRewardsKeyProvider` for given configuration.
61	type RelayerRewardsKeyProviderOf<T, I> = RelayerRewardsKeyProvider<
62		<T as frame_system::Config>::AccountId,
63		<T as Config<I>>::Reward,
64		<T as Config<I>>::RewardBalance,
65	>;
66
67	/// Shortcut to alternative beneficiary type for `Config::PaymentProcedure`.
68	pub type BeneficiaryOf<T, I> = <<T as Config<I>>::PaymentProcedure as PaymentProcedure<
69		<T as frame_system::Config>::AccountId,
70		<T as Config<I>>::Reward,
71		<T as Config<I>>::RewardBalance,
72	>>::Beneficiary;
73
74	#[pallet::config]
75	pub trait Config<I: 'static = ()>: frame_system::Config {
76		/// The overarching event type.
77		#[allow(deprecated)]
78		type RuntimeEvent: From<Event<Self, I>>
79			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
80
81		/// Type of relayer reward balance.
82		type RewardBalance: AtLeast32BitUnsigned + Copy + Member + Parameter + MaxEncodedLen;
83		/// Reward discriminator type. The pallet can collect different types of rewards for a
84		/// single account, so `Reward` is used as the second key in the `RelayerRewards` double
85		/// map.
86		///
87		/// For example, rewards for different bridges can be stored, where `Reward` is
88		/// implemented as an enum representing each bridge.
89		type Reward: Parameter + MaxEncodedLen + Send + Sync + Copy + Clone;
90
91		/// Pay rewards scheme.
92		type PaymentProcedure: PaymentProcedure<Self::AccountId, Self::Reward, Self::RewardBalance>;
93
94		/// Stake and slash scheme.
95		type StakeAndSlash: StakeAndSlash<Self::AccountId, BlockNumberFor<Self>, Self::Balance>;
96		/// Type for representing balance of an account used for `T::StakeAndSlash`.
97		type Balance: Balance;
98
99		/// Pallet call weights.
100		type WeightInfo: WeightInfoExt;
101	}
102
103	#[pallet::pallet]
104	#[pallet::storage_version(migration::STORAGE_VERSION)]
105	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
106
107	#[pallet::call]
108	impl<T: Config<I>, I: 'static> Pallet<T, I>
109	where
110		BeneficiaryOf<T, I>: From<<T as frame_system::Config>::AccountId>,
111	{
112		/// Claim accumulated rewards.
113		#[pallet::call_index(0)]
114		#[pallet::weight(T::WeightInfo::claim_rewards())]
115		pub fn claim_rewards(origin: OriginFor<T>, reward_kind: T::Reward) -> DispatchResult {
116			let relayer = ensure_signed(origin)?;
117
118			Self::do_claim_rewards(relayer.clone(), reward_kind, relayer.into())
119		}
120
121		/// Register relayer or update its registration.
122		///
123		/// Registration allows relayer to get priority boost for its message delivery transactions.
124		#[pallet::call_index(1)]
125		#[pallet::weight(T::WeightInfo::register())]
126		pub fn register(origin: OriginFor<T>, valid_till: BlockNumberFor<T>) -> DispatchResult {
127			let relayer = ensure_signed(origin)?;
128
129			// valid till must be larger than the current block number and the lease must be larger
130			// than the `RequiredRegistrationLease`
131			let lease = valid_till.saturating_sub(frame_system::Pallet::<T>::block_number());
132			ensure!(
133				lease > Self::required_registration_lease(),
134				Error::<T, I>::InvalidRegistrationLease
135			);
136
137			RegisteredRelayers::<T, I>::try_mutate(
138				&relayer,
139				|maybe_registration| -> DispatchResult {
140					let mut registration = maybe_registration
141						.unwrap_or_else(|| Registration { valid_till, stake: Zero::zero() });
142
143					// new `valid_till` must be larger (or equal) than the old one
144					ensure!(
145						valid_till >= registration.valid_till,
146						Error::<T, I>::CannotReduceRegistrationLease,
147					);
148					registration.valid_till = valid_till;
149
150					// regarding stake, there are three options:
151					// - if relayer stake is larger than required stake, we may do unreserve
152					// - if relayer stake equals to required stake, we do nothing
153					// - if relayer stake is smaller than required stake, we do additional reserve
154					let required_stake = Self::required_stake();
155					if let Some(to_unreserve) = registration.stake.checked_sub(&required_stake) {
156						Self::do_unreserve(&relayer, to_unreserve)?;
157					} else if let Some(to_reserve) = required_stake.checked_sub(&registration.stake)
158					{
159						T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| {
160							tracing::trace!(
161								target: LOG_TARGET,
162								error=?e,
163								?relayer,
164								?to_reserve,
165								"Failed to reserve on relayer account"
166							);
167
168							Error::<T, I>::FailedToReserve
169						})?;
170					}
171					registration.stake = required_stake;
172
173					tracing::trace!(target: LOG_TARGET, ?relayer, "Successfully registered relayer");
174					Self::deposit_event(Event::<T, I>::RegistrationUpdated {
175						relayer: relayer.clone(),
176						registration,
177					});
178
179					*maybe_registration = Some(registration);
180
181					Ok(())
182				},
183			)
184		}
185
186		/// `Deregister` relayer.
187		///
188		/// After this call, message delivery transactions of the relayer won't get any priority
189		/// boost.
190		#[pallet::call_index(2)]
191		#[pallet::weight(T::WeightInfo::deregister())]
192		pub fn deregister(origin: OriginFor<T>) -> DispatchResult {
193			let relayer = ensure_signed(origin)?;
194
195			RegisteredRelayers::<T, I>::try_mutate(
196				&relayer,
197				|maybe_registration| -> DispatchResult {
198					let registration = match maybe_registration.take() {
199						Some(registration) => registration,
200						None => fail!(Error::<T, I>::NotRegistered),
201					};
202
203					// we can't deregister until `valid_till + 1`
204					ensure!(
205						registration.valid_till < frame_system::Pallet::<T>::block_number(),
206						Error::<T, I>::RegistrationIsStillActive,
207					);
208
209					// if stake is non-zero, we should do unreserve
210					if !registration.stake.is_zero() {
211						Self::do_unreserve(&relayer, registration.stake)?;
212					}
213
214					tracing::trace!(target: LOG_TARGET, ?relayer, "Successfully deregistered relayer");
215					Self::deposit_event(Event::<T, I>::Deregistered { relayer: relayer.clone() });
216
217					*maybe_registration = None;
218
219					Ok(())
220				},
221			)
222		}
223
224		/// Claim accumulated rewards and send them to the alternative beneficiary.
225		#[pallet::call_index(3)]
226		#[pallet::weight(T::WeightInfo::claim_rewards_to())]
227		pub fn claim_rewards_to(
228			origin: OriginFor<T>,
229			reward_kind: T::Reward,
230			beneficiary: BeneficiaryOf<T, I>,
231		) -> DispatchResult {
232			let relayer = ensure_signed(origin)?;
233
234			Self::do_claim_rewards(relayer, reward_kind, beneficiary)
235		}
236	}
237
238	impl<T: Config<I>, I: 'static> Pallet<T, I> {
239		/// Relayers that have reserved some of their balance to get free priority boost
240		/// for their message delivery transactions.
241		pub fn registered_relayer(
242			relayer: &T::AccountId,
243		) -> Option<Registration<BlockNumberFor<T>, T::Balance>> {
244			RegisteredRelayers::<T, I>::get(relayer)
245		}
246
247		/// Map of the relayer => accumulated reward.
248		pub fn relayer_reward<EncodeLikeAccountId, EncodeLikeReward>(
249			key1: EncodeLikeAccountId,
250			key2: EncodeLikeReward,
251		) -> Option<<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Value>
252		where
253			EncodeLikeAccountId: codec::EncodeLike<
254				<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Key1,
255			>,
256			EncodeLikeReward: codec::EncodeLike<
257				<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Key2,
258			>,
259		{
260			RelayerRewards::<T, I>::get(key1, key2)
261		}
262
263		fn do_claim_rewards(
264			relayer: T::AccountId,
265			reward_kind: T::Reward,
266			beneficiary: BeneficiaryOf<T, I>,
267		) -> DispatchResult {
268			RelayerRewards::<T, I>::try_mutate_exists(
269				&relayer,
270				reward_kind,
271				|maybe_reward| -> DispatchResult {
272					let reward_balance =
273						maybe_reward.take().ok_or(Error::<T, I>::NoRewardForRelayer)?;
274					T::PaymentProcedure::pay_reward(
275						&relayer,
276						reward_kind,
277						reward_balance,
278						beneficiary.clone(),
279					)
280					.map_err(|e| {
281						tracing::error!(
282							target: LOG_TARGET,
283							error=?e,
284							?relayer,
285							?reward_kind,
286							?reward_balance,
287							?beneficiary,
288							"Failed to pay rewards"
289						);
290						Error::<T, I>::FailedToPayReward
291					})?;
292
293					Self::deposit_event(Event::<T, I>::RewardPaid {
294						relayer: relayer.clone(),
295						reward_kind,
296						reward_balance,
297						beneficiary,
298					});
299					Ok(())
300				},
301			)
302		}
303
304		/// Returns true if given relayer registration is active at current block.
305		///
306		/// This call respects both `RequiredStake` and `RequiredRegistrationLease`, meaning that
307		/// it'll return false if registered stake is lower than required or if remaining lease
308		/// is less than `RequiredRegistrationLease`.
309		pub fn is_registration_active(relayer: &T::AccountId) -> bool {
310			let registration = match Self::registered_relayer(relayer) {
311				Some(registration) => registration,
312				None => return false,
313			};
314
315			// registration is inactive if relayer stake is less than required
316			if registration.stake < Self::required_stake() {
317				return false;
318			}
319
320			// registration is inactive if it ends soon
321			let remaining_lease = registration
322				.valid_till
323				.saturating_sub(frame_system::Pallet::<T>::block_number());
324			if remaining_lease <= Self::required_registration_lease() {
325				return false;
326			}
327
328			true
329		}
330
331		/// Slash and `deregister` relayer. This function slashes all staked balance.
332		///
333		/// It may fail inside, but error is swallowed and we only log it.
334		pub fn slash_and_deregister(
335			relayer: &T::AccountId,
336			slash_destination: impl IdentifyAccount<AccountId = T::AccountId>,
337		) {
338			let registration = match RegisteredRelayers::<T, I>::take(relayer) {
339				Some(registration) => registration,
340				None => {
341					tracing::trace!(
342						target: crate::LOG_TARGET,
343						?relayer,
344						"Cannot slash unregistered relayer"
345					);
346
347					return;
348				},
349			};
350			let slash_destination = slash_destination.into_account();
351
352			match T::StakeAndSlash::repatriate_reserved(
353				relayer,
354				&slash_destination,
355				registration.stake,
356			) {
357				Ok(failed_to_slash) if failed_to_slash.is_zero() => {
358					tracing::trace!(
359						target: crate::LOG_TARGET,
360						?relayer,
361						amount=?registration.stake,
362						?slash_destination,
363						"Relayer account has been slashed. Funds were deposited."
364					);
365				},
366				Ok(failed_to_slash) => {
367					tracing::trace!(
368						target: crate::LOG_TARGET,
369						?relayer,
370						amount=?registration.stake,
371						?slash_destination,
372						?failed_to_slash,
373						"Relayer account has been partially slashed. Funds were deposited.",
374					);
375				},
376				Err(e) => {
377					// TODO: document this. Where?
378
379					// it may fail if there's no beneficiary account. For us, it means that this
380					// account must exist before we'll deploy the bridge
381					tracing::debug!(
382						target: crate::LOG_TARGET,
383						error=?e,
384						?relayer,
385						beneficiary=?slash_destination,
386						amount=?registration.stake,
387						failed_to_slash=?registration.stake,
388						"Failed to slash relayer account. Maybe beneficiary account doesn't exist?"
389					);
390				},
391			}
392
393			Self::deposit_event(Event::<T, I>::SlashedAndDeregistered {
394				relayer: relayer.clone(),
395				registration,
396			});
397		}
398
399		/// Register reward for given relayer.
400		pub(crate) fn register_relayer_reward(
401			reward_kind: T::Reward,
402			relayer: &T::AccountId,
403			reward_balance: T::RewardBalance,
404		) {
405			if reward_balance.is_zero() {
406				return;
407			}
408
409			RelayerRewards::<T, I>::mutate(
410				relayer,
411				reward_kind,
412				|old_reward: &mut Option<T::RewardBalance>| {
413					let new_reward =
414						old_reward.unwrap_or_else(Zero::zero).saturating_add(reward_balance);
415					*old_reward = Some(new_reward);
416
417					tracing::trace!(
418						target: crate::LOG_TARGET,
419						?relayer,
420						?reward_kind,
421						?new_reward,
422						"Relayer can now claim reward for serving payer"
423					);
424
425					Self::deposit_event(Event::<T, I>::RewardRegistered {
426						relayer: relayer.clone(),
427						reward_kind,
428						reward_balance,
429					});
430				},
431			);
432		}
433
434		/// Return required registration lease.
435		pub(crate) fn required_registration_lease() -> BlockNumberFor<T> {
436			<T::StakeAndSlash as StakeAndSlash<
437				T::AccountId,
438				BlockNumberFor<T>,
439				T::Balance,
440			>>::RequiredRegistrationLease::get()
441		}
442
443		/// Return required stake.
444		pub(crate) fn required_stake() -> T::Balance {
445			<T::StakeAndSlash as StakeAndSlash<
446				T::AccountId,
447				BlockNumberFor<T>,
448				T::Balance,
449			>>::RequiredStake::get()
450		}
451
452		/// `Unreserve` given amount on relayer account.
453		fn do_unreserve(relayer: &T::AccountId, amount: T::Balance) -> DispatchResult {
454			let failed_to_unreserve = T::StakeAndSlash::unreserve(relayer, amount);
455			if !failed_to_unreserve.is_zero() {
456				tracing::trace!(
457					target: LOG_TARGET,
458					?relayer,
459					?failed_to_unreserve,
460					?amount,
461					"Failed to unreserve on relayer account",
462				);
463
464				fail!(Error::<T, I>::FailedToUnreserve)
465			}
466
467			Ok(())
468		}
469	}
470
471	#[pallet::event]
472	#[pallet::generate_deposit(pub(super) fn deposit_event)]
473	pub enum Event<T: Config<I>, I: 'static = ()> {
474		/// Relayer reward has been registered and may be claimed later.
475		RewardRegistered {
476			/// Relayer account that can claim reward.
477			relayer: T::AccountId,
478			/// Relayer can claim this kind of reward.
479			reward_kind: T::Reward,
480			/// Reward amount.
481			reward_balance: T::RewardBalance,
482		},
483		/// Reward has been paid to the relayer.
484		RewardPaid {
485			/// Relayer account that has been rewarded.
486			relayer: T::AccountId,
487			/// Relayer has received reward of this kind.
488			reward_kind: T::Reward,
489			/// Reward amount.
490			reward_balance: T::RewardBalance,
491			/// Beneficiary.
492			beneficiary: BeneficiaryOf<T, I>,
493		},
494		/// Relayer registration has been added or updated.
495		RegistrationUpdated {
496			/// Relayer account that has been registered.
497			relayer: T::AccountId,
498			/// Relayer registration.
499			registration: Registration<BlockNumberFor<T>, T::Balance>,
500		},
501		/// Relayer has been `deregistered`.
502		Deregistered {
503			/// Relayer account that has been `deregistered`.
504			relayer: T::AccountId,
505		},
506		/// Relayer has been slashed and `deregistered`.
507		SlashedAndDeregistered {
508			/// Relayer account that has been `deregistered`.
509			relayer: T::AccountId,
510			/// Registration that was removed.
511			registration: Registration<BlockNumberFor<T>, T::Balance>,
512		},
513	}
514
515	#[pallet::error]
516	pub enum Error<T, I = ()> {
517		/// No reward can be claimed by given relayer.
518		NoRewardForRelayer,
519		/// Reward payment procedure has failed.
520		FailedToPayReward,
521		/// The relayer has tried to register for past block or registration lease
522		/// is too short.
523		InvalidRegistrationLease,
524		/// New registration lease is less than the previous one.
525		CannotReduceRegistrationLease,
526		/// Failed to reserve enough funds on relayer account.
527		FailedToReserve,
528		/// Failed to `unreserve` enough funds on relayer account.
529		FailedToUnreserve,
530		/// Cannot `deregister` if not registered.
531		NotRegistered,
532		/// Failed to `deregister` relayer, because lease is still active.
533		RegistrationIsStillActive,
534	}
535
536	/// Map of the relayer => accumulated reward.
537	#[pallet::storage]
538	pub type RelayerRewards<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
539		_,
540		<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Hasher1,
541		<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Key1,
542		<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Hasher2,
543		<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Key2,
544		<RelayerRewardsKeyProviderOf<T, I> as StorageDoubleMapKeyProvider>::Value,
545		OptionQuery,
546	>;
547
548	/// Relayers that have reserved some of their balance to get free priority boost
549	/// for their message delivery transactions.
550	///
551	/// Other relayers may submit transactions as well, but they will have default
552	/// priority and will be rejected (without significant tip) in case if registered
553	/// relayer is present.
554	#[pallet::storage]
555	pub type RegisteredRelayers<T: Config<I>, I: 'static = ()> = StorageMap<
556		_,
557		Blake2_128Concat,
558		T::AccountId,
559		Registration<BlockNumberFor<T>, T::Balance>,
560		OptionQuery,
561	>;
562}
563
564/// Implementation of `RewardLedger` for the pallet.
565impl<T: Config<I>, I: 'static, Reward, RewardBalance>
566	RewardLedger<T::AccountId, Reward, RewardBalance> for Pallet<T, I>
567where
568	Reward: Into<T::Reward>,
569	RewardBalance: Into<T::RewardBalance>,
570{
571	fn register_reward(relayer: &T::AccountId, reward: Reward, reward_balance: RewardBalance) {
572		Self::register_relayer_reward(reward.into(), relayer, reward_balance.into());
573	}
574}
575
576#[cfg(test)]
577mod tests {
578	use super::*;
579	use mock::{RuntimeEvent as TestEvent, *};
580
581	use bp_messages::{HashedLaneId, LaneIdType};
582	use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
583	use frame_support::{assert_noop, assert_ok, traits::fungible::Mutate};
584	use frame_system::{EventRecord, Pallet as System, Phase};
585	use sp_runtime::DispatchError;
586
587	fn get_ready_for_events() {
588		System::<TestRuntime>::set_block_number(1);
589		System::<TestRuntime>::reset_events();
590	}
591
592	#[test]
593	fn register_relayer_reward_emit_event() {
594		run_test(|| {
595			get_ready_for_events();
596
597			Pallet::<TestRuntime>::register_relayer_reward(
598				test_reward_account_param(),
599				&REGULAR_RELAYER,
600				100,
601			);
602
603			// Check if the `RewardRegistered` event was emitted.
604			assert_eq!(
605				System::<TestRuntime>::events().last(),
606				Some(&EventRecord {
607					phase: Phase::Initialization,
608					event: TestEvent::BridgeRelayers(Event::RewardRegistered {
609						relayer: REGULAR_RELAYER,
610						reward_kind: test_reward_account_param(),
611						reward_balance: 100
612					}),
613					topics: vec![],
614				}),
615			);
616		});
617	}
618
619	#[test]
620	fn slash_and_deregister_works() {
621		run_test(|| {
622			get_ready_for_events();
623
624			// register
625			assert_ok!(Pallet::<TestRuntime>::register(
626				RuntimeOrigin::signed(REGISTER_RELAYER),
627				150,
628			));
629			// check if registered
630			let registration =
631				Pallet::<TestRuntime>::registered_relayer(&REGISTER_RELAYER).unwrap();
632			assert_eq!(registration, Registration { valid_till: 150, stake: Stake::get() });
633
634			// slash and deregister
635			let slash_destination = RewardsAccountParams::new(
636				HashedLaneId::try_new(1, 2).unwrap(),
637				*b"test",
638				RewardsAccountOwner::ThisChain,
639			);
640			let slash_destination = bp_relayers::ExplicitOrAccountParams::Params(slash_destination);
641			Pallet::<TestRuntime>::slash_and_deregister(&REGISTER_RELAYER, slash_destination);
642			// check if event emitted
643			assert_eq!(
644				System::<TestRuntime>::events().last(),
645				Some(&EventRecord {
646					phase: Phase::Initialization,
647					event: TestEvent::BridgeRelayers(Event::SlashedAndDeregistered {
648						relayer: REGISTER_RELAYER,
649						registration,
650					}),
651					topics: vec![],
652				})
653			)
654		});
655	}
656
657	#[test]
658	fn root_cant_claim_anything() {
659		run_test(|| {
660			assert_noop!(
661				Pallet::<TestRuntime>::claim_rewards(
662					RuntimeOrigin::root(),
663					test_reward_account_param()
664				),
665				DispatchError::BadOrigin,
666			);
667		});
668	}
669
670	#[test]
671	fn relayer_cant_claim_if_no_reward_exists() {
672		run_test(|| {
673			assert_noop!(
674				Pallet::<TestRuntime>::claim_rewards(
675					RuntimeOrigin::signed(REGULAR_RELAYER),
676					test_reward_account_param()
677				),
678				Error::<TestRuntime>::NoRewardForRelayer,
679			);
680		});
681	}
682
683	#[test]
684	fn relayer_cant_claim_if_payment_procedure_fails() {
685		run_test(|| {
686			RelayerRewards::<TestRuntime>::insert(
687				FAILING_RELAYER,
688				test_reward_account_param(),
689				100,
690			);
691			assert_noop!(
692				Pallet::<TestRuntime>::claim_rewards(
693					RuntimeOrigin::signed(FAILING_RELAYER),
694					test_reward_account_param()
695				),
696				Error::<TestRuntime>::FailedToPayReward,
697			);
698		});
699	}
700
701	#[test]
702	fn relayer_can_claim_reward() {
703		run_test(|| {
704			get_ready_for_events();
705
706			RelayerRewards::<TestRuntime>::insert(
707				REGULAR_RELAYER,
708				test_reward_account_param(),
709				100,
710			);
711			assert_ok!(Pallet::<TestRuntime>::claim_rewards(
712				RuntimeOrigin::signed(REGULAR_RELAYER),
713				test_reward_account_param()
714			));
715			assert_eq!(
716				RelayerRewards::<TestRuntime>::get(REGULAR_RELAYER, test_reward_account_param()),
717				None
718			);
719
720			// Check if the `RewardPaid` event was emitted.
721			assert_eq!(
722				System::<TestRuntime>::events().last(),
723				Some(&EventRecord {
724					phase: Phase::Initialization,
725					event: TestEvent::BridgeRelayers(Event::RewardPaid {
726						relayer: REGULAR_RELAYER,
727						reward_kind: test_reward_account_param(),
728						reward_balance: 100,
729						beneficiary: REGULAR_RELAYER,
730					}),
731					topics: vec![],
732				}),
733			);
734		});
735	}
736
737	#[test]
738	fn relayer_can_claim_reward_to() {
739		run_test(|| {
740			get_ready_for_events();
741
742			RelayerRewards::<TestRuntime>::insert(
743				REGULAR_RELAYER,
744				test_reward_account_param(),
745				100,
746			);
747			assert_ok!(Pallet::<TestRuntime>::claim_rewards_to(
748				RuntimeOrigin::signed(REGULAR_RELAYER),
749				test_reward_account_param(),
750				REGULAR_RELAYER2,
751			));
752			assert_eq!(
753				RelayerRewards::<TestRuntime>::get(REGULAR_RELAYER, test_reward_account_param()),
754				None
755			);
756
757			// Check if the `RewardPaid` event was emitted.
758			assert_eq!(
759				System::<TestRuntime>::events().last(),
760				Some(&EventRecord {
761					phase: Phase::Initialization,
762					event: TestEvent::BridgeRelayers(Event::RewardPaid {
763						relayer: REGULAR_RELAYER,
764						reward_kind: test_reward_account_param(),
765						reward_balance: 100,
766						beneficiary: REGULAR_RELAYER2,
767					}),
768					topics: vec![],
769				}),
770			);
771		});
772	}
773
774	#[test]
775	fn register_fails_if_valid_till_is_a_past_block() {
776		run_test(|| {
777			System::<TestRuntime>::set_block_number(100);
778
779			assert_noop!(
780				Pallet::<TestRuntime>::register(RuntimeOrigin::signed(REGISTER_RELAYER), 50),
781				Error::<TestRuntime>::InvalidRegistrationLease,
782			);
783		});
784	}
785
786	#[test]
787	fn register_fails_if_valid_till_lease_is_less_than_required() {
788		run_test(|| {
789			System::<TestRuntime>::set_block_number(100);
790
791			assert_noop!(
792				Pallet::<TestRuntime>::register(
793					RuntimeOrigin::signed(REGISTER_RELAYER),
794					99 + Lease::get()
795				),
796				Error::<TestRuntime>::InvalidRegistrationLease,
797			);
798		});
799	}
800
801	#[test]
802	fn register_works() {
803		run_test(|| {
804			get_ready_for_events();
805
806			assert_ok!(Pallet::<TestRuntime>::register(
807				RuntimeOrigin::signed(REGISTER_RELAYER),
808				150
809			));
810			assert_eq!(Balances::reserved_balance(REGISTER_RELAYER), Stake::get());
811			assert_eq!(
812				Pallet::<TestRuntime>::registered_relayer(&REGISTER_RELAYER),
813				Some(Registration { valid_till: 150, stake: Stake::get() }),
814			);
815
816			assert_eq!(
817				System::<TestRuntime>::events().last(),
818				Some(&EventRecord {
819					phase: Phase::Initialization,
820					event: TestEvent::BridgeRelayers(Event::RegistrationUpdated {
821						relayer: REGISTER_RELAYER,
822						registration: Registration { valid_till: 150, stake: Stake::get() },
823					}),
824					topics: vec![],
825				}),
826			);
827		});
828	}
829
830	#[test]
831	fn register_fails_if_new_valid_till_is_lesser_than_previous() {
832		run_test(|| {
833			assert_ok!(Pallet::<TestRuntime>::register(
834				RuntimeOrigin::signed(REGISTER_RELAYER),
835				150
836			));
837
838			assert_noop!(
839				Pallet::<TestRuntime>::register(RuntimeOrigin::signed(REGISTER_RELAYER), 125),
840				Error::<TestRuntime>::CannotReduceRegistrationLease,
841			);
842		});
843	}
844
845	#[test]
846	fn register_fails_if_it_cant_unreserve_some_balance_if_required_stake_decreases() {
847		run_test(|| {
848			RegisteredRelayers::<TestRuntime>::insert(
849				REGISTER_RELAYER,
850				Registration { valid_till: 150, stake: Stake::get() + 1 },
851			);
852
853			assert_noop!(
854				Pallet::<TestRuntime>::register(RuntimeOrigin::signed(REGISTER_RELAYER), 150),
855				Error::<TestRuntime>::FailedToUnreserve,
856			);
857		});
858	}
859
860	#[test]
861	fn register_unreserves_some_balance_if_required_stake_decreases() {
862		run_test(|| {
863			get_ready_for_events();
864
865			RegisteredRelayers::<TestRuntime>::insert(
866				REGISTER_RELAYER,
867				Registration { valid_till: 150, stake: Stake::get() + 1 },
868			);
869			TestStakeAndSlash::reserve(&REGISTER_RELAYER, Stake::get() + 1).unwrap();
870			assert_eq!(Balances::reserved_balance(REGISTER_RELAYER), Stake::get() + 1);
871			let free_balance = Balances::free_balance(REGISTER_RELAYER);
872
873			assert_ok!(Pallet::<TestRuntime>::register(
874				RuntimeOrigin::signed(REGISTER_RELAYER),
875				150
876			));
877			assert_eq!(Balances::reserved_balance(REGISTER_RELAYER), Stake::get());
878			assert_eq!(Balances::free_balance(REGISTER_RELAYER), free_balance + 1);
879			assert_eq!(
880				Pallet::<TestRuntime>::registered_relayer(&REGISTER_RELAYER),
881				Some(Registration { valid_till: 150, stake: Stake::get() }),
882			);
883
884			assert_eq!(
885				System::<TestRuntime>::events().last(),
886				Some(&EventRecord {
887					phase: Phase::Initialization,
888					event: TestEvent::BridgeRelayers(Event::RegistrationUpdated {
889						relayer: REGISTER_RELAYER,
890						registration: Registration { valid_till: 150, stake: Stake::get() }
891					}),
892					topics: vec![],
893				}),
894			);
895		});
896	}
897
898	#[test]
899	fn register_fails_if_it_cant_reserve_some_balance() {
900		run_test(|| {
901			Balances::set_balance(&REGISTER_RELAYER, 0);
902			assert_noop!(
903				Pallet::<TestRuntime>::register(RuntimeOrigin::signed(REGISTER_RELAYER), 150),
904				Error::<TestRuntime>::FailedToReserve,
905			);
906		});
907	}
908
909	#[test]
910	fn register_fails_if_it_cant_reserve_some_balance_if_required_stake_increases() {
911		run_test(|| {
912			RegisteredRelayers::<TestRuntime>::insert(
913				REGISTER_RELAYER,
914				Registration { valid_till: 150, stake: Stake::get() - 1 },
915			);
916			Balances::set_balance(&REGISTER_RELAYER, 0);
917
918			assert_noop!(
919				Pallet::<TestRuntime>::register(RuntimeOrigin::signed(REGISTER_RELAYER), 150),
920				Error::<TestRuntime>::FailedToReserve,
921			);
922		});
923	}
924
925	#[test]
926	fn register_reserves_some_balance_if_required_stake_increases() {
927		run_test(|| {
928			get_ready_for_events();
929
930			RegisteredRelayers::<TestRuntime>::insert(
931				REGISTER_RELAYER,
932				Registration { valid_till: 150, stake: Stake::get() - 1 },
933			);
934			TestStakeAndSlash::reserve(&REGISTER_RELAYER, Stake::get() - 1).unwrap();
935
936			let free_balance = Balances::free_balance(REGISTER_RELAYER);
937			assert_ok!(Pallet::<TestRuntime>::register(
938				RuntimeOrigin::signed(REGISTER_RELAYER),
939				150
940			));
941			assert_eq!(Balances::reserved_balance(REGISTER_RELAYER), Stake::get());
942			assert_eq!(Balances::free_balance(REGISTER_RELAYER), free_balance - 1);
943			assert_eq!(
944				Pallet::<TestRuntime>::registered_relayer(&REGISTER_RELAYER),
945				Some(Registration { valid_till: 150, stake: Stake::get() }),
946			);
947
948			assert_eq!(
949				System::<TestRuntime>::events().last(),
950				Some(&EventRecord {
951					phase: Phase::Initialization,
952					event: TestEvent::BridgeRelayers(Event::RegistrationUpdated {
953						relayer: REGISTER_RELAYER,
954						registration: Registration { valid_till: 150, stake: Stake::get() }
955					}),
956					topics: vec![],
957				}),
958			);
959		});
960	}
961
962	#[test]
963	fn deregister_fails_if_not_registered() {
964		run_test(|| {
965			assert_noop!(
966				Pallet::<TestRuntime>::deregister(RuntimeOrigin::signed(REGISTER_RELAYER)),
967				Error::<TestRuntime>::NotRegistered,
968			);
969		});
970	}
971
972	#[test]
973	fn deregister_fails_if_registration_is_still_active() {
974		run_test(|| {
975			assert_ok!(Pallet::<TestRuntime>::register(
976				RuntimeOrigin::signed(REGISTER_RELAYER),
977				150
978			));
979
980			System::<TestRuntime>::set_block_number(100);
981
982			assert_noop!(
983				Pallet::<TestRuntime>::deregister(RuntimeOrigin::signed(REGISTER_RELAYER)),
984				Error::<TestRuntime>::RegistrationIsStillActive,
985			);
986		});
987	}
988
989	#[test]
990	fn deregister_works() {
991		run_test(|| {
992			get_ready_for_events();
993
994			assert_ok!(Pallet::<TestRuntime>::register(
995				RuntimeOrigin::signed(REGISTER_RELAYER),
996				150
997			));
998
999			System::<TestRuntime>::set_block_number(151);
1000
1001			let reserved_balance = Balances::reserved_balance(REGISTER_RELAYER);
1002			let free_balance = Balances::free_balance(REGISTER_RELAYER);
1003			assert_ok!(Pallet::<TestRuntime>::deregister(RuntimeOrigin::signed(REGISTER_RELAYER)));
1004			assert_eq!(
1005				Balances::reserved_balance(REGISTER_RELAYER),
1006				reserved_balance - Stake::get()
1007			);
1008			assert_eq!(Balances::free_balance(REGISTER_RELAYER), free_balance + Stake::get());
1009
1010			assert_eq!(
1011				System::<TestRuntime>::events().last(),
1012				Some(&EventRecord {
1013					phase: Phase::Initialization,
1014					event: TestEvent::BridgeRelayers(Event::Deregistered {
1015						relayer: REGISTER_RELAYER
1016					}),
1017					topics: vec![],
1018				}),
1019			);
1020		});
1021	}
1022
1023	#[test]
1024	fn is_registration_active_is_false_for_unregistered_relayer() {
1025		run_test(|| {
1026			assert!(!Pallet::<TestRuntime>::is_registration_active(&REGISTER_RELAYER));
1027		});
1028	}
1029
1030	#[test]
1031	fn is_registration_active_is_false_when_stake_is_too_low() {
1032		run_test(|| {
1033			RegisteredRelayers::<TestRuntime>::insert(
1034				REGISTER_RELAYER,
1035				Registration { valid_till: 150, stake: Stake::get() - 1 },
1036			);
1037			assert!(!Pallet::<TestRuntime>::is_registration_active(&REGISTER_RELAYER));
1038		});
1039	}
1040
1041	#[test]
1042	fn is_registration_active_is_false_when_remaining_lease_is_too_low() {
1043		run_test(|| {
1044			System::<TestRuntime>::set_block_number(150 - Lease::get());
1045
1046			RegisteredRelayers::<TestRuntime>::insert(
1047				REGISTER_RELAYER,
1048				Registration { valid_till: 150, stake: Stake::get() },
1049			);
1050			assert!(!Pallet::<TestRuntime>::is_registration_active(&REGISTER_RELAYER));
1051		});
1052	}
1053
1054	#[test]
1055	fn is_registration_active_is_true_when_relayer_is_properly_registeered() {
1056		run_test(|| {
1057			System::<TestRuntime>::set_block_number(150 - Lease::get());
1058
1059			RegisteredRelayers::<TestRuntime>::insert(
1060				REGISTER_RELAYER,
1061				Registration { valid_till: 151, stake: Stake::get() },
1062			);
1063			assert!(Pallet::<TestRuntime>::is_registration_active(&REGISTER_RELAYER));
1064		});
1065	}
1066}