From d7cefb5922e659978672b59bcc65e13a2d6ff412 Mon Sep 17 00:00:00 2001 From: Benjamin Gallois <business@gallois.cc> Date: Tue, 27 Feb 2024 17:22:20 +0100 Subject: [PATCH] Fix live tests (nodes/rust/duniter-v2s!248) * fix live-tests * add live tests for identity status coherence * collect membership storage --- live-tests/tests/sanity_gdev.rs | 133 ++++++++++++++++++++++++++++---- 1 file changed, 120 insertions(+), 13 deletions(-) diff --git a/live-tests/tests/sanity_gdev.rs b/live-tests/tests/sanity_gdev.rs index 86cec2524..d2f8f0915 100644 --- a/live-tests/tests/sanity_gdev.rs +++ b/live-tests/tests/sanity_gdev.rs @@ -22,7 +22,6 @@ pub mod gdev {} use countmap::CountMap; -use hex_literal::hex; use sp_core::crypto::AccountId32; use sp_core::{blake2_128, ByteArray, H256}; use std::collections::{HashMap, HashSet}; @@ -37,8 +36,9 @@ use subxt::ext::sp_core; const DEFAULT_ENDPOINT: &str = "ws://localhost:9944"; const EXISTENTIAL_DEPOSIT: u64 = 100; -const TREASURY_ACCOUNT_ID: [u8; 32] = - hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); +//use hex_literal::hex; +//const TREASURY_ACCOUNT_ID: [u8; 32] = +// hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); type Client = subxt::OnlineClient<GdevConfig>; @@ -56,12 +56,16 @@ type IdtyData = gdev::runtime_types::common_runtime::entities::IdtyData; type IdtyIndex = u32; type IdtyValue = gdev::runtime_types::pallet_identity::types::IdtyValue<BlockNumber, AccountId32, IdtyData>; -// use gdev::runtime_types::pallet_identity::types::IdtyStatus; +type MembershipData = gdev::runtime_types::sp_membership::MembershipData<BlockNumber>; +use gdev::runtime_types::pallet_identity::types::IdtyName; +use gdev::runtime_types::pallet_identity::types::IdtyStatus; struct Storage { accounts: HashMap<AccountId32, AccountInfo>, identities: HashMap<IdtyIndex, IdtyValue>, identity_index_of: HashMap<[u8; 16], IdtyIndex>, + memberships: HashMap<IdtyIndex, MembershipData>, + identities_names: HashMap<IdtyIndex, IdtyName>, } #[tokio::test(flavor = "current_thread")] @@ -146,10 +150,46 @@ async fn sanity_tests_at(client: Client, _maybe_block_hash: Option<H256>) -> any } println!("identity_index_of.len(): {}.", identity_index_of.len()); + // Collect identity_names + let mut identities_names: HashMap<IdtyIndex, IdtyName> = HashMap::new(); + let mut idty_name_iter = client + .storage() + .at_latest() + .await + .unwrap() + .iter(gdev::storage().identity().identities_names_iter()) + .await?; + while let Some(Ok((key, idty_index))) = idty_name_iter.next().await { + let name = IdtyName(key); + identities_names.insert(idty_index, name); + } + println!("identities_names.len(): {}.", identities_names.len()); + + // Collect memberships + let mut memberships: HashMap<IdtyIndex, MembershipData> = HashMap::new(); + let mut membership_iter = client + .storage() + .at_latest() + .await + .unwrap() + .iter(gdev::storage().membership().membership_iter()) + .await?; + while let Some(Ok((key, membership_data))) = membership_iter.next().await { + let mut idty_index_bytes = [0u8; 4]; + idty_index_bytes.copy_from_slice(&key[40..]); + let membership_val = MembershipData { + expire_on: membership_data.expire_on, + }; + memberships.insert(IdtyIndex::from_le_bytes(idty_index_bytes), membership_val); + } + println!("memberships.len(): {}.", memberships.len()); + let storage = Storage { accounts, identities, identity_index_of, + memberships, + identities_names, }; // ===== Verify storage ===== // @@ -178,6 +218,12 @@ mod verifier { .await; self.verify_identity_coherence(&storage.identities, &storage.identity_index_of) .await; + self.verify_status_coherence( + &storage.identities, + &storage.memberships, + &storage.identities_names, + ) + .await; if self.errors.is_empty() { Ok(()) @@ -232,15 +278,6 @@ mod verifier { format!("Account {} has no providers nor sufficients.", account_id), ); } - - if account_id.as_slice() != TREASURY_ACCOUNT_ID { - // Rule 4: If the account is not a "special account", - // it should have a consumer - self.assert( - account_info.consumers > 0, - format!("Account {} has no consumer.", account_id), - ); - } } } @@ -340,6 +377,76 @@ mod verifier { } } + /// check identities status and membership coherence + async fn verify_status_coherence( + &mut self, + identities: &HashMap<IdtyIndex, IdtyValue>, + memberships: &HashMap<IdtyIndex, MembershipData>, + names: &HashMap<IdtyIndex, IdtyName>, + ) { + for (idty_index, idty_value) in identities { + // Rule 1: each Status::Member should have a membership and a name. + if let IdtyStatus::Member = idty_value.status { + self.assert( + memberships.get(idty_index).is_some(), + format!("identity number {idty_index} should have a valid membership"), + ); + self.assert( + names.get(idty_index).is_some(), + format!("identity number {idty_index} should have a name"), + ); + } + + // Rule 2: each Status::NotMember should have a name but no membership. + if let IdtyStatus::NotMember = idty_value.status { + self.assert( + memberships.get(idty_index).is_none(), + format!("identity number {idty_index} should not have a valid membership"), + ); + self.assert( + names.get(idty_index).is_some(), + format!("identity number {idty_index} should have a name"), + ); + } + + // Rule 3: each Status::Revoke should should have a name but no membership. + if let IdtyStatus::Revoked = idty_value.status { + self.assert( + memberships.get(idty_index).is_none(), + format!("identity number {idty_index} should not have a valid membership"), + ); + self.assert( + names.get(idty_index).is_some(), + format!("identity number {idty_index} should have a name"), + ); + } + + // Rule 4: each Status::Unvalidaded should have a name but no membership. + if let IdtyStatus::Unvalidated = idty_value.status { + self.assert( + memberships.get(idty_index).is_none(), + format!("identity number {idty_index} should not have a valid membership"), + ); + self.assert( + names.get(idty_index).is_some(), + format!("identity number {idty_index} should have a name"), + ); + } + + // Rule 5: each Status::Unconfirmed should not have a name neither a membership. + if let IdtyStatus::Unconfirmed = idty_value.status { + self.assert( + memberships.get(idty_index).is_none(), + format!("identity number {idty_index} should not have a valid membership"), + ); + self.assert( + names.get(idty_index).is_none(), + format!("identity number {idty_index} should not have a name"), + ); + } + } + } + /// check coherence between identity list and identity index hashmap async fn verify_identity_coherence( &mut self, -- GitLab