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

cargo check ok

parent 4184a627
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !219. Comments created here will be created in the context of that merge request.
...@@ -37,6 +37,7 @@ use pallet_authority_members::SessionIndex; ...@@ -37,6 +37,7 @@ use pallet_authority_members::SessionIndex;
use sp_distance::{InherentError, INHERENT_IDENTIFIER}; use sp_distance::{InherentError, INHERENT_IDENTIFIER};
use sp_inherents::{InherentData, InherentIdentifier}; use sp_inherents::{InherentData, InherentIdentifier};
use sp_std::convert::TryInto; use sp_std::convert::TryInto;
use sp_std::prelude::*;
type IdtyIndex = u32; type IdtyIndex = u32;
...@@ -77,6 +78,8 @@ pub mod pallet { ...@@ -77,6 +78,8 @@ pub mod pallet {
#[pallet::constant] #[pallet::constant]
type MinAccessibleReferees: Get<Perbill>; type MinAccessibleReferees: Get<Perbill>;
/// Number of session to keep a positive evaluation result /// Number of session to keep a positive evaluation result
// (antispam mechanism)
#[pallet::constant]
type ResultExpiration: Get<u32>; type ResultExpiration: Get<u32>;
/// The overarching event type. /// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
...@@ -127,18 +130,34 @@ pub mod pallet { ...@@ -127,18 +130,34 @@ pub mod pallet {
pub type EvaluationBlock<T: Config> = pub type EvaluationBlock<T: Config> =
StorageValue<_, <T as frame_system::Config>::Hash, ValueQuery>; StorageValue<_, <T as frame_system::Config>::Hash, ValueQuery>;
/// Distance evaluation status by identity /// Pending evaluation requests
/// ///
/// * `.0` is the account who requested an evaluation and reserved the price, /// account who requested an evaluation and reserved the price,
/// for whom the price will be unreserved or slashed when the evaluation completes. /// for whom the price will be unreserved or slashed when the evaluation completes.
/// * `.1` is the status of the evaluation.
#[pallet::storage] #[pallet::storage]
#[pallet::getter(fn identity_distance_status)] #[pallet::getter(fn pending_evaluation_request)]
pub type IdentityDistanceStatus<T: Config> = StorageMap< pub type PendingEvaluationRequest<T: Config> = StorageMap<
_, _,
Twox64Concat, Twox64Concat,
<T as pallet_identity::Config>::IdtyIndex, <T as pallet_identity::Config>::IdtyIndex,
(<T as frame_system::Config>::AccountId, DistanceStatus), <T as frame_system::Config>::AccountId,
OptionQuery,
>;
/// Valid evaluation results
#[pallet::storage]
#[pallet::getter(fn valid_evaluation_result)]
pub type ValidEvaluationResult<T: Config> =
StorageMap<_, Twox64Concat, <T as pallet_identity::Config>::IdtyIndex, (), OptionQuery>;
/// Valid evaluation expiry blocks
#[pallet::storage]
#[pallet::getter(fn valid_evaluation_expire_on)]
pub type ValidEvaluationExpireOn<T: Config> = StorageMap<
_,
Twox64Concat,
u32,
Vec<<T as pallet_identity::Config>::IdtyIndex>,
OptionQuery, OptionQuery,
>; >;
...@@ -161,9 +180,9 @@ pub mod pallet { ...@@ -161,9 +180,9 @@ pub mod pallet {
idty_index: T::IdtyIndex, idty_index: T::IdtyIndex,
who: T::AccountId, who: T::AccountId,
}, },
/// A distance evaluation was updated. /// A distance evaluation was updated. // TODO refac
EvaluationUpdated { evaluator: T::AccountId }, EvaluationUpdated { evaluator: T::AccountId },
/// A distance status was forced. /// A distance status was forced. // TODO check if necessary to differenciate
EvaluationStatusForced { EvaluationStatusForced {
idty_index: T::IdtyIndex, idty_index: T::IdtyIndex,
status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>, status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>,
...@@ -183,7 +202,13 @@ pub mod pallet { ...@@ -183,7 +202,13 @@ pub mod pallet {
/// No author for this block. /// No author for this block.
NoAuthor, NoAuthor,
/// Caller has no identity. /// Caller has no identity.
NoIdentity, CallerHasNoIdentity,
/// Caller identity not found.
CallerIdentityNotFound,
/// Caller not member.
CallerNotMember,
/// Target identity not found.
TargetIdentityNotFound,
/// Evaluation queue is full. /// Evaluation queue is full.
QueueFull, QueueFull,
/// Too many evaluators in the current evaluation pool. /// Too many evaluators in the current evaluation pool.
...@@ -191,7 +216,10 @@ pub mod pallet { ...@@ -191,7 +216,10 @@ pub mod pallet {
/// Evaluation result has a wrong length. /// Evaluation result has a wrong length.
WrongResultLength, WrongResultLength,
/// Targeted distance evaluation request is only possible for an unvalidated identity /// Targeted distance evaluation request is only possible for an unvalidated identity
DistanceRequestNotAllowed, DistanceRequestOnlyAllowedForUnvalidated,
/// Can not request distance evaluation when a valid result has already been published recently
// (antispam)
ValidDistanceResultAlreadyAvailable,
} }
#[pallet::hooks] #[pallet::hooks]
...@@ -223,18 +251,9 @@ pub mod pallet { ...@@ -223,18 +251,9 @@ pub mod pallet {
pub fn request_distance_evaluation(origin: OriginFor<T>) -> DispatchResultWithPostInfo { pub fn request_distance_evaluation(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?; let who = ensure_signed(origin)?;
let idty = let idty = Self::check_request_distance_evaluation_self(&who)?;
pallet_identity::IdentityIndexOf::<T>::get(&who).ok_or(Error::<T>::NoIdentity)?;
// TODO is it necessary to check that the same account performed the request? Pallet::<T>::do_request_distance_evaluation(&who, idty)?;
// TODO what if the distance status is existing but valid?
ensure!(
IdentityDistanceStatus::<T>::get(idty)
!= Some((who.clone(), DistanceStatus::Pending)),
Error::<T>::AlreadyInEvaluation
);
Pallet::<T>::do_request_distance_evaluation(who, idty)?;
Ok(().into()) Ok(().into())
} }
...@@ -248,27 +267,9 @@ pub mod pallet { ...@@ -248,27 +267,9 @@ pub mod pallet {
) -> DispatchResultWithPostInfo { ) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?; let who = ensure_signed(origin)?;
// check that the caller has an identity (TODO is this necessary ?) Self::check_request_distance_evaluation_for(&who, target)?;
// 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 unvalidated
ensure!(
target_idty.status == pallet_identity::IdtyStatus::Unvalidated,
Error::<T>::DistanceRequestNotAllowed
);
// 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)?; Pallet::<T>::do_request_distance_evaluation(&who, target)?;
Ok(().into()) Ok(().into())
} }
...@@ -318,18 +319,13 @@ pub mod pallet { ...@@ -318,18 +319,13 @@ pub mod pallet {
/// * `status.1` is the status of the evaluation. /// * `status.1` is the status of the evaluation.
#[pallet::call_index(3)] #[pallet::call_index(3)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::force_set_distance_status())] #[pallet::weight(<T as pallet::Config>::WeightInfo::force_set_distance_status())]
pub fn force_set_distance_status( pub fn force_valid_distance_status(
origin: OriginFor<T>, origin: OriginFor<T>,
identity: <T as pallet_identity::Config>::IdtyIndex, identity: <T as pallet_identity::Config>::IdtyIndex,
status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>,
) -> DispatchResult { ) -> DispatchResult {
ensure_root(origin)?; ensure_root(origin)?;
Self::do_set_distance_status(identity, status.clone()); Self::do_valid_distance_status(identity);
Self::deposit_event(Event::EvaluationStatusForced {
idty_index: identity,
status,
});
Ok(()) Ok(())
} }
} }
...@@ -398,9 +394,74 @@ pub mod pallet { ...@@ -398,9 +394,74 @@ pub mod pallet {
} }
} }
/// check that request distance evaluation is allowed
fn check_request_distance_evaluation_self(
who: &T::AccountId,
) -> Result<<T as pallet_identity::Config>::IdtyIndex, DispatchError> {
// caller has an identity
let idty_index = pallet_identity::IdentityIndexOf::<T>::get(who)
.ok_or(Error::<T>::CallerHasNoIdentity)?;
// TODO some of the following can be moved to a "check idty call allowed" managed by wot
let idty = pallet_identity::Identities::<T>::get(idty_index)
.ok_or(Error::<T>::CallerIdentityNotFound)?;
// caller is member
ensure!(
idty.status == pallet_identity::IdtyStatus::NotMember
|| idty.status == pallet_identity::IdtyStatus::Member,
Error::<T>::CallerNotMember
);
Self::check_request_distance_evaluation_common(idty_index)?;
Ok(idty_index)
}
/// check that targeted request distance evaluation is allowed
fn check_request_distance_evaluation_for(
who: &T::AccountId,
target: <T as pallet_identity::Config>::IdtyIndex,
) -> Result<(), DispatchError> {
// caller has an identity
let caller_idty_index = pallet_identity::IdentityIndexOf::<T>::get(&who)
.ok_or(Error::<T>::CallerHasNoIdentity)?;
// TODO some of the following can be moved to a "check idty call allowed" managed by wot
let caller_idty = pallet_identity::Identities::<T>::get(caller_idty_index)
.ok_or(Error::<T>::CallerIdentityNotFound)?;
// caller is member
ensure!(
caller_idty.status == pallet_identity::IdtyStatus::Member,
Error::<T>::CallerNotMember
);
// target has an identity
let target_idty = pallet_identity::Identities::<T>::get(target)
.ok_or(Error::<T>::TargetIdentityNotFound)?;
// target is unvalidated
ensure!(
target_idty.status == pallet_identity::IdtyStatus::Unvalidated,
Error::<T>::DistanceRequestOnlyAllowedForUnvalidated
);
Self::check_request_distance_evaluation_common(target)?;
Ok(())
}
// common checks between check_request_distance_evaluation _self and _for
fn check_request_distance_evaluation_common(
target: <T as pallet_identity::Config>::IdtyIndex,
) -> Result<(), DispatchError> {
// no pending evaluation request
ensure!(
PendingEvaluationRequest::<T>::get(target).is_none(),
Error::<T>::AlreadyInEvaluation
);
// no valid status (antispam)
ensure!(
ValidEvaluationResult::<T>::get(target).is_none(),
Error::<T>::ValidDistanceResultAlreadyAvailable
);
Ok(())
}
/// request distance evaluation in current pool /// 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,
) -> Result<(), DispatchError> { ) -> Result<(), DispatchError> {
Pallet::<T>::mutate_current_pool( Pallet::<T>::mutate_current_pool(
...@@ -411,19 +472,19 @@ pub mod pallet { ...@@ -411,19 +472,19 @@ pub mod pallet {
Error::<T>::QueueFull Error::<T>::QueueFull
); );
T::Currency::reserve(&who, <T as Config>::EvaluationPrice::get())?; T::Currency::reserve(who, <T as Config>::EvaluationPrice::get())?;
current_pool current_pool
.evaluations .evaluations
.try_push((idty_index, median::MedianAcc::new())) .try_push((idty_index, median::MedianAcc::new()))
.map_err(|_| Error::<T>::QueueFull)?; .map_err(|_| Error::<T>::QueueFull)?;
IdentityDistanceStatus::<T>::insert( PendingEvaluationRequest::<T>::insert(idty_index, who);
idty_index,
(&who, DistanceStatus::Pending),
);
Self::deposit_event(Event::EvaluationRequested { idty_index, who }); Self::deposit_event(Event::EvaluationRequested {
idty_index,
who: who.clone(),
});
Ok(()) Ok(())
}, },
) )
...@@ -466,14 +527,17 @@ pub mod pallet { ...@@ -466,14 +527,17 @@ pub mod pallet {
} }
/// Set the distance status using IdtyIndex and AccountId /// Set the distance status using IdtyIndex and AccountId
pub fn do_set_distance_status( pub fn do_valid_distance_status(idty: <T as pallet_identity::Config>::IdtyIndex) {
identity: <T as pallet_identity::Config>::IdtyIndex, // expiration session index
status: Option<(<T as frame_system::Config>::AccountId, DistanceStatus)>, let expire_on =
) { pallet_session::Pallet::<T>::current_index() + T::ResultExpiration::get();
IdentityDistanceStatus::<T>::set(identity, status.clone()); // index valid result
if let Some((_, DistanceStatus::Valid)) = status { ValidEvaluationResult::<T>::set(idty, Some(()));
T::OnValidDistanceStatus::on_valid_distance_status(identity); // schedule expiry
} ValidEvaluationExpireOn::<T>::append(expire_on, idty);
// callback
T::OnValidDistanceStatus::on_valid_distance_status(idty);
// TODO event
} }
} }
...@@ -495,42 +559,37 @@ pub mod pallet { ...@@ -495,42 +559,37 @@ pub mod pallet {
MedianResult::One(m) => m, MedianResult::One(m) => m,
MedianResult::Two(m1, m2) => m1 + (m2 - m1) / 2, // Avoid overflow (since max is 1) MedianResult::Two(m1, m2) => m1 + (m2 - m1) / 2, // Avoid overflow (since max is 1)
}; };
// flag to capture distance status // distance status criterion
let is_distance_status_valid = median >= T::MinAccessibleReferees::get(); let is_distance_status_valid = median >= T::MinAccessibleReferees::get();
// mutate the distance status accordingly
IdentityDistanceStatus::<T>::mutate(idty, |entry| { // take requester and perform unreserve or slash
if let Some((account_id, status)) = entry.as_mut() { if let Some(requester) = PendingEvaluationRequest::<T>::take(idty) {
// result is ok if is_distance_status_valid {
if is_distance_status_valid { T::Currency::unreserve(
// unreserve price &requester,
T::Currency::unreserve( <T as Config>::EvaluationPrice::get(),
account_id, );
<T as Config>::EvaluationPrice::get(), } else {
); T::Currency::slash_reserved(
// update distance status &requester,
*status = DistanceStatus::Valid; <T as Config>::EvaluationPrice::get(),
} );
// result is ko }
else { }
// slash requester // if evaluation happened without request, it's ok to do nothing
T::Currency::slash_reserved(
account_id, // if evaluation is positive, remember it for antispam
<T as Config>::EvaluationPrice::get(), // and perform callbacks
);
// update distance status
*status = DistanceStatus::Invalid;
}
} // each entry should be Some((_, DistanceStatus::Pending))
});
// consequences of valid status
if is_distance_status_valid { if is_distance_status_valid {
T::OnValidDistanceStatus::on_valid_distance_status(idty); Self::do_valid_distance_status(idty);
} else {
// TODO event
} }
} else if let Some((account_id, _status)) = IdentityDistanceStatus::<T>::take(idty) }
{ // when no result is published, all funds are unreserved
// when no result is published, all funds are unreserved else if let Some(requester) = PendingEvaluationRequest::<T>::take(idty) {
<T as Config>::Currency::unreserve( <T as Config>::Currency::unreserve(
&account_id, &requester,
<T as Config>::EvaluationPrice::get(), <T as Config>::EvaluationPrice::get(),
); );
} }
......
...@@ -118,13 +118,12 @@ where ...@@ -118,13 +118,12 @@ where
fn is_distance_ok( fn is_distance_ok(
idty_id: &<T as pallet_identity::Config>::IdtyIndex, idty_id: &<T as pallet_identity::Config>::IdtyIndex,
) -> Result<(), DispatchError> { ) -> Result<(), DispatchError> {
match pallet_distance::Pallet::<T>::identity_distance_status(idty_id) { match pallet_distance::Pallet::<T>::valid_evaluation_result(idty_id) {
Some((_, status)) => match status { Some(()) => Ok(()),
pallet_distance::DistanceStatus::Valid => Ok(()), None => match pallet_distance::Pallet::<T>::pending_evaluation_request(idty_id) {
pallet_distance::DistanceStatus::Invalid => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceIsInvalid.into()), Some(_) => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationPending.into()),
pallet_distance::DistanceStatus::Pending => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationPending.into()), None => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationNotRequested.into()),
}, }
None => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationNotRequested.into()),
} }
} }
} }
...@@ -146,9 +145,8 @@ macro_rules! impl_benchmark_setup_handler { ...@@ -146,9 +145,8 @@ macro_rules! impl_benchmark_setup_handler {
idty_id: &IdtyIndex, idty_id: &IdtyIndex,
account: &<T as frame_system::Config>::AccountId, account: &<T as frame_system::Config>::AccountId,
) -> () { ) -> () {
let _ = pallet_distance::Pallet::<T>::do_set_distance_status( let _ = pallet_distance::Pallet::<T>::do_valid_distance_status(
*idty_id, *idty_id
Some((account.clone(), pallet_distance::DistanceStatus::Valid)),
); );
} }
fn add_cert(issuer: &IdtyIndex, receiver: &IdtyIndex) { fn add_cert(issuer: &IdtyIndex, receiver: &IdtyIndex) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment