diff --git a/Cargo.lock b/Cargo.lock index c06dcf48392e187fa4869af3cfe7f56968d8dea3..bbedc15e66b4abc0133c32d9704866348e986eda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6298,6 +6298,7 @@ dependencies = [ "maplit", "pallet-authority-members", "pallet-balances", + "pallet-identity", "parity-scale-codec", "scale-info", "serde", diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs index 20120f25c68a99791db7ca3ef76b2d0b26ad0b97..f8bff333c804b2a17f0152703ea267861d45cc0e 100644 --- a/pallets/identity/src/types.rs +++ b/pallets/identity/src/types.rs @@ -38,6 +38,7 @@ pub enum IdtyEvent<T: crate::Config> { /// removing an identity (unvalidated or revoked) // pallet wot removes associated certifications if status is not revoked // pallet quota removes associated quota + // pallet smith-members exclude smith Removed { status: IdtyStatus }, // TODO add a way to unlink accounts corresponding to revoked or removed identities } diff --git a/pallets/smith-members/Cargo.toml b/pallets/smith-members/Cargo.toml index 7d09d7dffc06b3dcf433c2d59cd9c6e7924a706d..5ee739b1ecbd8e3c3867d4818d1b9a74e31883dc 100644 --- a/pallets/smith-members/Cargo.toml +++ b/pallets/smith-members/Cargo.toml @@ -18,6 +18,7 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.101", default-features = false, optional = true } pallet-authority-members = { path = "../authority-members", default-features = false } +pallet-identity = { path = "../identity", default-features = false } frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } pallet-balances = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } diff --git a/pallets/smith-members/src/impls.rs b/pallets/smith-members/src/impls.rs index c3417028b21f708b59dbc39e2c43076e9bcfad4f..1fd68c58f869c03d84fd42f2f9f508166fb7589a 100644 --- a/pallets/smith-members/src/impls.rs +++ b/pallets/smith-members/src/impls.rs @@ -1,5 +1,7 @@ use crate::{Config, CurrentSession, Pallet}; +use frame_support::Parameter; use pallet_authority_members::SessionIndex; +use pallet_identity::IdtyEvent; use sp_runtime::traits::Convert; /// We want to remove a Smith when he is removed from the higher level set of "authorities". @@ -47,3 +49,20 @@ impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> { Pallet::<T>::do_exclude_expired_smiths(index); } } + +// implement identity event handler +impl< + IdtyIndex: Copy + Parameter, + T: Config<IdtyIndex = IdtyIndex> + pallet_identity::Config<IdtyIndex = IdtyIndex>, + > pallet_identity::traits::OnIdtyChange<T> for Pallet<T> +{ + fn on_idty_change(idty_id: IdtyIndex, idty_event: &IdtyEvent<T>) { + match idty_event { + // initialize quota on identity creation + IdtyEvent::Created { .. } => {} + IdtyEvent::Removed { .. } => { + Pallet::<T>::do_exclude_removed_wot_member(idty_id); + } + } + } +} diff --git a/pallets/smith-members/src/lib.rs b/pallets/smith-members/src/lib.rs index 90882404d63c7c417842fb012659dbc67a09f3c2..0bffb76319a755133a94aa05f04c32097c0586f1 100644 --- a/pallets/smith-members/src/lib.rs +++ b/pallets/smith-members/src/lib.rs @@ -444,36 +444,7 @@ impl<T: Config> Pallet<T> { if let Some(smith_meta) = Smiths::<T>::get(smith) { if let Some(expires_on) = smith_meta.expires_on { if expires_on == at { - let mut lost_certs = vec![]; - Smiths::<T>::mutate(smith, |maybe_smith_meta| { - let maybe_smith_meta = - maybe_smith_meta.as_mut().expect("checked earlier"); - maybe_smith_meta.expires_on = None; - maybe_smith_meta.status = SmithStatus::Excluded; - for cert in &maybe_smith_meta.received_certs { - lost_certs.push(*cert); - } - maybe_smith_meta.received_certs = vec![]; - // N.B.: the issued certs are kept in case the smith joins back - }); - // We remove the lost certs from their issuer's stock - for lost_cert in lost_certs { - Smiths::<T>::mutate(lost_cert, |maybe_smith_meta| { - let maybe_smith_meta = - maybe_smith_meta.as_mut().expect("checked earlier"); - if let Ok(index) = - maybe_smith_meta.issued_certs.binary_search(&smith) - { - maybe_smith_meta.issued_certs.remove(index); - } - }); - } - // Deletion done - T::OnSmithDelete::on_smith_delete( - smith, - SmithRemovalReason::OfflineTooLong, - ); - Self::deposit_event(Event::<T>::SmithExcluded { idty_index: smith }); + Self::do_exclude_smith(smith, SmithRemovalReason::OfflineTooLong); } } } @@ -481,6 +452,36 @@ impl<T: Config> Pallet<T> { } } + fn do_exclude_removed_wot_member(idty_index: T::IdtyIndex) { + Self::do_exclude_smith(idty_index, SmithRemovalReason::LostMembership); + } + + fn do_exclude_smith(idty_index: T::IdtyIndex, reason: SmithRemovalReason) { + let mut lost_certs = vec![]; + Smiths::<T>::mutate(idty_index, |maybe_smith_meta| { + let maybe_smith_meta = maybe_smith_meta.as_mut().expect("checked earlier"); + maybe_smith_meta.expires_on = None; + maybe_smith_meta.status = SmithStatus::Excluded; + for cert in &maybe_smith_meta.received_certs { + lost_certs.push(*cert); + } + maybe_smith_meta.received_certs = vec![]; + // N.B.: the issued certs are kept in case the smith joins back + }); + // We remove the lost certs from their issuer's stock + for lost_cert in lost_certs { + Smiths::<T>::mutate(lost_cert, |maybe_smith_meta| { + let maybe_smith_meta = maybe_smith_meta.as_mut().expect("checked earlier"); + if let Ok(index) = maybe_smith_meta.issued_certs.binary_search(&idty_index) { + maybe_smith_meta.issued_certs.remove(index); + } + }); + } + // Deletion done: notify (authority-members) for cascading + T::OnSmithDelete::on_smith_delete(idty_index, reason); + Self::deposit_event(Event::<T>::SmithExcluded { idty_index }); + } + // TODO: return what? fn smith_goes_online(idty_index: T::IdtyIndex) { if let Some(smith_meta) = Smiths::<T>::get(idty_index) { diff --git a/pallets/smith-members/src/tests.rs b/pallets/smith-members/src/tests.rs index caed26b8c17f009badcfa2126d6ebcb1bb2b92f7..405015f2b76bdd38f4a59c6117a27c49faa01285 100644 --- a/pallets/smith-members/src/tests.rs +++ b/pallets/smith-members/src/tests.rs @@ -486,3 +486,73 @@ fn invitation_on_non_wot_member() { ); }); } + +#[test] +fn losing_wot_membership_cascades_to_smith_members() { + new_test_ext(GenesisConfig { + certs_by_receiver: btreemap![ + 1 => vec![2, 3, 4], + 2 => vec![3, 4], + 3 => vec![1, 2], + 4 => vec![], + ], + }) + .execute_with(|| { + // State before + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: Smith, + expires_on: Some(5), + issued_certs: vec![3], + received_certs: vec![2, 3, 4], + }) + ); + assert_eq!( + Smiths::<Runtime>::get(1).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(2).unwrap().issued_certs, + Vec::<u64>::from([1, 3]) + ); + assert_eq!( + Smiths::<Runtime>::get(3).unwrap().issued_certs, + Vec::<u64>::from([1, 2]) + ); + assert_eq!( + Smiths::<Runtime>::get(4).unwrap().issued_certs, + Vec::<u64>::from([1, 2]) + ); + + Pallet::<Runtime>::do_exclude_removed_wot_member(1); + + // Excluded + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: Excluded, + expires_on: None, + issued_certs: vec![3], + received_certs: vec![], + }) + ); + // Issued certifications updated for certifiers of 1 + assert_eq!( + Smiths::<Runtime>::get(1).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(2).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(3).unwrap().issued_certs, + Vec::<u64>::from([2]) + ); + assert_eq!( + Smiths::<Runtime>::get(4).unwrap().issued_certs, + Vec::<u64>::from([2]) + ); + }); +}