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
...@@ -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