Skip to content
Snippets Groups Projects
Commit e00ff86a authored by Hugo Trentesaux's avatar Hugo Trentesaux
Browse files

cargo check ok

parent a0a4054f
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
mod median; mod median;
mod traits; pub mod traits;
mod types; mod types;
mod weights; mod weights;
...@@ -66,6 +66,7 @@ pub mod pallet { ...@@ -66,6 +66,7 @@ pub mod pallet {
+ pallet_identity::Config<IdtyIndex = IdtyIndex> + pallet_identity::Config<IdtyIndex = IdtyIndex>
+ pallet_session::Config + pallet_session::Config
{ {
/// Currency type used in this pallet (used for reserve/slash)
type Currency: ReservableCurrency<Self::AccountId>; type Currency: ReservableCurrency<Self::AccountId>;
/// Amount reserved during evaluation /// Amount reserved during evaluation
#[pallet::constant] #[pallet::constant]
...@@ -81,6 +82,8 @@ pub mod pallet { ...@@ -81,6 +82,8 @@ pub mod pallet {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Type representing the weight of this pallet /// Type representing the weight of this pallet
type WeightInfo: WeightInfo; type WeightInfo: WeightInfo;
/// Handler for successful distance evaluation
type OnValidDistanceStatus: OnValidDistanceStatus<Self>;
} }
// STORAGE // // STORAGE //
...@@ -139,20 +142,6 @@ pub mod pallet { ...@@ -139,20 +142,6 @@ pub mod pallet {
OptionQuery, OptionQuery,
>; >;
/// Identities by distance status expiration session index
#[pallet::storage]
#[pallet::getter(fn distance_status_expire_on)]
pub type DistanceStatusExpireOn<T: Config> = StorageMap<
_,
Twox64Concat,
u32,
BoundedVec<
<T as pallet_identity::Config>::IdtyIndex,
ConstU32<MAX_EVALUATIONS_PER_SESSION>,
>,
ValueQuery,
>;
/// Did evaluation get updated in this block? /// Did evaluation get updated in this block?
#[pallet::storage] #[pallet::storage]
pub(super) type DidUpdate<T: Config> = StorageValue<_, bool, ValueQuery>; pub(super) type DidUpdate<T: Config> = StorageValue<_, bool, ValueQuery>;
...@@ -224,7 +213,9 @@ pub mod pallet { ...@@ -224,7 +213,9 @@ pub mod pallet {
#[pallet::call] #[pallet::call]
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// Request an identity to be evaluated /// Request caller identity to be evaluated
/// positive evaluation will result in claim/renew membership
/// negative evaluation will result in slash for caller
#[pallet::call_index(0)] #[pallet::call_index(0)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::request_distance_evaluation())] #[pallet::weight(<T as pallet::Config>::WeightInfo::request_distance_evaluation())]
pub fn request_distance_evaluation(origin: OriginFor<T>) -> DispatchResultWithPostInfo { pub fn request_distance_evaluation(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
...@@ -233,6 +224,8 @@ pub mod pallet { ...@@ -233,6 +224,8 @@ pub mod pallet {
let idty = let idty =
pallet_identity::IdentityIndexOf::<T>::get(&who).ok_or(Error::<T>::NoIdentity)?; pallet_identity::IdentityIndexOf::<T>::get(&who).ok_or(Error::<T>::NoIdentity)?;
// TODO is it necessary to check that the same account performed the request?
// TODO what if the distance status is existing but valid?
ensure!( ensure!(
IdentityDistanceStatus::<T>::get(idty) IdentityDistanceStatus::<T>::get(idty)
!= Some((who.clone(), DistanceStatus::Pending)), != Some((who.clone(), DistanceStatus::Pending)),
...@@ -243,13 +236,49 @@ pub mod pallet { ...@@ -243,13 +236,49 @@ pub mod pallet {
Ok(().into()) Ok(().into())
} }
/// Request target identity to be evaluated
/// only possible for unconfirmed identity
#[pallet::call_index(4)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::request_distance_evaluation())]
pub fn request_distance_evaluation_for(
origin: OriginFor<T>,
target: T::IdtyIndex,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
// check that the caller has an identity (TODO is this necessary ?)
// let _ =
// pallet_identity::IdentityIndexOf::<T>::get(&who).ok_or(Error::<T>::NoIdentity)?;
// get the identity value of the target
let target_idty =
pallet_identity::Identities::<T>::get(target).ok_or(Error::<T>::NoIdentity)?;
// check that target is unconfirmed
ensure!(
target_idty.status == pallet_identity::IdtyStatus::Unconfirmed,
Error::<T>::NoIdentity
);
// check that no distance status is already there
ensure!(
IdentityDistanceStatus::<T>::get(target).is_none(),
Error::<T>::AlreadyInEvaluation
);
Pallet::<T>::do_request_distance_evaluation(who, target)?;
Ok(().into())
}
/// (Inherent) Push an evaluation result to the pool /// (Inherent) Push an evaluation result to the pool
/// this is called internally by validators (= inherent)
#[pallet::call_index(1)] #[pallet::call_index(1)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::update_evaluation(MAX_EVALUATIONS_PER_SESSION))] #[pallet::weight(<T as pallet::Config>::WeightInfo::update_evaluation(MAX_EVALUATIONS_PER_SESSION))]
pub fn update_evaluation( pub fn update_evaluation(
origin: OriginFor<T>, origin: OriginFor<T>,
computation_result: ComputationResult, computation_result: ComputationResult,
) -> DispatchResult { ) -> DispatchResult {
// no origin = inherent
ensure_none(origin)?; ensure_none(origin)?;
ensure!( ensure!(
!DidUpdate::<T>::exists(), !DidUpdate::<T>::exists(),
...@@ -263,7 +292,8 @@ pub mod pallet { ...@@ -263,7 +292,8 @@ pub mod pallet {
Ok(()) Ok(())
} }
/// Push an evaluation result to the pool /// Force push an evaluation result to the pool
// (it is convenient to have this call in end2end tests)
#[pallet::call_index(2)] #[pallet::call_index(2)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::force_update_evaluation(MAX_EVALUATIONS_PER_SESSION))] #[pallet::weight(<T as pallet::Config>::WeightInfo::force_update_evaluation(MAX_EVALUATIONS_PER_SESSION))]
pub fn force_update_evaluation( pub fn force_update_evaluation(
...@@ -276,7 +306,8 @@ pub mod pallet { ...@@ -276,7 +306,8 @@ pub mod pallet {
Pallet::<T>::do_update_evaluation(evaluator, computation_result) Pallet::<T>::do_update_evaluation(evaluator, computation_result)
} }
/// Set the distance evaluation status of an identity /// Force set the distance evaluation status of an identity
// (it is convenient to have this in test network)
/// ///
/// Removes the status if `status` is `None`. /// Removes the status if `status` is `None`.
/// ///
...@@ -292,15 +323,7 @@ pub mod pallet { ...@@ -292,15 +323,7 @@ pub mod pallet {
) -> DispatchResult { ) -> DispatchResult {
ensure_root(origin)?; ensure_root(origin)?;
IdentityDistanceStatus::<T>::set(identity, status.clone()); Self::do_set_distance_status(identity, status.clone());
DistanceStatusExpireOn::<T>::mutate(
pallet_session::CurrentIndex::<T>::get() + T::ResultExpiration::get(),
move |identities| {
identities
.try_push(identity)
.map_err(|_| Error::<T>::TooManyEvaluationsInBlock)
},
)?;
Self::deposit_event(Event::EvaluationStatusForced { Self::deposit_event(Event::EvaluationStatusForced {
idty_index: identity, idty_index: identity,
status, status,
...@@ -309,27 +332,6 @@ pub mod pallet { ...@@ -309,27 +332,6 @@ pub mod pallet {
} }
} }
// BENCHMARK FUNCTIONS //
impl<T: Config> Pallet<T> {
/// Force the distance status using IdtyIndex and AccountId
/// only to prepare identity for benchmarking.
pub fn set_distance_status(
identity: <T as pallet_identity::Config>::IdtyIndex,
status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>,
) -> DispatchResult {
IdentityDistanceStatus::<T>::set(identity, status);
DistanceStatusExpireOn::<T>::mutate(
pallet_session::CurrentIndex::<T>::get() + T::ResultExpiration::get(),
move |identities| {
identities
.try_push(identity)
.map_err(|_| Error::<T>::TooManyEvaluationsInBlock.into())
},
)
}
}
// INTERNAL FUNCTIONS // // INTERNAL FUNCTIONS //
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
...@@ -394,6 +396,7 @@ pub mod pallet { ...@@ -394,6 +396,7 @@ pub mod pallet {
} }
} }
/// request distance evaluation in current pool
fn do_request_distance_evaluation( fn do_request_distance_evaluation(
who: T::AccountId, who: T::AccountId,
idty_index: <T as pallet_identity::Config>::IdtyIndex, idty_index: <T as pallet_identity::Config>::IdtyIndex,
...@@ -418,31 +421,31 @@ pub mod pallet { ...@@ -418,31 +421,31 @@ pub mod pallet {
(&who, DistanceStatus::Pending), (&who, DistanceStatus::Pending),
); );
DistanceStatusExpireOn::<T>::mutate(
pallet_session::CurrentIndex::<T>::get() + T::ResultExpiration::get(),
move |identities| identities.try_push(idty_index).ok(),
);
Self::deposit_event(Event::EvaluationRequested { idty_index, who }); Self::deposit_event(Event::EvaluationRequested { idty_index, who });
Ok(()) Ok(())
}, },
) )
} }
/// update distance evaluation in next pool
fn do_update_evaluation( fn do_update_evaluation(
evaluator: <T as frame_system::Config>::AccountId, evaluator: <T as frame_system::Config>::AccountId,
computation_result: ComputationResult, computation_result: ComputationResult,
) -> DispatchResult { ) -> DispatchResult {
Pallet::<T>::mutate_next_pool(pallet_session::CurrentIndex::<T>::get(), |result_pool| { Pallet::<T>::mutate_next_pool(pallet_session::CurrentIndex::<T>::get(), |result_pool| {
// evaluation must be provided for all identities (no more, no less)
ensure!( ensure!(
computation_result.distances.len() == result_pool.evaluations.len(), computation_result.distances.len() == result_pool.evaluations.len(),
Error::<T>::WrongResultLength Error::<T>::WrongResultLength
); );
// insert the evaluator if not already there
if result_pool if result_pool
.evaluators .evaluators
.try_insert(evaluator.clone()) .try_insert(evaluator.clone())
.map_err(|_| Error::<T>::TooManyEvaluators)? .map_err(|_| Error::<T>::TooManyEvaluators)?
{ {
// update the median accumulator with the new result
for (distance_value, (_identity, median_acc)) in computation_result for (distance_value, (_identity, median_acc)) in computation_result
.distances .distances
.into_iter() .into_iter()
...@@ -454,19 +457,28 @@ pub mod pallet { ...@@ -454,19 +457,28 @@ pub mod pallet {
Self::deposit_event(Event::EvaluationUpdated { evaluator }); Self::deposit_event(Event::EvaluationUpdated { evaluator });
Ok(()) Ok(())
} else { } else {
// one author can only submit one evaluation
Err(Error::<T>::TooManyEvaluationsByAuthor.into()) Err(Error::<T>::TooManyEvaluationsByAuthor.into())
} }
}) })
} }
/// Set the distance status using IdtyIndex and AccountId
pub fn do_set_distance_status(
identity: <T as pallet_identity::Config>::IdtyIndex,
status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>,
) {
IdentityDistanceStatus::<T>::set(identity, status.clone());
if let Some((_, DistanceStatus::Valid)) = status {
T::OnValidDistanceStatus::on_valid_distance_status(identity);
}
}
} }
impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> { impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> {
fn on_new_session(index: SessionIndex) { fn on_new_session(index: SessionIndex) {
EvaluationBlock::<T>::set(frame_system::Pallet::<T>::parent_hash()); EvaluationBlock::<T>::set(frame_system::Pallet::<T>::parent_hash());
// Make results expire
DistanceStatusExpireOn::<T>::remove(index);
// Apply the results from the current pool (which was previous session's result pool) // Apply the results from the current pool (which was previous session's result pool)
// We take the results so the pool is left empty for the new session. // We take the results so the pool is left empty for the new session.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
......
...@@ -259,6 +259,7 @@ impl pallet_distance::Config for Test { ...@@ -259,6 +259,7 @@ impl pallet_distance::Config for Test {
type ResultExpiration = frame_support::traits::ConstU32<720>; type ResultExpiration = frame_support::traits::ConstU32<720>;
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = (); type WeightInfo = ();
type OnValidDistanceStatus = ();
} }
// Build genesis storage according to the mock runtime. // Build genesis storage according to the mock runtime.
......
...@@ -14,8 +14,13 @@ ...@@ -14,8 +14,13 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. // along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
pub trait HandleNegativeEvaluation<T: crate::Config> { use crate::*;
/// Do something with the reserved amount on the account,
/// when distance evaluation result is negative. pub trait OnValidDistanceStatus<T: Config> {
fn handle_negative_evaluation(account_id: T::AccountId); /// Handler for valid distance evaluation
fn on_valid_distance_status(idty_index: T::IdtyIndex);
}
impl<T: Config> OnValidDistanceStatus<T> for () {
fn on_valid_distance_status(_idty_index: T::IdtyIndex) {}
} }
...@@ -356,3 +356,28 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI ...@@ -356,3 +356,28 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI
} }
} }
} }
/// valid distance status handler
impl<T: Config<I> + pallet_distance::Config, I: 'static>
pallet_distance::traits::OnValidDistanceStatus<T> for Pallet<T, I>
{
fn on_valid_distance_status(idty_index: IdtyIndex) {
if let Some(identity) = pallet_identity::Identities::<T>::get(idty_index) {
match identity.status {
IdtyStatus::Unconfirmed => { /* should not happen */ }
IdtyStatus::Unvalidated | IdtyStatus::NotMember => {
// ok to fail
let _ = pallet_membership::Pallet::<T, I>::try_claim_membership(idty_index);
}
IdtyStatus::Member => {
// ok to fail
let _ = pallet_membership::Pallet::<T, I>::try_renew_membership(idty_index);
}
IdtyStatus::Revoked => { /* should not happen */ }
}
} else {
// identity was removed before distance status was found
// so it's ok to do nothing
}
}
}
...@@ -203,8 +203,7 @@ pub mod pallet { ...@@ -203,8 +203,7 @@ pub mod pallet {
// get identity // get identity
let idty_id = Self::get_idty_id(origin)?; let idty_id = Self::get_idty_id(origin)?;
Self::check_allowed_to_claim(idty_id)?; Self::try_claim_membership(idty_id)?;
Self::do_add_membership(idty_id);
Ok(().into()) Ok(().into())
} }
...@@ -214,16 +213,8 @@ pub mod pallet { ...@@ -214,16 +213,8 @@ pub mod pallet {
pub fn renew_membership(origin: OriginFor<T>) -> DispatchResultWithPostInfo { pub fn renew_membership(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// Verify phase // Verify phase
let idty_id = Self::get_idty_id(origin)?; let idty_id = Self::get_idty_id(origin)?;
let membership_data =
Membership::<T, I>::get(idty_id).ok_or(Error::<T, I>::MembershipNotFound)?;
T::CheckMembershipCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
// apply phase
Self::unschedule_membership_expiry(idty_id, membership_data.expire_on);
Self::insert_membership_and_schedule_expiry(idty_id);
T::OnEvent::on_event(&sp_membership::Event::MembershipRenewed(idty_id));
Self::try_renew_membership(idty_id)?;
Ok(().into()) Ok(().into())
} }
...@@ -274,12 +265,48 @@ pub mod pallet { ...@@ -274,12 +265,48 @@ pub mod pallet {
Ok(()) Ok(())
} }
/// check that membership can be renewed
pub fn check_allowed_to_renew(
idty_id: T::IdtyId,
) -> Result<MembershipData<T::BlockNumber>, DispatchError> {
let membership_data =
Membership::<T, I>::get(idty_id).ok_or(Error::<T, I>::MembershipNotFound)?;
// enough certifications and distance rule for example
T::CheckMembershipCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
Ok(membership_data)
}
/// try claim membership
pub fn try_claim_membership(idty_id: T::IdtyId) -> Result<(), DispatchError> {
Self::check_allowed_to_claim(idty_id)?;
Self::do_add_membership(idty_id);
Ok(())
}
/// try renew membership
pub fn try_renew_membership(idty_id: T::IdtyId) -> Result<(), DispatchError> {
let membership_data = Self::check_allowed_to_renew(idty_id)?;
Self::do_renew_membership(idty_id, membership_data);
Ok(())
}
/// perform membership addition /// perform membership addition
fn do_add_membership(idty_id: T::IdtyId) { fn do_add_membership(idty_id: T::IdtyId) {
Self::insert_membership_and_schedule_expiry(idty_id); Self::insert_membership_and_schedule_expiry(idty_id);
T::OnEvent::on_event(&sp_membership::Event::MembershipAdded(idty_id)); T::OnEvent::on_event(&sp_membership::Event::MembershipAdded(idty_id));
} }
/// perform membership renewal
fn do_renew_membership(
idty_id: T::IdtyId,
membership_data: MembershipData<T::BlockNumber>,
) {
Self::unschedule_membership_expiry(idty_id, membership_data.expire_on);
Self::insert_membership_and_schedule_expiry(idty_id);
T::OnEvent::on_event(&sp_membership::Event::MembershipRenewed(idty_id));
}
/// perform membership removal /// perform membership removal
pub fn do_remove_membership(idty_id: T::IdtyId, reason: MembershipRemovalReason) { pub fn do_remove_membership(idty_id: T::IdtyId, reason: MembershipRemovalReason) {
if let Some(membership_data) = Membership::<T, I>::take(idty_id) { if let Some(membership_data) = Membership::<T, I>::take(idty_id) {
......
...@@ -522,6 +522,7 @@ macro_rules! pallets_config { ...@@ -522,6 +522,7 @@ macro_rules! pallets_config {
type ResultExpiration = frame_support::traits::ConstU32<720>; type ResultExpiration = frame_support::traits::ConstU32<720>;
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = common_runtime::weights::pallet_distance::WeightInfo<Runtime>; type WeightInfo = common_runtime::weights::pallet_distance::WeightInfo<Runtime>;
type OnValidDistanceStatus = Wot;
} }
// SMITHS SUB-WOT // // SMITHS SUB-WOT //
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment