Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade registrations and unregister #254

Merged
merged 11 commits into from
Aug 16, 2022
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
145 changes: 126 additions & 19 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 @@ -173,6 +174,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())?;
clangenb marked this conversation as resolved.
Show resolved Hide resolved
let current_phase = <encointer_scheduler::Pallet<T>>::current_phase();
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
};

if let Some(participant_type) = Self::get_participant_type((cid, cindex), &sender) {
pifragile marked this conversation as resolved.
Show resolved Hide resolved
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())
}
} else {
return Err(<Error<T>>::ParticipantIsNotRegistered.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!(
vec![CeremonyPhaseType::Registering, CeremonyPhaseType::Attesting]
.contains(&current_phase),
Error::<T>::RegisteringOrAttestationPhaseRequired
);
pifragile marked this conversation as resolved.
Show resolved Hide resolved

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 {
if let Some(cc) = maybe_reputation_community_ceremony {
pifragile marked this conversation as resolved.
Show resolved Hide resolved
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);
} else {
return Err(<Error<T>>::ReputationCommunityCeremonyRequired.into())
}
}
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 +512,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 +858,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 +1303,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 +1312,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
45 changes: 45 additions & 0 deletions ceremonies/src/storage_helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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));
}
}