Skip to content

Commit

Permalink
Upgrade registrations and unregister (#254)
Browse files Browse the repository at this point in the history
* make unregistering generic

* implement registration upgrading

* implement unregistering

* add benchmarks and weights

* use .ok_or

* move _unregister to storage_helper

* use register_participant extrinsic in tests

* introduce is_registering_or_attesting

* use ok_or

* estend tests

Co-authored-by: clangenb <37865735+clangenb@users.noreply.github.com>
  • Loading branch information
pifragile and clangenb committed Aug 16, 2022
1 parent 5b673f0 commit 45f328c
Show file tree
Hide file tree
Showing 6 changed files with 681 additions and 90 deletions.
54 changes: 54 additions & 0 deletions ceremonies/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,60 @@ benchmarks! {
);
}

upgrade_registration {
let cid = create_community::<T>();

let zoran = generate_pair();
let zoran_account= account_id::<T>(&zoran);
let proof = fake_last_attendance_and_get_proof::<T>(&zoran, cid);
let cindex = encointer_scheduler::Pallet::<T>::current_ceremony_index();

assert_ok!(Pallet::<T>::register_participant(
RawOrigin::Signed(zoran_account.clone()).into(),
cid,
None
));

assert_eq!(NewbieCount::<T>::get((cid, cindex)), 1);
}: _(RawOrigin::Signed(zoran_account.clone()), cid, proof)
verify {
assert_eq!(ReputableCount::<T>::get((cid, cindex)), 1);
assert_eq!(NewbieCount::<T>::get((cid, cindex)), 0);
assert_eq!(
Pallet::<T>::participant_reputation((cid, cindex - 1), zoran_account),
Reputation::VerifiedLinked
);
}

unregister_participant {
let cid = create_community::<T>();

let zoran = generate_pair();
let zoran_account= account_id::<T>(&zoran);
let proof = fake_last_attendance_and_get_proof::<T>(&zoran, cid);
let cindex = encointer_scheduler::Pallet::<T>::current_ceremony_index();

assert_ok!(Pallet::<T>::register_participant(
RawOrigin::Signed(zoran_account.clone()).into(),
cid,
Some(proof)
));

assert_eq!(ReputableCount::<T>::get((cid, cindex)), 1);
assert_eq!(
Pallet::<T>::participant_reputation((cid, cindex - 1), &zoran_account),
Reputation::VerifiedLinked
);
}: _(RawOrigin::Signed(zoran_account.clone()), cid, Some((cid, cindex - 1)))
verify {
assert_eq!(ReputableCount::<T>::get((cid, cindex)), 0);
assert_eq!(
Pallet::<T>::participant_reputation((cid, cindex - 1), zoran_account),
Reputation::VerifiedUnlinked
);
}


attest_claims {
let cid = create_community::<T>();

Expand Down
148 changes: 127 additions & 21 deletions ceremonies/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const LOG: &str = "encointer";
pub use pallet::*;
pub use weights::WeightInfo;

mod storage_helper;
#[allow(clippy::unused_unit)]
#[frame_support::pallet]
pub mod pallet {
Expand Down Expand Up @@ -109,8 +110,7 @@ pub mod pallet {
let sender = ensure_signed(origin)?;
let current_phase = <encointer_scheduler::Pallet<T>>::current_phase();
ensure!(
vec![CeremonyPhaseType::Registering, CeremonyPhaseType::Attesting]
.contains(&current_phase),
CeremonyPhaseType::is_registering_or_attesting(&current_phase),
Error::<T>::RegisteringOrAttestationPhaseRequired
);

Expand Down Expand Up @@ -173,6 +173,88 @@ pub mod pallet {
Ok(().into())
}

#[pallet::weight((<T as Config>::WeightInfo::upgrade_registration(), DispatchClass::Normal, Pays::Yes))]
pub fn upgrade_registration(
origin: OriginFor<T>,
cid: CommunityIdentifier,
proof: ProofOfAttendance<T::Signature, T::AccountId>,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin.clone())?;
let current_phase = <encointer_scheduler::Pallet<T>>::current_phase();
ensure!(
<encointer_communities::Pallet<T>>::community_identifiers().contains(&cid),
Error::<T>::InexistentCommunity
);

ensure!(
CeremonyPhaseType::is_registering_or_attesting(&current_phase),
Error::<T>::RegisteringOrAttestationPhaseRequired
);

let mut cindex = <encointer_scheduler::Pallet<T>>::current_ceremony_index();

if current_phase == CeremonyPhaseType::Attesting {
cindex += 1
};

let participant_type = Self::get_participant_type((cid, cindex), &sender)
.ok_or(<Error<T>>::ParticipantIsNotRegistered)?;
if participant_type == ParticipantType::Newbie {
Self::remove_participant_from_registry(cid, cindex, &sender)?;
Self::register_participant(origin, cid, Some(proof))?;
} else {
return Err(<Error<T>>::MustBeNewbieToUpgradeRegistration.into())
}
Ok(().into())
}

#[pallet::weight((<T as Config>::WeightInfo::unregister_participant(), DispatchClass::Normal, Pays::Yes))]
pub fn unregister_participant(
origin: OriginFor<T>,
cid: CommunityIdentifier,
maybe_reputation_community_ceremony: Option<CommunityCeremony>,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin)?;
let current_phase = <encointer_scheduler::Pallet<T>>::current_phase();
ensure!(
CeremonyPhaseType::is_registering_or_attesting(&current_phase),
Error::<T>::RegisteringOrAttestationPhaseRequired
);

ensure!(
<encointer_communities::Pallet<T>>::community_identifiers().contains(&cid),
Error::<T>::InexistentCommunity
);

let mut cindex = <encointer_scheduler::Pallet<T>>::current_ceremony_index();

if current_phase == CeremonyPhaseType::Attesting {
cindex += 1
};

let participant_type = Self::get_participant_type((cid, cindex), &sender)
.ok_or(<Error<T>>::ParticipantIsNotRegistered)?;
if participant_type == ParticipantType::Reputable {
let cc = maybe_reputation_community_ceremony
.ok_or(<Error<T>>::ReputationCommunityCeremonyRequired)?;
ensure!(
cc.1 >= cindex.saturating_sub(Self::reputation_lifetime()),
Error::<T>::ProofOutdated
);

ensure!(
Self::participant_reputation(&cc, &sender) == Reputation::VerifiedLinked,
Error::<T>::ReputationMustBeLinked
);

<ParticipantReputation<T>>::insert(&cc, &sender, Reputation::VerifiedUnlinked);
<ParticipantReputation<T>>::remove((cid, cindex), &sender);
}
Self::remove_participant_from_registry(cid, cindex, &sender)?;

Ok(().into())
}

#[pallet::weight((<T as Config>::WeightInfo::attest_attendees(), DispatchClass::Normal, Pays::Yes))]
pub fn attest_attendees(
origin: OriginFor<T>,
Expand Down Expand Up @@ -429,7 +511,7 @@ pub mod pallet {
<EndorseesCount<T>>::mutate((cid, cindex), |c| *c += 1); // safe; limited by AMOUNT_NEWBIE_TICKETS

if <NewbieIndex<T>>::contains_key((cid, cindex), &newbie) {
Self::unregister_newbie(cid, cindex, &newbie)?;
Self::remove_participant_from_registry(cid, cindex, &newbie)?;
Self::register(cid, cindex, &newbie, false)?;
}

Expand Down Expand Up @@ -775,6 +857,12 @@ pub mod pallet {
AttestationsBeyondTimeTolerance,
// Not possible to pay rewards in attestations phase
EarlyRewardsNotPossible,
// Only newbies can upgrade their registration
MustBeNewbieToUpgradeRegistration,
// To unregister as a reputable you need to provide a provide a community ceremony where you have a linked reputation
ReputationCommunityCeremonyRequired,
// In order to unregister a reputable, the provided reputation must be linked
ReputationMustBeLinked,
}

#[pallet::storage]
Expand Down Expand Up @@ -1214,7 +1302,7 @@ impl<T: Config> Pallet<T> {
}

/// removes a participant from the registry maintaining continuous indices
fn unregister_newbie(
fn remove_participant_from_registry(
cid: CommunityIdentifier,
cindex: CeremonyIndexType,
participant: &T::AccountId,
Expand All @@ -1223,25 +1311,43 @@ impl<T: Config> Pallet<T> {
return Err(<Error<T>>::WrongPhaseForUnregistering)
}

let participant_count = <NewbieCount<T>>::get((cid, cindex));

if !<NewbieIndex<T>>::contains_key((cid, cindex), &participant) || participant_count < 1 {
return Ok(())
let participant_type = Self::get_participant_type((cid, cindex), participant)
.ok_or(<Error<T>>::ParticipantIsNotRegistered)?;
match participant_type {
ParticipantType::Bootstrapper => {
storage_helper::remove_participant_from_registry::<
BootstrapperIndex<T>,
BootstrapperRegistry<T>,
BootstrapperCount<T>,
T::AccountId,
>(cid, cindex, participant);
},
ParticipantType::Reputable => {
storage_helper::remove_participant_from_registry::<
ReputableIndex<T>,
ReputableRegistry<T>,
ReputableCount<T>,
T::AccountId,
>(cid, cindex, participant);
},
ParticipantType::Endorsee => {
storage_helper::remove_participant_from_registry::<
EndorseeIndex<T>,
EndorseeRegistry<T>,
EndorseeCount<T>,
T::AccountId,
>(cid, cindex, participant);
},
ParticipantType::Newbie => {
storage_helper::remove_participant_from_registry::<
NewbieIndex<T>,
NewbieRegistry<T>,
NewbieCount<T>,
T::AccountId,
>(cid, cindex, participant);
},
}

let participant_index = <NewbieIndex<T>>::get((cid, cindex), &participant);

let last_participant = <NewbieRegistry<T>>::get((cid, cindex), &participant_count)
.expect("Indices are continuous, thus index participant_count is Some; qed");

<NewbieRegistry<T>>::insert((cid, cindex), &participant_index, &last_participant);
<NewbieIndex<T>>::insert((cid, cindex), &last_participant, &participant_index);

<NewbieRegistry<T>>::remove((cid, cindex), &participant_count);
<NewbieIndex<T>>::remove((cid, cindex), &participant);

<NewbieCount<T>>::insert((cid, cindex), participant_count.saturating_sub(1));

Ok(())
}

Expand Down
44 changes: 44 additions & 0 deletions ceremonies/src/storage_helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use codec::{Decode, EncodeLike};
use encointer_primitives::{
ceremonies::{CommunityCeremony, ParticipantIndexType},
communities::CommunityIdentifier,
scheduler::CeremonyIndexType,
};
pub fn remove_participant_from_registry<Index, Registry, Count, AccountId>(
cid: CommunityIdentifier,
cindex: CeremonyIndexType,
participant: &AccountId,
) where
Index: frame_support::StorageDoubleMap<
CommunityCeremony,
AccountId,
ParticipantIndexType,
Query = ParticipantIndexType,
>,
Registry: frame_support::StorageDoubleMap<
CommunityCeremony,
ParticipantIndexType,
AccountId,
Query = Option<AccountId>,
>,
Count: frame_support::StorageMap<
CommunityCeremony,
ParticipantIndexType,
Query = ParticipantIndexType,
>,
AccountId: EncodeLike + Decode,
{
let participant_count = Count::get((cid, cindex));
let participant_index = Index::get((cid, cindex), &participant);
let maybe_last_participant = Registry::get((cid, cindex), participant_count);

if let Some(last_participant) = maybe_last_participant {
Registry::insert((cid, cindex), participant_index, &last_participant);
Index::insert((cid, cindex), last_participant, participant_index);

Registry::remove((cid, cindex), participant_count);
Index::remove((cid, cindex), &participant);

Count::insert((cid, cindex), participant_count.saturating_sub(1));
}
}

0 comments on commit 45f328c

Please sign in to comment.