diff --git a/live-tests/tests/sanity_gdev.rs b/live-tests/tests/sanity_gdev.rs index 3036290550e0aafd7a67fac6a74e8cc2e0afec0f..0e549a2e3bcde1a539ef67b1b2a85f122255773f 100644 --- a/live-tests/tests/sanity_gdev.rs +++ b/live-tests/tests/sanity_gdev.rs @@ -23,7 +23,6 @@ use std::collections::{HashMap, HashSet}; use subxt::{backend::rpc::RpcClient, config::SubstrateConfig as GdevConfig}; const DEFAULT_ENDPOINT: &str = "ws://localhost:9944"; -//const DEFAULT_ENDPOINT: &str = "wss://gdev.coinduf.eu"; // Will fail for runtime 801 (https://git.duniter.org/nodes/rust/duniter-v2s/-/issues/244) const EXISTENTIAL_DEPOSIT: u64 = 100; //use hex_literal::hex; @@ -374,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(), @@ -398,7 +400,9 @@ mod verifier { ); } - // 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(), @@ -414,7 +418,10 @@ mod verifier { ); } - // 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(), @@ -430,7 +437,9 @@ mod verifier { ); } - // 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(), @@ -446,7 +455,9 @@ mod verifier { ); } - // 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(), @@ -456,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!("identity number {idty_index} should have a non-null next_scheduled value"), + ); } } } diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs index b3a1b79600068d78a8c9cdcfa06f71ac215f52f6..c78154891055aa953851add1c16ab0b668137624 100644 --- a/node/src/chain_spec/gdev.rs +++ b/node/src/chain_spec/gdev.rs @@ -279,6 +279,8 @@ fn genesis_data_to_gdev_genesis_conf( name, owner_key, status, + // at this point next_scheduled takes status into account + // so is null for member account next_scheduled, }| GenesisIdty { index: idty_index, diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs index 901af51ef36a0f59a14ea245ab875a7990c7179b..a7c338ac60e080bc48569576b511bdd2f8b9a5a2 100644 --- a/node/src/chain_spec/gen_genesis_data.rs +++ b/node/src/chain_spec/gen_genesis_data.rs @@ -196,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 @@ -1268,6 +1272,7 @@ 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_revoke_on: common_parameters.membership_membership_period, revoked: false, @@ -1329,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() { @@ -1411,23 +1397,27 @@ fn feed_identities( status, next_scheduled: match status { IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => { - panic!("Unconfirmed or Unvalidated or Revoked identity in genesis") + // 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 } - // The identity will be scheduled for revocation after the auto-revocation period. - IdtyStatus::NotMember => common_parameters.identity_autorevocation_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, }, ); @@ -1760,6 +1750,7 @@ 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| { ( diff --git a/runtime/gdev/src/parameters.rs b/runtime/gdev/src/parameters.rs index 860d6369627e2a9927bcc90465381060e964daa6..3acae2658a4adf220d9d0abb8d23788aa4f3e454 100644 --- a/runtime/gdev/src/parameters.rs +++ b/runtime/gdev/src/parameters.rs @@ -90,9 +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 DeletionPeriod: BlockNumber = 10 * YEARS; + pub const AutorevocationPeriod: BlockNumber = 1 * MONTHS; + pub const DeletionPeriod: BlockNumber = 1 * MONTHS; } // Membership