1#![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
51pub 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 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 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 #[allow(deprecated)]
78 type RuntimeEvent: From<Event<Self, I>>
79 + IsType<<Self as frame_system::Config>::RuntimeEvent>;
80
81 type RewardBalance: AtLeast32BitUnsigned + Copy + Member + Parameter + MaxEncodedLen;
83 type Reward: Parameter + MaxEncodedLen + Send + Sync + Copy + Clone;
90
91 type PaymentProcedure: PaymentProcedure<Self::AccountId, Self::Reward, Self::RewardBalance>;
93
94 type StakeAndSlash: StakeAndSlash<Self::AccountId, BlockNumberFor<Self>, Self::Balance>;
96 type Balance: Balance;
98
99 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 #[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 #[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 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 ensure!(
145 valid_till >= registration.valid_till,
146 Error::<T, I>::CannotReduceRegistrationLease,
147 );
148 registration.valid_till = valid_till;
149
150 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(®istration.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 #[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 ensure!(
205 registration.valid_till < frame_system::Pallet::<T>::block_number(),
206 Error::<T, I>::RegistrationIsStillActive,
207 );
208
209 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 #[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 pub fn registered_relayer(
242 relayer: &T::AccountId,
243 ) -> Option<Registration<BlockNumberFor<T>, T::Balance>> {
244 RegisteredRelayers::<T, I>::get(relayer)
245 }
246
247 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 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 if registration.stake < Self::required_stake() {
317 return false;
318 }
319
320 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 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 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 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 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 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 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 RewardRegistered {
476 relayer: T::AccountId,
478 reward_kind: T::Reward,
480 reward_balance: T::RewardBalance,
482 },
483 RewardPaid {
485 relayer: T::AccountId,
487 reward_kind: T::Reward,
489 reward_balance: T::RewardBalance,
491 beneficiary: BeneficiaryOf<T, I>,
493 },
494 RegistrationUpdated {
496 relayer: T::AccountId,
498 registration: Registration<BlockNumberFor<T>, T::Balance>,
500 },
501 Deregistered {
503 relayer: T::AccountId,
505 },
506 SlashedAndDeregistered {
508 relayer: T::AccountId,
510 registration: Registration<BlockNumberFor<T>, T::Balance>,
512 },
513 }
514
515 #[pallet::error]
516 pub enum Error<T, I = ()> {
517 NoRewardForRelayer,
519 FailedToPayReward,
521 InvalidRegistrationLease,
524 CannotReduceRegistrationLease,
526 FailedToReserve,
528 FailedToUnreserve,
530 NotRegistered,
532 RegistrationIsStillActive,
534 }
535
536 #[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 #[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
564impl<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 ®ULAR_RELAYER,
600 100,
601 );
602
603 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 assert_ok!(Pallet::<TestRuntime>::register(
626 RuntimeOrigin::signed(REGISTER_RELAYER),
627 150,
628 ));
629 let registration =
631 Pallet::<TestRuntime>::registered_relayer(®ISTER_RELAYER).unwrap();
632 assert_eq!(registration, Registration { valid_till: 150, stake: Stake::get() });
633
634 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(®ISTER_RELAYER, slash_destination);
642 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 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 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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_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(®ISTER_RELAYER));
1064 });
1065 }
1066}