diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs index 50a41c70b5184d96a8fa1598b958a80cfb32aad1..d897b0f3df905633f2ce51538bb13080a36e922b 100644 --- a/pallets/duniter-wot/src/lib.rs +++ b/pallets/duniter-wot/src/lib.rs @@ -365,21 +365,12 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI if receiver_received_count < T::MinCertForMembership::get() && pallet_membership::Pallet::<T, I>::is_member(&receiver) { - if T::IsSubWot::get() { - // expire receiver membership - // it gives him a bit of time to get back enough certs - if let Err(e) = <pallet_membership::Pallet<T, I>>::force_expire_membership(receiver) - { - sp_std::if_std! { - println!("fail to expire membership: {:?}", e) - } + // expire receiver membership + // it gives him a bit of time to get back enough certs + if let Err(e) = <pallet_membership::Pallet<T, I>>::force_expire_membership(receiver) { + sp_std::if_std! { + println!("fail to expire membership: {:?}", e) } - } else { - // Revoke receiver membership and disable his identity - Self::dispath_idty_call(pallet_identity::Call::remove_identity { - idty_index: receiver, - idty_name: None, - }); } } Weight::zero() diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs index a2e645a13ad0d224feb9537529ef129737d0f657..af88fd49cb3376f779812dd6f6d7d61044837f9a 100644 --- a/pallets/duniter-wot/src/mock.rs +++ b/pallets/duniter-wot/src/mock.rs @@ -322,6 +322,7 @@ pub fn new_test_ext( pub fn run_to_block(n: u64) { while System::block_number() < n { + // finalize previous block DuniterWot::on_finalize(System::block_number()); Identity::on_finalize(System::block_number()); Membership::on_finalize(System::block_number()); @@ -330,8 +331,10 @@ pub fn run_to_block(n: u64) { SmithMembership::on_finalize(System::block_number()); SmithCert::on_finalize(System::block_number()); System::on_finalize(System::block_number()); + // reset events and change block number System::reset_events(); System::set_block_number(System::block_number() + 1); + // initialize next block System::on_initialize(System::block_number()); DuniterWot::on_initialize(System::block_number()); Identity::on_initialize(System::block_number()); diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs index 7f98d970f7f134e5207d1ecbe1771c8ec39c4640..bade3ace78e5bde08f51c734d77da857bf3fdf58 100644 --- a/pallets/duniter-wot/src/tests.rs +++ b/pallets/duniter-wot/src/tests.rs @@ -26,6 +26,8 @@ use pallet_identity::{ }; use sp_runtime::testing::TestSignature; +/// test that genesis builder creates the good number of identities +/// and good identity and certification metadate #[test] fn test_genesis_build() { new_test_ext(3, 2).execute_with(|| { @@ -40,14 +42,15 @@ fn test_genesis_build() { }); } +/// test that Alice is not able to create an identity when she received too few certs (2 of 4) #[test] fn test_creator_not_allowed_to_create_idty() { new_test_ext(3, 2).execute_with(|| { run_to_block(1); - // Alice should not be able to create an identity before block #2 - // because Alice.next_issuable_on = 2 - // but the true reason is that alice did not receive enough certs + // Alice did not receive enough certs + // (anyway Alice should not be able to create an identity before block #2 + // because Alice.next_issuable_on = 2) assert_noop!( Identity::create_identity(RuntimeOrigin::signed(1), 4), pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty @@ -55,6 +58,20 @@ fn test_creator_not_allowed_to_create_idty() { }); } +/// test that Alice is able to create an identity when she received enough certs (4) +#[test] +fn test_creator_allowed_to_create_idty() { + new_test_ext(5, 2).execute_with(|| { + run_to_block(2); + + // Alice should be able to create an identity + assert_ok!( + Identity::create_identity(RuntimeOrigin::signed(1), 6), + // pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty + ); + }); +} + /// test smith joining workflow #[test] fn test_join_smiths() { @@ -232,6 +249,7 @@ fn test_new_idty_validation() { }); } +/// test that Ferdie can confirm an identity created for him by Alice #[test] fn test_confirm_idty_ok() { new_test_ext(5, 2).execute_with(|| { @@ -260,6 +278,9 @@ fn test_confirm_idty_ok() { }); } +/// test identity revocation +/// - a smith ca not revoke his identity +/// - anyone can submit a revocation certificate signed by bob #[test] fn test_revoke_idty() { new_test_ext(5, 1).execute_with(|| { @@ -310,7 +331,7 @@ fn test_revoke_idty() { }); } -/// test that expired membership lose the identity and can not be certified +/// test that expired membership lose the identity after a delay #[test] fn test_idty_membership_expire() { new_test_ext(3, 2).execute_with(|| { @@ -354,6 +375,7 @@ fn test_idty_membership_expire() { }); } +/// when an identity is confirmed and not validated, the certification received should be removed #[test] fn test_unvalidated_idty_certs_removal() { new_test_ext(5, 2).execute_with(|| { @@ -375,3 +397,104 @@ fn test_unvalidated_idty_certs_removal() { assert_eq!(Cert::certs_by_receiver(6).len(), 0); }); } + +/// test what happens when certification expire +#[test] +fn test_certification_expire() { + new_test_ext(3, 3).execute_with(|| { + // smith cert Bob → Alice not renewed + // cert Bob → Alice not renewed + // --- BLOCK 2 --- + run_to_block(2); + assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2)); + assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 3)); + assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); + assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 2)); + assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 3)); + assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 1)); + // --- BLOCK 4 --- + run_to_block(4); + assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 3)); + assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 2)); + assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 3)); + assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 2)); + // --- BLOCK 7 --- + run_to_block(7); + assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(1))); + assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(2))); + assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(3))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); + + // smith cert Bob → Alice expires at block 10 + run_to_block(10); + // println!("{:?}", System::events()); + System::assert_has_event(RuntimeEvent::SmithCert( + pallet_certification::Event::RemovedCert { + issuer: 2, // Bob + issuer_issued_count: 1, // Bob → Charlie only + receiver: 1, // Alice + receiver_received_count: 1, // Charlie → Alice only + expiration: true, + }, + )); + // in consequence, since Alice has only 1/2 smith certification remaining, she looses smith membership + System::assert_has_event(RuntimeEvent::SmithMembership( + pallet_membership::Event::MembershipExpired(1), + )); + + // --- BLOCK 14 --- + run_to_block(14); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); + + // normal cert Bob → Alice expires at block 20 + run_to_block(20); + // println!("{:?}", System::events()); + System::assert_has_event(RuntimeEvent::Cert( + pallet_certification::Event::RemovedCert { + issuer: 2, // Bob + issuer_issued_count: 1, // Bob → Charlie + receiver: 1, // Alice + receiver_received_count: 1, // Charlie → Alice + expiration: true, + }, + )); + // in consequence, since Alice has only 1/2 normal certification remaining, she looses normal membership + System::assert_has_event(RuntimeEvent::Membership( + pallet_membership::Event::MembershipExpired(1), + )); + + // --- BLOCK 21 --- + // Bob and Charlie can renew their membership + run_to_block(21); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); + assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); + + // Alice can not renew her membership which does not exist because it is pending + assert_noop!( + Membership::renew_membership(RuntimeOrigin::signed(1)), + pallet_membership::Error::<Test, Instance1>::MembershipNotFound + ); + + // Alice can not claim her membership because she does not have enough certifications + assert_noop!( + Membership::claim_membership(RuntimeOrigin::signed(1)), + pallet_duniter_wot::Error::<Test, Instance1>::IdtyNotAllowedToClaimMembership + ); + + // --- BLOCK 23 --- + run_to_block(23); + // println!("{:?}", System::events()); + // after a delay (3 blocks), the pending membership finally expires + System::assert_has_event(RuntimeEvent::Membership( + pallet_membership::Event::PendingMembershipExpired(1), + )); + // and the identity is removed + System::assert_has_event(RuntimeEvent::Identity( + pallet_identity::Event::IdtyRemoved { idty_index: 1 }, + )); + }) +}