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