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
186 changes: 171 additions & 15 deletions ceremonies/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,94 @@ 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
};

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::Reputable {
if let Some(cc) = maybe_reputation_community_ceremony {
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)?;
} else {
return Err(<Error<T>>::ParticipantIsNotRegistered.into())
}
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 +517,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 +863,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 +1308,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,26 +1317,88 @@ 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(())
if let Some(participant_type) = Self::get_participant_type((cid, cindex), participant) {
pifragile marked this conversation as resolved.
Show resolved Hide resolved
match participant_type {
ParticipantType::Bootstrapper => {
Self::_unregister::<
BootstrapperIndex<T>,
BootstrapperRegistry<T>,
BootstrapperCount<T>,
>(cid, cindex, participant);
},
ParticipantType::Reputable => {
Self::_unregister::<ReputableIndex<T>, ReputableRegistry<T>, ReputableCount<T>>(
cid,
cindex,
participant,
);
},
ParticipantType::Endorsee => {
Self::_unregister::<EndorseeIndex<T>, EndorseeRegistry<T>, EndorseeCount<T>>(
cid,
cindex,
participant,
);
},
ParticipantType::Newbie => {
Self::_unregister::<NewbieIndex<T>, NewbieRegistry<T>, NewbieCount<T>>(
cid,
cindex,
participant,
);
},
}
} else {
return Err(<Error<T>>::ParticipantIsNotRegistered)
}

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

let last_participant = <NewbieRegistry<T>>::get((cid, cindex), &participant_count)
.expect("Indices are continuous, thus index participant_count is Some; qed");
fn _unregister<Index, Registry, Count>(
pifragile marked this conversation as resolved.
Show resolved Hide resolved
cid: CommunityIdentifier,
cindex: CeremonyIndexType,
participant: &T::AccountId,
) where
Index:
frame_support::StorageDoubleMap<CommunityCeremony, T::AccountId, ParticipantIndexType>,
Registry:
frame_support::StorageDoubleMap<CommunityCeremony, ParticipantIndexType, T::AccountId>,
Count: frame_support::StorageMap<CommunityCeremony, ParticipantIndexType>,
ParticipantIndexType:
From<<Count as frame_support::StorageMap<(CommunityIdentifier, u32), u64>>::Query>,
ParticipantIndexType: From<
<Index as frame_support::StorageDoubleMap<
CommunityCeremony,
T::AccountId,
ParticipantIndexType,
>>::Query,
>,
Option<T::AccountId>: From<
<Registry as frame_support::StorageDoubleMap<
CommunityCeremony,
ParticipantIndexType,
T::AccountId,
>>::Query,
>,
{
let participant_count: ParticipantIndexType = Count::get((cid, cindex)).into();

<NewbieRegistry<T>>::insert((cid, cindex), &participant_index, &last_participant);
<NewbieIndex<T>>::insert((cid, cindex), &last_participant, &participant_index);
let participant_index: ParticipantIndexType =
Index::get((cid, cindex), &participant).into();

<NewbieRegistry<T>>::remove((cid, cindex), &participant_count);
<NewbieIndex<T>>::remove((cid, cindex), &participant);
let maybe_last_participant: Option<T::AccountId> =
Registry::get((cid, cindex), participant_count).into();

<NewbieCount<T>>::insert((cid, cindex), participant_count.saturating_sub(1));
if let Some(last_participant) = maybe_last_participant {
Registry::insert((cid, cindex), participant_index, &last_participant);
Index::insert((cid, cindex), last_participant, participant_index);

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

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

fn is_registered(
Expand Down