From db052be79c30af922d177d8984360f59e329801a Mon Sep 17 00:00:00 2001
From: Benjamin Gallois <business@gallois.cc>
Date: Fri, 8 Nov 2024 16:43:48 +0100
Subject: [PATCH] Fix 244 coherence between identity next_schedule and
 membership expire_on (nodes/rust/duniter-v2s!275)

* add info about status

* update metadata after autorevoke and deletion period change

* clippy

* add comments

* refactore identity chain spec

* add coherence test

* fix https://git.duniter.org/nodes/rust/duniter-v2s/-/issues/244
---
 Cargo.lock                              |  71 +++++++++++-----------
 live-tests/tests/sanity_gdev.rs         |  50 ++++++++++++++--
 node/src/chain_spec/g1.rs               |  20 ++-----
 node/src/chain_spec/gdev.rs             |  19 ++----
 node/src/chain_spec/gen_genesis_data.rs |  75 ++++++++++++------------
 node/src/chain_spec/gtest.rs            |  17 ++----
 resources/metadata.scale                | Bin 149644 -> 149644 bytes
 runtime/common/src/pallets_config.rs    |   1 -
 runtime/g1/src/parameters.rs            |   1 +
 runtime/gdev/src/parameters.rs          |   4 +-
 runtime/gtest/src/parameters.rs         |   1 +
 11 files changed, 142 insertions(+), 117 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0d42a0448..d0f9a4833 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -996,9 +996,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.22"
+version = "1.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
 dependencies = [
  "jobserver",
  "libc",
@@ -1134,9 +1134,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.18"
+version = "4.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
+checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -1144,9 +1144,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.18"
+version = "4.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
+checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
 dependencies = [
  "anstream",
  "anstyle",
@@ -1157,9 +1157,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.29"
+version = "4.5.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e"
+checksum = "74a01f4f9ee6c066d42a1c8dedf0dcddad16c72a8981a309d6398de3a75b0c39"
 dependencies = [
  "clap",
 ]
@@ -3678,7 +3678,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http 0.2.12",
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
  "slab",
  "tokio",
  "tokio-util",
@@ -3697,7 +3697,7 @@ dependencies = [
  "futures-core",
  "futures-sink",
  "http 1.1.0",
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
  "slab",
  "tokio",
  "tokio-util",
@@ -3759,6 +3759,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+
 [[package]]
 name = "hashlink"
 version = "0.8.4"
@@ -3927,9 +3933,9 @@ dependencies = [
 
 [[package]]
 name = "httparse"
-version = "1.9.4"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 
 [[package]]
 name = "httpdate"
@@ -4226,12 +4232,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.5",
+ "hashbrown 0.15.0",
 ]
 
 [[package]]
@@ -5368,7 +5374,7 @@ dependencies = [
  "futures 0.3.30",
  "futures-timer",
  "hex-literal",
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
  "libc",
  "mockall 0.12.1",
  "multiaddr 0.17.1",
@@ -7209,7 +7215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
 dependencies = [
  "fixedbitset",
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
 ]
 
 [[package]]
@@ -7986,9 +7992,9 @@ dependencies = [
 
 [[package]]
 name = "raw-cpuid"
-version = "11.1.0"
+version = "11.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d"
+checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -8173,9 +8179,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "reqwest"
-version = "0.12.7"
+version = "0.12.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
+checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
 dependencies = [
  "base64 0.22.1",
  "bytes",
@@ -8196,7 +8202,7 @@ dependencies = [
  "pin-project-lite",
  "quinn 0.11.5",
  "rustls 0.23.13",
- "rustls-pemfile 2.1.3",
+ "rustls-pemfile 2.2.0",
  "rustls-pki-types",
  "serde",
  "serde_json",
@@ -8445,7 +8451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
 dependencies = [
  "openssl-probe",
- "rustls-pemfile 2.1.3",
+ "rustls-pemfile 2.2.0",
  "rustls-pki-types",
  "schannel",
  "security-framework",
@@ -8462,11 +8468,10 @@ dependencies = [
 
 [[package]]
 name = "rustls-pemfile"
-version = "2.1.3"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
 dependencies = [
- "base64 0.22.1",
  "rustls-pki-types",
 ]
 
@@ -10127,7 +10132,7 @@ version = "0.9.34+deprecated"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
 dependencies = [
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
  "itoa",
  "ryu",
  "serde",
@@ -11777,12 +11782,12 @@ dependencies = [
 
 [[package]]
 name = "terminal_size"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
 dependencies = [
  "rustix 0.38.37",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -12040,7 +12045,7 @@ version = "0.22.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
 dependencies = [
- "indexmap 2.5.0",
+ "indexmap 2.6.0",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -12397,9 +12402,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
 
 [[package]]
 name = "unicode-ident"
diff --git a/live-tests/tests/sanity_gdev.rs b/live-tests/tests/sanity_gdev.rs
index ca6ded3e8..132680dfd 100644
--- a/live-tests/tests/sanity_gdev.rs
+++ b/live-tests/tests/sanity_gdev.rs
@@ -373,7 +373,10 @@ mod verifier {
             names: &HashMap<IdtyIndex, IdtyName>,
         ) {
             for (idty_index, idty_value) in identities {
-                // Rule 1: each Status::Member should have a membership and a name.
+                // Rule 1: each Status::Member
+                // should have a membership and a name
+                // membership should be set to expire
+                // identity should have no scheduled action
                 if let IdtyStatus::Member = idty_value.status {
                     self.assert(
                         memberships.get(idty_index).is_some(),
@@ -383,9 +386,23 @@ mod verifier {
                         names.get(idty_index).is_some(),
                         format!("identity number {idty_index} should have a name"),
                     );
+                    self.assert(
+                        memberships.get(idty_index).unwrap().expire_on != 0,
+                        format!(
+                            "Member identity number {idty_index} should have a non-null expire_on value"
+                        ),
+                    );
+                    self.assert(
+                        identities.get(idty_index).unwrap().next_scheduled == 0,
+                        format!(
+                            "Member identity number {idty_index} should have a null next_scheduled value"
+                        ),
+                    );
                 }
 
-                // Rule 2: each Status::NotMember should have a name but no membership.
+                // Rule 2: each Status::NotMember
+                // should have a name but no membership
+                // should have a scheduled action (auto-revocation)
                 if let IdtyStatus::NotMember = idty_value.status {
                     self.assert(
                         memberships.get(idty_index).is_none(),
@@ -395,9 +412,16 @@ mod verifier {
                         names.get(idty_index).is_some(),
                         format!("identity number {idty_index} should have a name"),
                     );
+                    self.assert(
+                        identities.get(idty_index).unwrap().next_scheduled != 0,
+                        format!("NotMember identity number {idty_index} should have a non-null next_scheduled value"),
+                    );
                 }
 
-                // Rule 3: each Status::Revoke should should have a name but no membership.
+                // Rule 3: each Status::Revoked
+                // should should have a name
+                // no membership
+                // should be scheduled for removal
                 if let IdtyStatus::Revoked = idty_value.status {
                     self.assert(
                         memberships.get(idty_index).is_none(),
@@ -407,9 +431,15 @@ mod verifier {
                         names.get(idty_index).is_some(),
                         format!("identity number {idty_index} should have a name"),
                     );
+                    self.assert(
+                        identities.get(idty_index).unwrap().next_scheduled != 0,
+                        format!("Revoked identity number {idty_index} should have a non-null next_scheduled value"),
+                    );
                 }
 
-                // Rule 4: each Status::Unvalidaded should have a name but no membership.
+                // Rule 4: each Status::Unvalidaded
+                // should have a name but no membership.
+                // should be scheduled for removal
                 if let IdtyStatus::Unvalidated = idty_value.status {
                     self.assert(
                         memberships.get(idty_index).is_none(),
@@ -419,9 +449,15 @@ mod verifier {
                         names.get(idty_index).is_some(),
                         format!("identity number {idty_index} should have a name"),
                     );
+                    self.assert(
+                        identities.get(idty_index).unwrap().next_scheduled != 0,
+                        format!("Unvalidated identity number {idty_index} should have a non-null next_scheduled value"),
+                    );
                 }
 
-                // Rule 5: each Status::Unconfirmed should not have a name neither a membership.
+                // Rule 5: each Status::Unconfirmed
+                // should not have a name neither a membership.
+                // should be scheduled for removal soon
                 if let IdtyStatus::Unconfirmed = idty_value.status {
                     self.assert(
                         memberships.get(idty_index).is_none(),
@@ -431,6 +467,10 @@ mod verifier {
                         names.get(idty_index).is_none(),
                         format!("identity number {idty_index} should not have a name"),
                     );
+                    self.assert(
+                        identities.get(idty_index).unwrap().next_scheduled != 0,
+                        format!("Unconfirmed identity number {idty_index} should have a non-null next_scheduled value"),
+                    );
                 }
             }
         }
diff --git a/node/src/chain_spec/g1.rs b/node/src/chain_spec/g1.rs
index b84e42225..8ad20d230 100644
--- a/node/src/chain_spec/g1.rs
+++ b/node/src/chain_spec/g1.rs
@@ -18,9 +18,10 @@ use super::*;
 use crate::chain_spec::gen_genesis_data::{
     AuthorityKeys, CommonParameters, GenesisIdentity, SessionKeysProvider,
 };
-use common_runtime::{constants::*, entities::IdtyData, GenesisIdty, IdtyStatus};
+use common_runtime::{constants::*, entities::IdtyData, GenesisIdty};
 use g1_runtime::{
-    opaque::SessionKeys, pallet_universal_dividend, parameters, Runtime, WASM_BINARY,
+    opaque::SessionKeys, pallet_universal_dividend, parameters, Runtime, RuntimeGenesisConfig,
+    WASM_BINARY,
 };
 use sc_service::ChainType;
 use serde::Deserialize;
@@ -73,6 +74,7 @@ fn get_parameters(_parameters_from_file: &Option<GenesisParameters>) -> CommonPa
         identity_change_owner_key_period: parameters::ChangeOwnerKeyPeriod::get(),
         identity_idty_creation_period: parameters::IdtyCreationPeriod::get(),
         identity_autorevocation_period: parameters::AutorevocationPeriod::get(),
+        identity_deletion_period: parameters::DeletionPeriod::get(),
         membership_membership_period: parameters::MembershipPeriod::get(),
         membership_membership_renewal_period: parameters::MembershipRenewalPeriod::get(),
         cert_max_by_issuer: parameters::MaxByIssuer::get(),
@@ -191,8 +193,7 @@ fn genesis_data_to_g1_genesis_conf(
                          name,
                          owner_key,
                          status,
-                         expires_on,
-                         revokes_on,
+                         next_scheduled,
                      }| GenesisIdty {
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
@@ -201,16 +202,7 @@ fn genesis_data_to_g1_genesis_conf(
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
-                            next_scheduled: match status {
-                                IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => {
-                                    panic!("Unconfirmed or Unvalidated identity in genesis")
-                                }
-                                IdtyStatus::Member => expires_on.expect("must have expires_on set"),
-                                IdtyStatus::Revoked => 0,
-                                IdtyStatus::NotMember => {
-                                    revokes_on.expect("must have revokes_on set")
-                                }
-                            },
+                            next_scheduled,
                             status,
                         },
                     },
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index 5b4a27c1d..c78154891 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -18,7 +18,7 @@ use super::*;
 use crate::chain_spec::gen_genesis_data::{
     AuthorityKeys, CommonParameters, GenesisIdentity, SessionKeysProvider,
 };
-use common_runtime::{constants::*, entities::IdtyData, GenesisIdty, IdtyStatus};
+use common_runtime::{constants::*, entities::IdtyData, GenesisIdty};
 use gdev_runtime::{
     opaque::SessionKeys, pallet_universal_dividend, parameters, Runtime, WASM_BINARY,
 };
@@ -79,6 +79,7 @@ fn get_parameters(parameters_from_file: &Option<GenesisParameters>) -> CommonPar
         identity_change_owner_key_period: parameters::ChangeOwnerKeyPeriod::get(),
         identity_idty_creation_period: parameters_from_file.idty_creation_period,
         identity_autorevocation_period: parameters::AutorevocationPeriod::get(),
+        identity_deletion_period: parameters::DeletionPeriod::get(),
         membership_membership_period: parameters_from_file.membership_period,
         membership_membership_renewal_period: parameters_from_file.membership_renewal_period,
         cert_max_by_issuer: parameters_from_file.cert_max_by_issuer,
@@ -278,8 +279,9 @@ fn genesis_data_to_gdev_genesis_conf(
                          name,
                          owner_key,
                          status,
-                         expires_on,
-                         revokes_on,
+                        // at this point next_scheduled takes status into account
+                        // so is null for member account
+                         next_scheduled,
                      }| GenesisIdty {
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
@@ -288,16 +290,7 @@ fn genesis_data_to_gdev_genesis_conf(
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
-                            next_scheduled: match status {
-                                IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => {
-                                    panic!("Unconfirmed or Unvalidated identity in genesis")
-                                }
-                                IdtyStatus::Member => expires_on.expect("must have expires_on set"),
-                                IdtyStatus::Revoked => 0,
-                                IdtyStatus::NotMember => {
-                                    revokes_on.expect("must have revokes_on set")
-                                }
-                            },
+                            next_scheduled,
                             status,
                         },
                     },
diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs
index 72a7a0dc6..a7c338ac6 100644
--- a/node/src/chain_spec/gen_genesis_data.rs
+++ b/node/src/chain_spec/gen_genesis_data.rs
@@ -100,8 +100,7 @@ pub struct GenesisIdentity {
     pub name: String,
     pub owner_key: AccountId,
     pub status: IdtyStatus,
-    pub expires_on: Option<u32>,
-    pub revokes_on: Option<u32>,
+    pub next_scheduled: u32,
 }
 
 #[derive(Deserialize, Serialize)]
@@ -197,6 +196,10 @@ struct IdentityV1 {
 }
 
 /// identities
+// note: having membership_expire_on and identity_revoke_on is tricky
+// because the model of identity does not take into account the status
+// see this forum topic for a suggestion
+// https://forum.duniter.org/t/proposition-pour-supprimer-la-pallet-membership/11918
 #[derive(Clone, Deserialize, Serialize)]
 struct IdentityV2 {
     /// indentity index matching the order of appearance in the Ǧ1v1 blockchain
@@ -206,7 +209,7 @@ struct IdentityV2 {
     /// block at which the membership is set to expire (0 for expired members)
     membership_expire_on: u32,
     /// block at which the identity should be revoked (value in the past for already revoked identities)
-    identity_revokes_on: u32,
+    identity_revoke_on: u32,
     /// whether the identity is revoked (manually or automatically)
     revoked: bool,
     /// block at which the next cert can be emitted
@@ -376,6 +379,7 @@ where
         &mut inactive_identities,
         &mut memberships,
         &identities_v2,
+        &common_parameters,
     )?;
     if was_fatal {
         fatal = true;
@@ -1223,7 +1227,7 @@ fn genesis_data_to_identities_v2(
                         i.membership_expire_on,
                         genesis_timestamp,
                     ),
-                    identity_revokes_on: timestamp_to_relative_blocs(
+                    identity_revoke_on: timestamp_to_relative_blocs(
                         i.membership_revokes_on,
                         genesis_timestamp,
                     ),
@@ -1268,8 +1272,9 @@ fn make_authority_exist<SessionKeys: Encode, SKP: SessionKeysProvider<SessionKey
                 owner_key: get_account_id_from_seed::<sr25519::Public>(authority_name),
                 balance: common_parameters.balances_existential_deposit,
                 certs_received: HashMap::new(),
+                // note: in this context of generating genesis identities
                 membership_expire_on: common_parameters.membership_membership_period,
-                identity_revokes_on: common_parameters.identity_autorevocation_period,
+                identity_revoke_on: common_parameters.membership_membership_period,
                 revoked: false,
                 next_cert_issuable_on: 0,
             },
@@ -1319,6 +1324,7 @@ fn feed_identities(
     inactive_identities: &mut HashMap<u32, (String, IdtyStatus)>,
     memberships: &mut BTreeMap<u32, MembershipData>,
     identities_v2: &HashMap<String, IdentityV2>,
+    common_parameters: &CommonParameters,
 ) -> Result<(bool, Vec<GenesisIdentity>), String> {
     let mut fatal = false;
     let mut identities: Vec<GenesisIdentity> = Vec::new();
@@ -1328,25 +1334,6 @@ fn feed_identities(
             return Err(format!("Identity name '{}' is invalid", &name));
         }
 
-        // TODO: re-check this code origin and wether it should be included or not
-        // do not check existential deposit of identities
-        // // check existential deposit
-        // if identity.balance < common_parameters.existencial_deposit {
-        //     if identity.membership_expire_on == 0 {
-        //         log::warn!(
-        //             "expired identity {name} has {} cǦT which is below {}",
-        //             identity.balance, common_parameters.existencial_deposit
-        //         );
-        //         fatal = true;
-        //     } else {
-        //         member identities can still be below existential deposit thanks to sufficient
-        //         log::info!(
-        //             "identity {name} has {} cǦT which is below {}",
-        //             identity.balance, common_parameters.existencial_deposit
-        //         );
-        //     }
-        // }
-
         // Money
         // check that wallet with same owner_key does not exist
         if accounts.get(&identity.owner_key).is_some() {
@@ -1408,23 +1395,29 @@ fn feed_identities(
             owner_key: identity.owner_key.clone(),
             // but expired identities will just have their pseudonym reserved in the storage
             status,
-            expires_on: if status == IdtyStatus::Member {
-                Some(identity.membership_expire_on)
-            } else {
-                None
-            },
-            revokes_on: if status == IdtyStatus::NotMember {
-                Some(identity.identity_revokes_on)
-            } else {
-                None
+            next_scheduled: match status {
+                IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => {
+                    // these intermediary formats are disallowed in the genesis
+                    // since they correspond to offchain v1 data
+                    panic!("Unconfirmed or Unvalidated identity in genesis")
+                }
+                // Member identities schedule is managed by membership pallet
+                IdtyStatus::Member => 0,
+                // The identity will be scheduled for revocation after the auto-revocation period.
+                IdtyStatus::NotMember => common_parameters.identity_autorevocation_period,
+                // The identity will be scheduled for removal at the revoke block plus the deletion period.
+                IdtyStatus::Revoked => {
+                    identity.identity_revoke_on + common_parameters.identity_deletion_period
+                }
             },
         });
 
-        // insert the membershup data (only if not expired)
+        // insert the membership data (only if not expired)
         if !expired {
             memberships.insert(
                 identity.index,
                 MembershipData {
+                    // here we are using the correct expire block
                     expire_on: identity.membership_expire_on,
                 },
             );
@@ -1667,8 +1660,7 @@ where
             name: String::from_utf8(name.0.clone()).unwrap(),
             owner_key: owner_key.clone(),
             status: IdtyStatus::Member,
-            expires_on: Some(common_parameters.membership_membership_period),
-            revokes_on: None,
+            next_scheduled: 0,
         })
         .collect();
 
@@ -1758,8 +1750,16 @@ where
         identities,
         initial_authorities,
         initial_monetary_mass: initial_identities_len as u64 * initial_idty_balance,
+        // when generating data for local chain, we can set membersip expiration to membership period
         memberships: (1..=initial_identities.len())
-            .map(|i| (i as u32, MembershipData { expire_on: 0 }))
+            .map(|i| {
+                (
+                    i as u32,
+                    MembershipData {
+                        expire_on: common_parameters.membership_membership_period,
+                    },
+                )
+            })
             .collect(),
         parameters,
         common_parameters: None,
@@ -1935,6 +1935,7 @@ pub struct CommonParameters {
     pub identity_change_owner_key_period: u32,
     pub identity_idty_creation_period: u32,
     pub identity_autorevocation_period: u32,
+    pub identity_deletion_period: u32,
     pub membership_membership_period: u32,
     pub membership_membership_renewal_period: u32,
     pub cert_cert_period: u32,
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 930d5ea75..2b4020664 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -16,7 +16,7 @@
 
 use super::*;
 use crate::chain_spec::gen_genesis_data::{CommonParameters, GenesisIdentity, SessionKeysProvider};
-use common_runtime::{constants::*, entities::IdtyData, GenesisIdty, IdtyStatus};
+use common_runtime::{constants::*, entities::IdtyData, GenesisIdty};
 use gtest_runtime::{
     opaque::SessionKeys, pallet_universal_dividend, parameters, ImOnlineId, Runtime, WASM_BINARY,
 };
@@ -127,6 +127,7 @@ fn get_parameters(_: &Option<GenesisParameters>) -> CommonParameters {
         identity_change_owner_key_period: parameters::ChangeOwnerKeyPeriod::get(),
         identity_idty_creation_period: parameters::IdtyCreationPeriod::get(),
         identity_autorevocation_period: parameters::AutorevocationPeriod::get(),
+        identity_deletion_period: parameters::DeletionPeriod::get(),
         membership_membership_period: parameters::MembershipPeriod::get(),
         membership_membership_renewal_period: parameters::MembershipRenewalPeriod::get(),
         cert_max_by_issuer: parameters::MaxByIssuer::get(),
@@ -285,8 +286,7 @@ fn genesis_data_to_gtest_genesis_conf(
                          name,
                          owner_key,
                          status,
-                         expires_on,
-                         revokes_on,
+                         next_scheduled,
                      }| GenesisIdty {
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
@@ -295,16 +295,7 @@ fn genesis_data_to_gtest_genesis_conf(
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
-                            next_scheduled: match status {
-                                IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => {
-                                    panic!("Unconfirmed or Unvalidated identity in genesis")
-                                }
-                                IdtyStatus::Member => expires_on.expect("must have expires_on set"),
-                                IdtyStatus::Revoked => 0,
-                                IdtyStatus::NotMember => {
-                                    revokes_on.expect("must have revokes_on set")
-                                }
-                            },
+                            next_scheduled,
                             status,
                         },
                     },
diff --git a/resources/metadata.scale b/resources/metadata.scale
index 945a23e9cc05e24d7f4eced0da1216cf5843b4db..bc6249410cc4aae5fb67a3b3d64645f97d7f75b7 100644
GIT binary patch
delta 33
ncmeB~$k{WIv!R7?3)2%0W|<9a)1PxNWv~Dl4BLY_nJn!A!DR{@

delta 33
pcmeB~$k{WIv!R7?3)2%0<^acl>CZWsGFTLPm6*2&b23@l0|3H53M&8r

diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index 3b5ae90ba..0b906cddb 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -454,7 +454,6 @@ macro_rules! pallets_config {
 
         parameter_types! {
             pub const ValidationPeriod: BlockNumber = 2 * MONTHS;
-            pub const DeletionPeriod: BlockNumber = 10 * YEARS;
         }
         impl pallet_identity::Config for Runtime {
             type AccountLinker = Account;
diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs
index ee768989c..d787eb5bf 100644
--- a/runtime/g1/src/parameters.rs
+++ b/runtime/g1/src/parameters.rs
@@ -112,6 +112,7 @@ parameter_types! {
     pub const IdtyCreationPeriod: BlockNumber = MONTHS;
     pub const ValidationPeriod: BlockNumber = YEARS;
     pub const AutorevocationPeriod: BlockNumber = YEARS;
+    pub const DeletionPeriod: BlockNumber = 10 * YEARS;
 }
 
 // Membership
diff --git a/runtime/gdev/src/parameters.rs b/runtime/gdev/src/parameters.rs
index 0b7083313..bcca8e7d2 100644
--- a/runtime/gdev/src/parameters.rs
+++ b/runtime/gdev/src/parameters.rs
@@ -90,8 +90,10 @@ parameter_types! {
 
 // Identity
 frame_support::parameter_types! {
+    // for gdev we can have short periods
     pub const ChangeOwnerKeyPeriod: BlockNumber = 7 * DAYS;
-    pub const AutorevocationPeriod: BlockNumber = YEARS;
+    pub const AutorevocationPeriod: BlockNumber = MONTHS;
+    pub const DeletionPeriod: BlockNumber = MONTHS;
 }
 
 // Membership
diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs
index 6295b34bc..307f59b19 100644
--- a/runtime/gtest/src/parameters.rs
+++ b/runtime/gtest/src/parameters.rs
@@ -105,6 +105,7 @@ parameter_types! {
     pub const ConfirmPeriod: BlockNumber = DAYS;
     pub const IdtyCreationPeriod: BlockNumber = DAYS;
     pub const AutorevocationPeriod: BlockNumber = YEARS;
+    pub const DeletionPeriod: BlockNumber = 10 * YEARS;
 }
 
 // Membership
-- 
GitLab