diff --git a/pallets/smith-members/src/lib.rs b/pallets/smith-members/src/lib.rs index 3ec870a07df8d6d6401c20059ec89a77e7cbd2d8..68221c0cf0a1eb848ae6691fa93ef5ce350ab77d 100644 --- a/pallets/smith-members/src/lib.rs +++ b/pallets/smith-members/src/lib.rs @@ -225,30 +225,28 @@ pub mod pallet { #[pallet::error] pub enum Error<T> { - /// Certification issuer has no known identity ID - UnknownIssuer, + /// Issuer of anything (invitation, acceptance, certification) must have an identity ID + OriginMustHaveAnIdentity, /// Issuer must be known as a potential smith - IssuerHasNoSmithStatus, + OriginHasNeverBeenInvited, /// Invitation is reseverd to smiths - CannotInvite, - /// Must have receive invitation to accept it - NotInvited, + InvitationIsASmithPrivilege, /// Invitation must not have been accepted yet - AlreadyAcceptedInvitation, - /// Recevier must not be known among smiths - OnlyExcludedCanComeBack, - /// Recevier must have accepted to eventually become a smith - ReceveirMustAcceptInvitation, + InvitationAlreadyAccepted, + /// Invitation of an already known smith is forbidden except if it has been excluded + InvitationOfNonExcluded, + /// Certification cannot be made on someone who has not accepted an invitation + CertificationMustBeAgreed, + /// Certification cannot be made on excluded + CertificationOnExcludedIsForbidden, /// Issuer must be a smith - IssuerIsNotASmith, + CertificationIsASmithPrivilege, /// Smith cannot certify itself - CannotCertifySelf, + CertificationOfSelfIsForbidden, /// Receiver must be invited by another smith - ReceiverHasNotBeenInvited, - /// Smith must be a member of the main WoT - NotAMember, + CertificationReceiverMustHaveBeenInvited, /// A smith has a limited stock of certifications - TooMuchCertificationsIssued, + CertificationStockFullyConsumed, } #[pallet::call] @@ -260,7 +258,8 @@ pub mod pallet { receiver: T::IdtyIndex, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin.clone())?; - let issuer = T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::UnknownIssuer)?; + let issuer = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; Self::check_invite_smith(issuer, receiver)?; Self::do_invite_smith(issuer, receiver); Ok(().into()) @@ -270,7 +269,8 @@ pub mod pallet { #[pallet::weight(1_000_000_000)] pub fn accept_invitation(origin: OriginFor<T>) -> DispatchResultWithPostInfo { let who = ensure_signed(origin.clone())?; - let receiver = T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::UnknownIssuer)?; + let receiver = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; Self::check_accept_invitation(receiver)?; Self::do_accept_invitation(receiver)?; Ok(().into()) @@ -283,7 +283,8 @@ pub mod pallet { receiver: T::IdtyIndex, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let issuer = T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::UnknownIssuer)?; + let issuer = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; Self::check_certify_smith(issuer, receiver)?; Self::do_certify_smith(receiver, issuer); Ok(().into()) @@ -297,16 +298,16 @@ impl<T: Config> Pallet<T> { receiver: T::IdtyIndex, ) -> DispatchResultWithPostInfo { let issuer_status = Smiths::<T>::get(issuer) - .ok_or(Error::<T>::IssuerHasNoSmithStatus)? + .ok_or(Error::<T>::OriginHasNeverBeenInvited)? .status; ensure!( issuer_status == SmithStatus::Smith, - Error::<T>::CannotInvite + Error::<T>::InvitationIsASmithPrivilege ); if let Some(receiver_meta) = Smiths::<T>::get(receiver) { ensure!( receiver_meta.status == SmithStatus::Excluded, - Error::<T>::OnlyExcludedCanComeBack + Error::<T>::InvitationOfNonExcluded ); } @@ -343,11 +344,11 @@ impl<T: Config> Pallet<T> { fn check_accept_invitation(receiver: T::IdtyIndex) -> DispatchResultWithPostInfo { let pretender_status = Smiths::<T>::get(receiver) - .ok_or(Error::<T>::NotInvited)? + .ok_or(Error::<T>::OriginHasNeverBeenInvited)? .status; ensure!( pretender_status == SmithStatus::Invited, - Error::<T>::AlreadyAcceptedInvitation + Error::<T>::InvitationAlreadyAccepted ); Ok(().into()) } @@ -367,23 +368,30 @@ impl<T: Config> Pallet<T> { issuer: T::IdtyIndex, receiver: T::IdtyIndex, ) -> DispatchResultWithPostInfo { - ensure!(issuer != receiver, Error::<T>::CannotCertifySelf); - let issuer = Smiths::<T>::get(issuer).ok_or(Error::<T>::IssuerHasNoSmithStatus)?; + ensure!( + issuer != receiver, + Error::<T>::CertificationOfSelfIsForbidden + ); + let issuer = Smiths::<T>::get(issuer).ok_or(Error::<T>::OriginHasNeverBeenInvited)?; ensure!( issuer.status == SmithStatus::Smith, - Error::<T>::IssuerIsNotASmith + Error::<T>::CertificationIsASmithPrivilege ); let issued_certs = issuer.issued_certs.len() as u32; ensure!( issued_certs < T::MaxByIssuer::get(), - Error::<T>::TooMuchCertificationsIssued + Error::<T>::CertificationStockFullyConsumed ); let receiver_status = Smiths::<T>::get(receiver) - .ok_or(Error::<T>::ReceiverHasNotBeenInvited)? + .ok_or(Error::<T>::CertificationReceiverMustHaveBeenInvited)? .status; ensure!( receiver_status != SmithStatus::Invited, - Error::<T>::ReceveirMustAcceptInvitation + Error::<T>::CertificationMustBeAgreed + ); + ensure!( + receiver_status != SmithStatus::Excluded, + Error::<T>::CertificationOnExcludedIsForbidden ); Ok(().into()) diff --git a/pallets/smith-members/src/tests.rs b/pallets/smith-members/src/tests.rs index 885567b6c679fc8d7eebf2ad0aa662c01d144b22..0d8eaabd168a6ca0ec7bdc26864f0a91045e163d 100644 --- a/pallets/smith-members/src/tests.rs +++ b/pallets/smith-members/src/tests.rs @@ -20,6 +20,7 @@ use super::*; use crate::mock::{new_test_ext, run_to_block, Runtime, RuntimeEvent, RuntimeOrigin, System}; use frame_support::{assert_err, assert_ok}; +use crate::SmithStatus::{Excluded, Invited, Pending, Smith}; #[cfg(test)] use maplit::btreemap; use pallet_authority_members::OnNewSession; @@ -204,19 +205,19 @@ fn should_have_checks_on_certify() { // Tries all possible errors assert_err!( Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(0), 1), - Error::<Runtime>::IssuerHasNoSmithStatus + Error::<Runtime>::OriginHasNeverBeenInvited ); assert_err!( Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 1), - Error::<Runtime>::CannotCertifySelf + Error::<Runtime>::CertificationOfSelfIsForbidden ); assert_err!( Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(3), 5), - Error::<Runtime>::IssuerIsNotASmith + Error::<Runtime>::CertificationIsASmithPrivilege ); assert_err!( Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 6), - Error::<Runtime>::ReceiverHasNotBeenInvited + Error::<Runtime>::CertificationReceiverMustHaveBeenInvited ); // #3: state before @@ -396,7 +397,70 @@ fn smith_coming_back_recovers_its_issued_certs() { // Max stock is reached (3 = 1 recovered + 2 new) assert_err!( Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(2), 5), - Error::<Runtime>::TooMuchCertificationsIssued + Error::<Runtime>::CertificationStockFullyConsumed + ); + }); +} + +#[test] +fn certifying_on_different_status() { + new_test_ext(GenesisConfig { + certs_by_receiver: btreemap![ + 1 => vec![2, 3, 4], + 2 => vec![3, 4], + 3 => vec![1, 2], + 4 => vec![], + ], + }) + .execute_with(|| { + // State before + assert_eq!(Smiths::<Runtime>::get(5), None); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationReceiverMustHaveBeenInvited + ); + + // After invitation + assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 5)); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Invited); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationMustBeAgreed + ); + + // After acceptation + assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed( + 5 + ))); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(1), + 5 + )); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(2), + 5 + )); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Smith); + + // After being a smith + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(3), + 5 + )); + + Pallet::<Runtime>::smith_goes_online(1); + Pallet::<Runtime>::smith_goes_online(2); + Pallet::<Runtime>::on_new_session(5); + assert_eq!(Smiths::<Runtime>::get(1).unwrap().status, Smith); + assert_eq!(Smiths::<Runtime>::get(2).unwrap().status, Smith); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Excluded); + + // After being excluded + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationOnExcludedIsForbidden ); }); }