Skip to content
Snippets Groups Projects
Commit a795c0e7 authored by Pascal Engélibert's avatar Pascal Engélibert :bicyclist:
Browse files

feat(identity): revoke_identity

parent b85e3528
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !12. Comments created here will be created in the context of that merge request.
...@@ -36,7 +36,7 @@ use crate::traits::*; ...@@ -36,7 +36,7 @@ use crate::traits::*;
use codec::Codec; use codec::Codec;
use frame_support::dispatch::Weight; use frame_support::dispatch::Weight;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use sp_runtime::traits::{AtLeast32BitUnsigned, One, Saturating, Zero}; use sp_runtime::traits::{AtLeast32BitUnsigned, IdentifyAccount, One, Saturating, Zero};
use sp_std::fmt::Debug; use sp_std::fmt::Debug;
use sp_std::prelude::*; use sp_std::prelude::*;
...@@ -47,6 +47,7 @@ pub mod pallet { ...@@ -47,6 +47,7 @@ pub mod pallet {
use frame_support::traits::StorageVersion; use frame_support::traits::StorageVersion;
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
use sp_membership::traits::MembershipAction as _; use sp_membership::traits::MembershipAction as _;
use sp_runtime::traits::Verify;
/// The current storage version. /// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
...@@ -102,6 +103,10 @@ pub mod pallet { ...@@ -102,6 +103,10 @@ pub mod pallet {
type MaxNoRightPeriod: Get<Self::BlockNumber>; type MaxNoRightPeriod: Get<Self::BlockNumber>;
/// ///
type Membership: sp_membership::traits::MembershipAction<Self::IdtyIndex, Self::Origin>; type Membership: sp_membership::traits::MembershipAction<Self::IdtyIndex, Self::Origin>;
/// Signing key of revocation payload
type RevocationSigner: IdentifyAccount<AccountId = Self::AccountId>;
/// Signature of revocation payload
type RevocationSignature: Parameter + Verify<Signer = Self::RevocationSigner>;
} }
// GENESIS STUFF // // GENESIS STUFF //
...@@ -510,15 +515,13 @@ pub mod pallet { ...@@ -510,15 +515,13 @@ pub mod pallet {
.rights .rights
.binary_search_by(|(right_, _)| right_.cmp(&right)) .binary_search_by(|(right_, _)| right_.cmp(&right))
{ {
let name = idty_value.name.clone(); <Pallet<T>>::do_del_right(
let old_key_opt = if let Some(ref subkey) = idty_value.rights[index].1 { idty_index,
Some(subkey.clone()) idty_value.name.clone(),
} else if right.allow_owner_key() { &idty_value.owner_key,
Some(idty_value.owner_key.clone()) right,
} else { idty_value.rights.remove(index).1,
None );
};
idty_value.rights.remove(index);
if idty_value.rights.is_empty() { if idty_value.rights.is_empty() {
let block_number = frame_system::pallet::Pallet::<T>::block_number(); let block_number = frame_system::pallet::Pallet::<T>::block_number();
...@@ -531,15 +534,6 @@ pub mod pallet { ...@@ -531,15 +534,6 @@ pub mod pallet {
} }
<Identities<T>>::insert(idty_index, idty_value); <Identities<T>>::insert(idty_index, idty_value);
Self::deposit_event(Event::<T>::IdtyLostRight(name, right));
if old_key_opt.is_some() {
T::OnRightKeyChange::on_right_key_change(
idty_index,
right,
old_key_opt,
None,
);
}
Ok(().into()) Ok(().into())
} else { } else {
Err(Error::<T>::RightNotExist.into()) Err(Error::<T>::RightNotExist.into())
...@@ -549,6 +543,55 @@ pub mod pallet { ...@@ -549,6 +543,55 @@ pub mod pallet {
} }
} }
#[pallet::weight(0)] #[pallet::weight(0)]
pub fn revoke_identity(
origin: OriginFor<T>,
payload: RevocationPayload<T::AccountId, T::IdtyIndex, T::Hash>,
payload_sig: T::RevocationSignature,
) -> DispatchResultWithPostInfo {
let _ = ensure_signed(origin)?;
if payload.genesis_hash != frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero())
{
return Err(Error::<T>::BadGenesisHash.into());
}
if !payload.using_encoded(|bytes| payload_sig.verify(bytes, &payload.owner_key)) {
return Err(Error::<T>::BadProof.into());
}
let idty_index = payload.idty;
if let Ok(mut idty_value) = <Identities<T>>::try_get(idty_index) {
if idty_value.owner_key != payload.owner_key {
return Err(Error::<T>::RequireToBeOwner.into());
}
if idty_value.status != IdtyStatus::Validated {
return Err(Error::<T>::IdtyNotValidated.into());
}
let idty_name = idty_value.name.clone();
idty_value.rights.drain(..).for_each(|(right, subkey_opt)| {
<Pallet<T>>::do_del_right(
idty_index,
idty_name.clone(),
&payload.owner_key,
right,
subkey_opt,
)
});
let block_number = frame_system::pallet::Pallet::<T>::block_number();
let removable_on = block_number + T::MaxNoRightPeriod::get();
idty_value.removable_on = removable_on;
<IdentitiesRemovableOn<T>>::append(
removable_on,
(idty_index, IdtyStatus::Validated),
);
<Identities<T>>::insert(idty_index, idty_value);
Ok(().into())
} else {
Err(Error::<T>::IdtyNotFound.into())
}
}
#[pallet::weight(0)]
pub fn set_right_subkey( pub fn set_right_subkey(
origin: OriginFor<T>, origin: OriginFor<T>,
idty_index: T::IdtyIndex, idty_index: T::IdtyIndex,
...@@ -608,6 +651,10 @@ pub mod pallet { ...@@ -608,6 +651,10 @@ pub mod pallet {
#[pallet::error] #[pallet::error]
pub enum Error<T> { pub enum Error<T> {
/// Genesis hash does not match
BadGenesisHash,
/// Signature is invalid
BadProof,
/// Creator not exist /// Creator not exist
CreatorNotExist, CreatorNotExist,
/// Creator not allowed to create identities /// Creator not allowed to create identities
...@@ -727,6 +774,26 @@ pub mod pallet { ...@@ -727,6 +774,26 @@ pub mod pallet {
total_weight total_weight
} }
pub(super) fn do_del_right(
idty_index: T::IdtyIndex,
idty_name: IdtyName,
owner_key: &T::AccountId,
right: T::IdtyRight,
subkey_opt: Option<T::AccountId>,
) {
let old_key_opt = if let Some(ref subkey) = subkey_opt {
Some(subkey.clone())
} else if right.allow_owner_key() {
Some(owner_key.clone())
} else {
None
};
Self::deposit_event(Event::<T>::IdtyLostRight(idty_name, right));
if old_key_opt.is_some() {
T::OnRightKeyChange::on_right_key_change(idty_index, right, old_key_opt, None);
}
}
} }
} }
......
...@@ -27,7 +27,7 @@ use scale_info::TypeInfo; ...@@ -27,7 +27,7 @@ use scale_info::TypeInfo;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sp_core::H256; use sp_core::H256;
use sp_runtime::{ use sp_runtime::{
testing::Header, testing::{Header, TestSignature, UintAuthorityId},
traits::{BlakeTwo256, IdentityLookup}, traits::{BlakeTwo256, IdentityLookup},
BuildStorage, BuildStorage,
}; };
...@@ -145,6 +145,8 @@ impl pallet_identity::Config for Test { ...@@ -145,6 +145,8 @@ impl pallet_identity::Config for Test {
type OnRightKeyChange = (); type OnRightKeyChange = ();
type MaxNoRightPeriod = MaxNoRightPeriod; type MaxNoRightPeriod = MaxNoRightPeriod;
type Membership = (); type Membership = ();
type RevocationSigner = UintAuthorityId;
type RevocationSignature = TestSignature;
} }
// Build genesis storage according to the mock runtime. // Build genesis storage according to the mock runtime.
......
...@@ -19,7 +19,9 @@ use crate::mock::*; ...@@ -19,7 +19,9 @@ use crate::mock::*;
use crate::{Error, IdtyName, IdtyValue}; use crate::{Error, IdtyName, IdtyValue};
use frame_support::assert_err; use frame_support::assert_err;
use frame_support::assert_ok; use frame_support::assert_ok;
use frame_support::pallet_prelude::Encode;
use frame_system::{EventRecord, Phase}; use frame_system::{EventRecord, Phase};
use sp_runtime::testing::TestSignature;
type IdtyVal = IdtyValue<u64, u64, (), Right>; type IdtyVal = IdtyValue<u64, u64, (), Right>;
...@@ -247,3 +249,67 @@ fn test_two_identities() { ...@@ -247,3 +249,67 @@ fn test_two_identities() {
assert_eq!(idty2.removable_on, 7); assert_eq!(idty2.removable_on, 7);
}); });
} }
#[test]
fn test_revoke_identity_ok() {
let identities = vec![crate::IdtyValue {
name: IdtyName(vec![0]),
owner_key: 1,
next_creatable_identity_on: 0,
removable_on: 0,
rights: vec![(Right::Right1, None), (Right::Right2, Some(10))],
status: crate::IdtyStatus::Validated,
data: (),
}];
new_test_ext(IdentityConfig { identities }).execute_with(|| {
// Should have one identity
assert_eq!(Identity::identities_count(), 1);
// We need to initialize at least one block before any call
run_to_block(1);
let revocation_payload = crate::RevocationPayload {
owner_key: 1,
idty: 1,
genesis_hash: System::block_hash(0),
};
let revocation_signature = TestSignature(1, revocation_payload.encode());
// Delete right Right1 for IdtyName(vec![1])
// Should succes and trigger the correct event
assert_ok!(Identity::revoke_identity(
Origin::signed(2),
revocation_payload,
revocation_signature
));
let events = System::events();
assert_eq!(events.len(), 2);
assert_eq!(
events[0],
EventRecord {
phase: Phase::Initialization,
event: Event::Identity(crate::Event::IdtyLostRight(
IdtyName(vec![0]),
Right::Right1
)),
topics: vec![],
}
);
assert_eq!(
events[1],
EventRecord {
phase: Phase::Initialization,
event: Event::Identity(crate::Event::IdtyLostRight(
IdtyName(vec![0]),
Right::Right2
)),
topics: vec![],
}
);
// The identity has no more rights, the inactivity period must start to run
let idty = Identity::identity(1).expect("idty not found");
assert!(idty.rights.is_empty());
assert_eq!(idty.removable_on, 5);
});
}
...@@ -113,3 +113,11 @@ where ...@@ -113,3 +113,11 @@ where
} }
} }
} }
#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)]
pub struct RevocationPayload<AccountId, IdtyIndex: Decode + Encode + TypeInfo, Hash> {
pub owner_key: AccountId,
pub idty: IdtyIndex,
// Avoid replay attack between blockchains
pub genesis_hash: Hash,
}
...@@ -201,6 +201,8 @@ macro_rules! pallets_config { ...@@ -201,6 +201,8 @@ macro_rules! pallets_config {
type OnRightKeyChange = OnRightKeyChangeHandler<Runtime>; type OnRightKeyChange = OnRightKeyChangeHandler<Runtime>;
type MaxNoRightPeriod = MaxNoRightPeriod; type MaxNoRightPeriod = MaxNoRightPeriod;
type Membership = Membership; type Membership = Membership;
type RevocationSigner = <Signature as sp_runtime::traits::Verify>::Signer;
type RevocationSignature = Signature;
} }
impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime { impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
......
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