diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ce5414b958737f138f9549f2a2d2a031d5cf5200..327707ff9926ebe9ac4180049235c237fc04c84b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -94,6 +94,7 @@ run_benchmarks: tags: - podman +# FIXME: "gtest_build" gdev_build: stage: build image: rust:1-bullseye diff --git a/Cargo.lock b/Cargo.lock index 7c939dae90fe4114d37d5934cd15ab862df6c7f6..d4e07f05ff14faaeab5e20373e79b117145c8636 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,6 +1160,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", + "pallet-smith-members", "pallet-timestamp", "pallet-treasury", "pallet-universal-dividend", @@ -3171,6 +3172,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", + "pallet-smith-members", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -3241,6 +3243,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", + "pallet-smith-members", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -3572,6 +3575,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", + "pallet-smith-members", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -6348,6 +6352,27 @@ dependencies = [ "sp-std 5.0.0", ] +[[package]] +name = "pallet-smith-members" +version = "3.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "maplit", + "pallet-authority-members", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + [[package]] name = "pallet-sudo" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 5517414ea929bdcb8445fca79f6b8e9b0f7e711d..362749c15a189ed509b54fa6e311b5075387ad1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -156,6 +156,7 @@ members = [ 'pallets/membership', 'pallets/oneshot-account', 'pallets/authority-members', + 'pallets/smith-members', 'pallets/universal-dividend', 'pallets/upgrade-origin', 'primitives/membership', diff --git a/end2end-tests/cucumber-genesis/default.json b/end2end-tests/cucumber-genesis/default.json index fab39aad614d7f3f631cae19d24dfd757cc567d0..245e91e312e06afca31bf3a5023a5e423c8d2e31 100644 --- a/end2end-tests/cucumber-genesis/default.json +++ b/end2end-tests/cucumber-genesis/default.json @@ -56,13 +56,8 @@ "pending_membership_period": 500, "ud_creation_period": 60000, "ud_reeval_period": 600000, - "smith_cert_period": 15, "smith_cert_max_by_issuer": 8, - "smith_cert_min_received_cert_to_issue_cert": 2, - "smith_cert_validity_period": 1000, - "smith_membership_period": 1000, - "smith_pending_membership_period": 500, - "smith_wot_first_cert_issuable_on": 20, + "smith_inactivity_max_duration": 48, "smith_wot_min_cert_for_membership": 2, "wot_first_cert_issuable_on": 20, "wot_min_cert_for_create_idty_right": 2, diff --git a/end2end-tests/cucumber-genesis/wot.json b/end2end-tests/cucumber-genesis/wot.json index 4c7183b2a37cd3b82fd4c95ba360cf0025c91ae8..6b1fad67065eb3323c083cc7e0e80ae8ce6098ef 100644 --- a/end2end-tests/cucumber-genesis/wot.json +++ b/end2end-tests/cucumber-genesis/wot.json @@ -65,13 +65,8 @@ "pending_membership_period": 500, "ud_creation_period": 60000, "ud_reeval_period": 600000, - "smith_cert_period": 15, "smith_cert_max_by_issuer": 8, - "smith_cert_min_received_cert_to_issue_cert": 2, - "smith_cert_validity_period": 1000, - "smith_membership_period": 1000, - "smith_pending_membership_period": 500, - "smith_wot_first_cert_issuable_on": 20, + "smith_inactivity_max_duration": 48, "smith_wot_min_cert_for_membership": 2, "wot_first_cert_issuable_on": 20, "wot_min_cert_for_create_idty_right": 2, diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs index 0639cbfed4d086ba965d2ce4fb8cc15f7c8d37f0..4d80232c6e87564a2a7cfcffb75261c29bd49164 100644 --- a/node/src/chain_spec/gdev.rs +++ b/node/src/chain_spec/gdev.rs @@ -24,9 +24,8 @@ use common_runtime::*; use gdev_runtime::{ opaque::SessionKeys, pallet_universal_dividend, parameters, AccountConfig, AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig, GenesisConfig, IdentityConfig, - MembershipConfig, ParametersConfig, QuotaConfig, Runtime, SessionConfig, SmithCertConfig, - SmithMembershipConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, - UniversalDividendConfig, WASM_BINARY, + MembershipConfig, ParametersConfig, QuotaConfig, Runtime, SessionConfig, SmithMembersConfig, + SudoConfig, SystemConfig, TechnicalCommitteeConfig, UniversalDividendConfig, WASM_BINARY, }; use jsonrpsee::core::JsonValue; use sc_network::config::MultiaddrWithPeerId; @@ -39,7 +38,7 @@ use std::{env, fs}; pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>; -type GenesisParameters = gdev_runtime::GenesisParameters<u32, u32, u64>; +type GenesisParameters = gdev_runtime::GenesisParameters<u32, u32, u64, u32>; const TOKEN_DECIMALS: usize = 2; const TOKEN_SYMBOL: &str = "ĞD"; @@ -94,17 +93,10 @@ fn get_parameters(parameters_from_file: &Option<GenesisParameters>) -> CommonPar cert_validity_period: parameters_from_file.cert_validity_period, distance_min_accessible_referees: Perbill::from_percent(80), // TODO: generalize distance_max_depth: 5, // TODO: generalize - smith_sub_wot_first_issuable_on: parameters_from_file.smith_wot_first_cert_issuable_on, smith_sub_wot_min_cert_for_membership: parameters_from_file .smith_wot_min_cert_for_membership, - smith_membership_membership_period: parameters_from_file.smith_membership_period, - smith_membership_pending_membership_period: parameters_from_file - .smith_pending_membership_period, - smith_cert_cert_period: parameters_from_file.smith_cert_period, smith_cert_max_by_issuer: parameters_from_file.smith_cert_max_by_issuer, - smith_cert_min_received_cert_to_be_able_to_issue_cert: parameters_from_file - .smith_cert_min_received_cert_to_issue_cert, - smith_cert_validity_period: parameters_from_file.smith_cert_validity_period, + smith_inactivity_max_duration: parameters_from_file.smith_inactivity_max_duration, cert_cert_period: parameters_from_file.cert_period, treasury_spend_period: <Runtime as pallet_treasury::Config>::SpendPeriod::get(), } @@ -290,8 +282,7 @@ fn genesis_data_to_gdev_genesis_conf( parameters, common_parameters: _, session_keys_map, - smith_certs_by_receiver, - smith_memberships, + initial_smiths, sudo_key, technical_committee_members, ud, @@ -366,13 +357,7 @@ fn genesis_data_to_gdev_genesis_conf( certs_by_receiver, }, membership: MembershipConfig { memberships }, - smith_cert: SmithCertConfig { - apply_cert_period_at_genesis: true, - certs_by_receiver: smith_certs_by_receiver, - }, - smith_membership: SmithMembershipConfig { - memberships: smith_memberships, - }, + smith_members: SmithMembersConfig { initial_smiths }, universal_dividend: UniversalDividendConfig { first_reeval: first_ud_reeval, first_ud, @@ -387,8 +372,6 @@ fn get_local_chain_parameters() -> Option<GenesisParameters> { let babe_epoch_duration = get_env("DUNITER_BABE_EPOCH_DURATION", 30) as u64; let cert_validity_period = get_env("DUNITER_CERT_VALIDITY_PERIOD", 1_000); let membership_period = get_env("DUNITER_MEMBERSHIP_PERIOD", 1_000); - let smith_cert_validity_period = get_env("DUNITER_SMITH_CERT_VALIDITY_PERIOD", 1_000); - let smith_membership_period = get_env("DUNITER_SMITH_MEMBERSHIP_PERIOD", 1_000); let ud_creation_period = get_env("DUNITER_UD_CREATION_PERIOD", 60_000); let ud_reeval_period = get_env("DUNITER_UD_REEEVAL_PERIOD", 1_200_000); Some(GenesisParameters { @@ -403,13 +386,8 @@ fn get_local_chain_parameters() -> Option<GenesisParameters> { pending_membership_period: 500, ud_creation_period, ud_reeval_period, - smith_cert_period: 15, smith_cert_max_by_issuer: 8, - smith_cert_min_received_cert_to_issue_cert: 2, - smith_cert_validity_period, - smith_membership_period, - smith_pending_membership_period: 500, - smith_wot_first_cert_issuable_on: 20, + smith_inactivity_max_duration: 48, smith_wot_min_cert_for_membership: 2, wot_first_cert_issuable_on: 20, wot_min_cert_for_create_idty_right: 2, diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs index 1813434b7a43e0366d89fc345c163a498102f250..ab9856efe65d8161e595fb68d0cc0b1960c21259 100644 --- a/node/src/chain_spec/gen_genesis_data.rs +++ b/node/src/chain_spec/gen_genesis_data.rs @@ -74,8 +74,7 @@ pub struct GenesisData<Parameters: DeserializeOwned, SessionKeys: Decode> { pub parameters: Option<Parameters>, pub common_parameters: Option<CommonParameters>, pub session_keys_map: BTreeMap<AccountId, SessionKeys>, - pub smith_certs_by_receiver: BTreeMap<u32, BTreeMap<u32, Option<u32>>>, - pub smith_memberships: BTreeMap<u32, MembershipData>, + pub initial_smiths: BTreeMap<u32, (bool, Vec<u32>)>, pub sudo_key: Option<AccountId>, pub technical_committee_members: Vec<AccountId>, pub ud: u64, @@ -235,9 +234,8 @@ struct CliqueSmith { session_keys: Option<String>, } -struct SmithWoT<SK: Decode> { - smith_certs_by_receiver: BTreeMap<u32, BTreeMap<u32, Option<u32>>>, - smith_memberships: BTreeMap<u32, sp_membership::MembershipData<u32>>, +struct SmithMembers<SK: Decode> { + initial_smiths_wot: BTreeMap<u32, (bool, Vec<u32>)>, session_keys_map: BTreeMap<<<MultiSignature as Verify>::Signer as IdentifyAccount>::AccountId, SK>, } @@ -249,7 +247,7 @@ struct GenesisInfo<'a> { inactive_identities: &'a HashMap<u32, String>, identities: &'a Vec<GenesisIdentity>, identity_index: &'a HashMap<u32, String>, - smith_memberships: &'a BTreeMap<u32, MembershipData>, + initial_smiths: &'a BTreeMap<u32, (bool, Vec<u32>)>, counter_online_authorities: &'a u32, counter_cert: &'a u32, counter_smith_cert: &'a u32, @@ -395,16 +393,14 @@ where was_fatal, counter_online_authorities, counter_smith_cert, - SmithWoT { - smith_certs_by_receiver, - smith_memberships, + SmithMembers { + initial_smiths_wot, session_keys_map, }, ) = create_smith_wot( &mut initial_authorities, &identities_v2, &smiths, - &common_parameters, &clique_smiths, )?; if was_fatal { @@ -429,7 +425,7 @@ where } // Verify smith certifications coherence - for (idty_index, certs) in &smith_certs_by_receiver { + for (idty_index, (_online, certs)) in &initial_smiths_wot { if certs.len() < common_parameters.smith_sub_wot_min_cert_for_membership as usize { log::error!( "[{}] has received only {}/{} smith certifications", @@ -515,7 +511,7 @@ where identities: &identities, inactive_identities: &inactive_identities, identity_index: &identity_index, - smith_memberships: &smith_memberships, + initial_smiths: &initial_smiths_wot, counter_online_authorities: &counter_online_authorities, counter_cert: &counter_cert, counter_smith_cert: &counter_smith_cert, @@ -637,8 +633,8 @@ where identities.len() - inactive_identities.len(), memberships.len() ); - assert_eq!(smith_memberships.len(), initial_authorities.len()); - assert_eq!(smith_memberships.len(), session_keys_map.len()); + assert_eq!(initial_smiths_wot.len(), initial_authorities.len()); + assert_eq!(initial_smiths_wot.len(), session_keys_map.len()); assert_eq!(identity_index.len(), identities.len()); assert_eq!( accounts.len(), @@ -657,7 +653,6 @@ where // genesis_certs_min_received => min_cert // genesis_memberships_expire_on => membership_period // genesis_smith_certs_min_received => smith_min_cert - // genesis_smith_memberships_expire_on => smith_membership_period let export = GenesisIndexerExport { first_ud, first_ud_reeval, @@ -730,8 +725,7 @@ where parameters, common_parameters: Some(common_parameters), session_keys_map, - smith_certs_by_receiver, - smith_memberships, + initial_smiths: initial_smiths_wot, sudo_key, technical_committee_members, ud, @@ -759,7 +753,7 @@ fn dump_genesis_info(info: GenesisInfo) { info.identity_index.len(), info.identities.len() - info.inactive_identities.len(), info.inactive_identities.len(), - info.smith_memberships.len(), + info.initial_smiths.len(), info.counter_online_authorities, info.counter_cert, info.counter_smith_cert, @@ -829,28 +823,15 @@ fn dump_genesis_info(info: GenesisInfo) { get_best_unit_and_diviser_for_perbill(p.distance_min_accessible_referees); let (distance_max_depth, distance_max_depth_unit) = get_best_unit_and_diviser_for_depth(p.distance_max_depth); - let (smith_sub_wot_first_issuable_on, smith_sub_wot_first_issuable_on_unit) = - get_best_unit_and_diviser_for_blocks(p.smith_sub_wot_first_issuable_on); - let (smith_sub_wot_min_cert_for_membership, smith_sub_wot_min_cert_for_membership_unit) = + let (smith_members_min_cert_for_membership, smith_members_min_cert_for_membership_unit) = get_best_unit_and_diviser_for_certs(p.smith_sub_wot_min_cert_for_membership); - let (smith_membership_membership_period, smith_membership_membership_period_unit) = - get_best_unit_and_diviser_for_blocks(p.smith_membership_membership_period); - let ( - smith_membership_pending_membership_period, - smith_membership_pending_membership_period_unit, - ) = get_best_unit_and_diviser_for_blocks(p.smith_membership_pending_membership_period); - let (smith_cert_cert_period, smith_cert_cert_period_unit) = - get_best_unit_and_diviser_for_blocks(p.smith_cert_cert_period); - let (smith_cert_max_by_issuer, smith_cert_max_by_issuer_unit) = + let (smith_members_max_by_issuer, smith_members_max_by_issuer_unit) = get_best_unit_and_diviser_for_certs(p.smith_cert_max_by_issuer); - let ( - smith_cert_min_received_cert_to_be_able_to_issue_cert, - smith_cert_min_received_cert_to_be_able_to_issue_cert_unit, - ) = get_best_unit_and_diviser_for_certs( - p.smith_cert_min_received_cert_to_be_able_to_issue_cert, - ); - let (smith_cert_validity_period, smith_cert_validity_period_unit) = - get_best_unit_and_diviser_for_blocks(p.smith_cert_validity_period); + let (smith_members_inactivity_max_duration, smith_members_inactivity_max_duration_unit) = + get_best_unit_and_diviser_for_sessions( + p.smith_inactivity_max_duration, + p.babe_epoch_duration, + ); let (treasury_spend_period, treasury_spend_period_unit) = get_best_unit_and_diviser_for_blocks(p.treasury_spend_period); @@ -883,14 +864,9 @@ fn dump_genesis_info(info: GenesisInfo) { - cert.validity_period: {} {} - distance.min_accessible_referees: {} {} - distance.max_depth: {} {}, - - smith_sub_wot.first_issuable_on: {} {} - - smith_sub_wot.min_cert_for_membership: {} {} - - smith_membership.membership_period: {} {} - - smith_membership.pending_membership_period: {} {} - - smith_cert.cert_period: {} {} - - smith_cert.max_by_issuer: {} {} - - smith_cert.min_received_cert_to_be_able_to_issue_cert: {} {} - - smith_cert.validity_period: {} {} + - smith_members.min_cert_for_membership: {} {} + - smith_members.max_by_issuer: {} {} + - smith_members.smith_inactivity_max_duration: {} {} - treasury.spend_period: {} {} - currency decimals: {}", babe_epoch_duration, @@ -945,22 +921,12 @@ fn dump_genesis_info(info: GenesisInfo) { distance_min_accessible_referees_unit, distance_max_depth, distance_max_depth_unit, - smith_sub_wot_first_issuable_on, - smith_sub_wot_first_issuable_on_unit, - smith_sub_wot_min_cert_for_membership, - smith_sub_wot_min_cert_for_membership_unit, - smith_membership_membership_period, - smith_membership_membership_period_unit, - smith_membership_pending_membership_period, - smith_membership_pending_membership_period_unit, - smith_cert_cert_period, - smith_cert_cert_period_unit, - smith_cert_max_by_issuer, - smith_cert_max_by_issuer_unit, - smith_cert_min_received_cert_to_be_able_to_issue_cert, - smith_cert_min_received_cert_to_be_able_to_issue_cert_unit, - smith_cert_validity_period, - smith_cert_validity_period_unit, + smith_members_min_cert_for_membership, + smith_members_min_cert_for_membership_unit, + smith_members_max_by_issuer, + smith_members_max_by_issuer_unit, + smith_members_inactivity_max_duration, + smith_members_inactivity_max_duration_unit, treasury_spend_period, treasury_spend_period_unit, info.common_parameters.decimals, @@ -979,6 +945,16 @@ fn get_best_unit_and_diviser_for_blocks(duration_in_blocks: u32) -> (f32, String get_best_unit_and_diviser_for_ms(duration_in_ms) } +fn get_best_unit_and_diviser_for_sessions( + duration_in_sessions: u32, + babe_epoch_duration_in_blocks: u64, +) -> (f32, String) { + let duration_in_ms = duration_in_sessions as f32 + * babe_epoch_duration_in_blocks as f32 + * (MILLISECS_PER_BLOCK as u32) as f32; + get_best_unit_and_diviser_for_ms(duration_in_ms) +} + fn get_best_unit_and_diviser_for_perbill_square(qty: Perbill) -> (f32, String) { let qty = f32::sqrt(qty.deconstruct() as f32 / 1_000_000_000f32) * 100f32; (qty, "%".to_string()) @@ -1073,16 +1049,14 @@ fn create_smith_wot<SK: Decode>( initial_authorities: &mut BTreeMap<u32, (AccountId32, bool)>, identities_v2: &HashMap<String, IdentityV2>, smiths: &Vec<SmithData>, - common_parameters: &CommonParameters, clique_smiths: &Option<Vec<CliqueSmith>>, -) -> Result<(bool, u32, u32, SmithWoT<SK>), String> { +) -> Result<(bool, u32, u32, SmithMembers<SK>), String> { let mut fatal = false; let mut counter_online_authorities = 0; // counter for smith certifications let mut counter_smith_cert = 0; let mut smith_certs_by_receiver = BTreeMap::new(); // smith memberships - let mut smith_memberships = BTreeMap::new(); let mut session_keys_map = BTreeMap::new(); // Then create the smith WoT for smith in smiths { @@ -1103,16 +1077,7 @@ fn create_smith_wot<SK: Decode>( &smith, identity, &identities_v2_clone, - common_parameters, )?; - - // smith memberships - smith_memberships.insert( - identity.index, - MembershipData { - expire_on: common_parameters.smith_membership_membership_period, - }, - ); } else { log::error!( "Smith '{}' does not correspond to exising identity", @@ -1125,9 +1090,18 @@ fn create_smith_wot<SK: Decode>( fatal, counter_online_authorities, counter_smith_cert, - SmithWoT { - smith_certs_by_receiver, - smith_memberships, + SmithMembers { + initial_smiths_wot: smith_certs_by_receiver + .iter() + .map(|(k, v)| { + let is_online = initial_authorities + .iter() + .filter(|(k2, (_, online))| *k2 == k && *online) + .count() + > 0; + (*k, (is_online, v.clone())) + }) + .collect(), session_keys_map, }, )) @@ -1549,15 +1523,14 @@ where } fn feed_smith_certs_by_receiver( - smith_certs_by_receiver: &mut BTreeMap<u32, BTreeMap<u32, Option<u32>>>, + smith_certs_by_receiver: &mut BTreeMap<u32, Vec<u32>>, clique_smiths: &Option<Vec<CliqueSmith>>, smith: &&SmithData, identity: &IdentityV2, identities_v2: &HashMap<String, IdentityV2>, - common_parameters: &CommonParameters, ) -> Result<u32, String> { let mut counter_smith_cert = 0; - let mut certs = BTreeMap::new(); + let mut certs = Vec::<u32>::new(); if clique_smiths.is_some() { // All initial smiths are considered to be certifying all each other clique_smiths @@ -1572,7 +1545,7 @@ fn feed_smith_certs_by_receiver( panic!("Identity '{}' does not exist", other_smith.name.as_str()) }) .index; - certs.insert(*issuer_index, None); + certs.push(*issuer_index); counter_smith_cert += 1; }); } else { @@ -1581,10 +1554,7 @@ fn feed_smith_certs_by_receiver( .get(issuer) .ok_or(format!("Identity '{}' does not exist", issuer))? .index; - certs.insert( - *issuer_index, - Some(common_parameters.smith_cert_validity_period), - ); + certs.push(*issuer_index); counter_smith_cert += 1; } } @@ -1767,11 +1737,11 @@ where let genesis_data_wallets_count = 0; let inactive_identities = HashMap::new(); - let smith_memberships = (1..=initial_smiths_len) - .map(|i| (i as u32, MembershipData { expire_on: 0 })) - .collect(); - - let (smith_certs_by_receiver, counter_smith_cert) = clique_wot(initial_smiths_len); + let initial_smiths_wot: BTreeMap<u32, (bool, Vec<u32>)> = clique_smith_wot(initial_smiths_len); + let counter_smith_cert = initial_smiths_wot + .iter() + .map(|(_, (_, v))| v.len()) + .sum::<usize>() as u32; let initial_authorities: BTreeMap< u32, @@ -1808,7 +1778,7 @@ where identities: &identities, inactive_identities: &inactive_identities, identity_index: &identity_index, - smith_memberships: &smith_memberships, + initial_smiths: &initial_smiths_wot, counter_online_authorities: &counter_online_authorities, counter_cert: &counter_cert, counter_smith_cert: &counter_smith_cert, @@ -1834,8 +1804,7 @@ where parameters, common_parameters: None, session_keys_map, - smith_certs_by_receiver, - smith_memberships, + initial_smiths: initial_smiths_wot, sudo_key: Some(root_key), technical_committee_members, ud, @@ -1871,6 +1840,23 @@ fn clique_wot( (certs_by_issuer, count) } +#[cfg(feature = "gdev")] +fn clique_smith_wot(initial_identities_len: usize) -> BTreeMap<IdtyIndex, (bool, Vec<IdtyIndex>)> { + let mut certs_by_issuer = BTreeMap::new(); + for i in 1..=initial_identities_len { + certs_by_issuer.insert( + i as IdtyIndex, + ( + true, + (1..=initial_identities_len) + .filter_map(|j| if i != j { Some(j as IdtyIndex) } else { None }) + .collect(), + ), + ); + } + certs_by_issuer +} + fn check_parameters_consistency( wallets: &BTreeMap<PubkeyV1, u64>, first_ud: &Option<u64>, @@ -1999,14 +1985,9 @@ pub struct CommonParameters { pub cert_validity_period: u32, pub distance_min_accessible_referees: Perbill, pub distance_max_depth: u32, - pub smith_sub_wot_first_issuable_on: u32, pub smith_sub_wot_min_cert_for_membership: u32, - pub smith_membership_membership_period: u32, - pub smith_membership_pending_membership_period: u32, - pub smith_cert_cert_period: u32, pub smith_cert_max_by_issuer: u32, - pub smith_cert_min_received_cert_to_be_able_to_issue_cert: u32, - pub smith_cert_validity_period: u32, + pub smith_inactivity_max_duration: u32, pub treasury_spend_period: u32, // TODO: replace u32 by BlockNumber when appropriate pub currency_name: String, diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs index 796b2c7de224df2f3422af8097065389ac3e534c..4b1ee27f2b5b4842cfd04082099e1cb876fef9f8 100644 --- a/node/src/chain_spec/gtest.rs +++ b/node/src/chain_spec/gtest.rs @@ -20,12 +20,12 @@ use common_runtime::constants::*; use common_runtime::entities::IdtyData; use common_runtime::*; use frame_benchmarking::frame_support::traits::Get; +use gtest_runtime::SmithMembersConfig; use gtest_runtime::{ opaque::SessionKeys, pallet_universal_dividend, parameters, AccountConfig, AccountId, AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig, GenesisConfig, IdentityConfig, - ImOnlineId, MembershipConfig, Perbill, QuotaConfig, Runtime, SessionConfig, SmithCertConfig, - SmithMembershipConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, - UniversalDividendConfig, WASM_BINARY, + ImOnlineId, MembershipConfig, Perbill, QuotaConfig, Runtime, SessionConfig, SudoConfig, + SystemConfig, TechnicalCommitteeConfig, UniversalDividendConfig, WASM_BINARY, }; use jsonrpsee::core::JsonValue; use sc_consensus_grandpa::AuthorityId as GrandpaId; @@ -98,15 +98,9 @@ fn get_parameters(_: &Option<GenesisParameters>) -> CommonParameters { cert_validity_period: parameters::ValidityPeriod::get(), distance_min_accessible_referees: Perbill::from_percent(80), // TODO: generalize distance_max_depth: 5, // TODO: generalize - smith_sub_wot_first_issuable_on: parameters::SmithWotFirstCertIssuableOn::get(), smith_sub_wot_min_cert_for_membership: parameters::SmithWotMinCertForMembership::get(), - smith_membership_membership_period: parameters::SmithMembershipPeriod::get(), - smith_membership_pending_membership_period: parameters::SmithPendingMembershipPeriod::get(), - smith_cert_cert_period: parameters::SmithCertPeriod::get(), + smith_inactivity_max_duration: parameters::SmithInactivityMaxDuration::get(), smith_cert_max_by_issuer: parameters::SmithMaxByIssuer::get(), - smith_cert_min_received_cert_to_be_able_to_issue_cert: - parameters::SmithMinReceivedCertToBeAbleToIssueCert::get(), - smith_cert_validity_period: parameters::SmithValidityPeriod::get(), cert_cert_period: parameters::CertPeriod::get(), treasury_spend_period: <Runtime as pallet_treasury::Config>::SpendPeriod::get(), } @@ -239,8 +233,7 @@ fn genesis_data_to_gtest_genesis_conf( parameters: _, common_parameters: _, session_keys_map, - smith_certs_by_receiver, - smith_memberships, + initial_smiths, sudo_key, technical_committee_members, ud, @@ -313,13 +306,7 @@ fn genesis_data_to_gtest_genesis_conf( certs_by_receiver, }, membership: MembershipConfig { memberships }, - smith_cert: SmithCertConfig { - apply_cert_period_at_genesis: true, - certs_by_receiver: smith_certs_by_receiver, - }, - smith_membership: SmithMembershipConfig { - memberships: smith_memberships, - }, + smith_members: SmithMembersConfig { initial_smiths }, universal_dividend: UniversalDividendConfig { first_reeval: first_ud_reeval, first_ud, diff --git a/pallets/authority-members/src/impls.rs b/pallets/authority-members/src/impls.rs index ade9f7437bcf80a0e396625d44530c901841dd35..d656f01e6d905427015a02697b026fd54ff036eb 100644 --- a/pallets/authority-members/src/impls.rs +++ b/pallets/authority-members/src/impls.rs @@ -20,7 +20,6 @@ //! The offences are executed here based. The offenders are disconnected and //! can be added to a blacklist to avoid futur connection. -#![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::type_complexity)] use super::pallet::*; @@ -54,9 +53,8 @@ where match strategy { SlashStrategy::Blacklist => { for offender in offenders { - Blacklist::<T>::mutate(|blacklist| { - if let Some(member_id) = T::MemberIdOf::convert(offender.offender.0.clone()) - { + if let Some(member_id) = T::MemberIdOf::convert(offender.offender.0.clone()) { + Blacklist::<T>::mutate(|blacklist| { if !blacklist.contains(&member_id) { blacklist.push(member_id); Self::deposit_event(Event::MemberAddedToBlacklist { @@ -66,8 +64,8 @@ where } Self::insert_out(member_id); add_db_reads_writes(2, 1); - } - }) + }); + } } } SlashStrategy::Disconnect => { diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs index 29c4ecaab49aa3d4c114c5021a892d6bd89fb563..d4ebf6b3fd4a919e055e2f5e72e8c2692e992cf7 100644 --- a/pallets/authority-members/src/lib.rs +++ b/pallets/authority-members/src/lib.rs @@ -51,6 +51,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_runtime::traits::{Convert, IsMember}; use sp_std::collections::btree_map::BTreeMap; + use sp_std::vec; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -68,7 +69,8 @@ pub mod pallet { { type IsMember: IsMember<Self::MemberId>; type OnNewSession: OnNewSession; - type OnRemovedMember: OnRemovedMember<Self::MemberId>; + type OnOutgoingMember: OnOutgoingMember<Self::MemberId>; + type OnIncomingMember: OnIncomingMember<Self::MemberId>; /// Max number of authorities allowed #[pallet::constant] type MaxAuthorities: Get<u32>; @@ -401,7 +403,6 @@ pub mod pallet { // Emit event Self::deposit_event(Event::MemberRemoved { member: member_id }); - T::OnRemovedMember::on_removed_member(member_id); } /// perform incoming authorities insertion fn insert_in(member_id: T::MemberId) -> bool { @@ -513,20 +514,23 @@ impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> { let members_ids_to_add = IncomingAuthorities::<T>::take(); let members_ids_to_del = OutgoingAuthorities::<T>::take(); - if members_ids_to_add.is_empty() { - if members_ids_to_del.is_empty() { - // when no change to the set of autorities, return None - return None; - } else { - Self::deposit_event(Event::OutgoingAuthorities { - members: members_ids_to_del.clone(), - }); - } - } else { + if members_ids_to_add.is_empty() && members_ids_to_del.is_empty() { + // when no change to the set of autorities, return None + return None; + } + + for member_id in members_ids_to_add.iter() { + T::OnIncomingMember::on_incoming_member(*member_id); Self::deposit_event(Event::IncomingAuthorities { members: members_ids_to_add.clone(), }); } + for member_id in members_ids_to_del.iter() { + T::OnOutgoingMember::on_outgoing_member(*member_id); + Self::deposit_event(Event::OutgoingAuthorities { + members: members_ids_to_del.clone(), + }); + } // updates the list of OnlineAuthorities and returns the list of their key Some( diff --git a/pallets/authority-members/src/mock.rs b/pallets/authority-members/src/mock.rs index d04f0f47f89905eb13f211dcfd58098887743239..4c818534a42d84227b1542ed68dc29f4c449804a 100644 --- a/pallets/authority-members/src/mock.rs +++ b/pallets/authority-members/src/mock.rs @@ -156,10 +156,11 @@ impl pallet_authority_members::Config for Test { type MemberId = u64; type MemberIdOf = ConvertInto; type OnNewSession = (); - type OnRemovedMember = (); type RemoveMemberOrigin = system::EnsureRoot<u64>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + type OnIncomingMember = (); + type OnOutgoingMember = (); } // Build genesis storage according to the mock runtime. diff --git a/pallets/authority-members/src/traits.rs b/pallets/authority-members/src/traits.rs index 81f36396e9e1b5f3cd4baebc3c07c6c4f013365e..2bb98f77d134a8e3e6f6b45c53c88626309ee330 100644 --- a/pallets/authority-members/src/traits.rs +++ b/pallets/authority-members/src/traits.rs @@ -24,10 +24,22 @@ impl OnNewSession for () { fn on_new_session(_: SessionIndex) {} } -pub trait OnRemovedMember<MemberId> { - fn on_removed_member(member_id: MemberId); +/// Handle the consequences of going in the authority set for other pallets. +/// Typically, a smith won't expire as long as he is in the authority set. +pub trait OnIncomingMember<MemberId> { + fn on_incoming_member(member_id: MemberId); +} +/// By default: no consequences +impl<MemberId> OnIncomingMember<MemberId> for () { + fn on_incoming_member(_: MemberId) {} } -impl<MemberId> OnRemovedMember<MemberId> for () { - fn on_removed_member(_: MemberId) {} +/// Handle the consequences of going out of authority set for other pallets. +/// Typically, the smiths are not allowed to stay offline for a too long time. +pub trait OnOutgoingMember<MemberId> { + fn on_outgoing_member(member_id: MemberId); +} +/// By default: no consequences +impl<MemberId> OnOutgoingMember<MemberId> for () { + fn on_outgoing_member(_: MemberId) {} } diff --git a/pallets/certification/src/benchmarking.rs b/pallets/certification/src/benchmarking.rs index 4a4b61a8e812d97c676ae190d43aa5512a0ccfab..553e34846ae9c1a99e68c5ee677ffbd126c50979 100644 --- a/pallets/certification/src/benchmarking.rs +++ b/pallets/certification/src/benchmarking.rs @@ -18,7 +18,7 @@ use super::*; -use frame_benchmarking::benchmarks_instance_pallet; +use frame_benchmarking::benchmarks; use frame_benchmarking::Zero; use frame_system::RawOrigin; use sp_runtime::traits::Convert; @@ -28,23 +28,23 @@ use maplit::btreemap; use crate::Pallet; -fn assert_has_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) { +fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) { frame_system::Pallet::<T>::assert_has_event(generic_event.into()); } -fn add_certs<T: Config<I>, I: 'static>(i: u32, receiver: T::IdtyIndex) -> Result<(), &'static str> { - Pallet::<T, I>::remove_all_certs_received_by(RawOrigin::Root.into(), receiver)?; +fn add_certs<T: Config>(i: u32, receiver: T::IdtyIndex) -> Result<(), &'static str> { + Pallet::<T>::remove_all_certs_received_by(RawOrigin::Root.into(), receiver)?; for j in 1..i { - Pallet::<T, I>::do_add_cert_checked(j.into(), receiver, false)?; + Pallet::<T>::do_add_cert_checked(j.into(), receiver, false)?; } assert!( - CertsByReceiver::<T, I>::get(receiver).len() as u32 == i - 1, + CertsByReceiver::<T>::get(receiver).len() as u32 == i - 1, "Certs not added", ); Ok(()) } -benchmarks_instance_pallet! { +benchmarks! { where_clause { where T::IdtyIndex: From<u32>, @@ -54,47 +54,47 @@ benchmarks_instance_pallet! { let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); let receiver: T::IdtyIndex = 2.into(); - Pallet::<T, I>::del_cert(RawOrigin::Root.into(), issuer, receiver)?; - let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count; - let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count; + Pallet::<T>::del_cert(RawOrigin::Root.into(), issuer, receiver)?; + let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count; + let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count; frame_system::pallet::Pallet::<T>::set_block_number(T::CertPeriod::get()); }: _<T::RuntimeOrigin>(caller_origin, issuer, receiver) verify { - assert_has_event::<T, I>(Event::<T, I>::CertAdded{ issuer, receiver }.into()); + assert_has_event::<T>(Event::<T>::CertAdded{ issuer, receiver }.into()); } del_cert { let issuer: T::IdtyIndex = 1.into(); let receiver: T::IdtyIndex = 0.into(); - Pallet::<T, I>::do_add_cert_checked(issuer, receiver, false)?; - let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count; - let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count; + Pallet::<T>::do_add_cert_checked(issuer, receiver, false)?; + let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count; + let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count; }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), issuer, receiver) verify { - assert_has_event::<T, I>(Event::<T, I>::CertRemoved{ issuer, receiver, expiration: false }.into()); + assert_has_event::<T>(Event::<T>::CertRemoved{ issuer, receiver, expiration: false }.into()); } remove_all_certs_received_by { let receiver: T::IdtyIndex = 0.into(); - let i in 2..1000 => add_certs::<T, I>(i, receiver)?; + let i in 2..1000 => add_certs::<T>(i, receiver)?; }: _<T::RuntimeOrigin>(RawOrigin::Root.into(), receiver) verify { - assert!(CertsByReceiver::<T, I>::get(receiver).is_empty() ); + assert!(CertsByReceiver::<T>::get(receiver).is_empty() ); } on_initialize { - assert!(StorageCertsRemovableOn::<T, I>::try_get(T::BlockNumber::zero()).is_err()); - }: {Pallet::<T, I>::on_initialize(T::BlockNumber::zero());} + assert!(StorageCertsRemovableOn::<T>::try_get(T::BlockNumber::zero()).is_err()); + }: {Pallet::<T>::on_initialize(T::BlockNumber::zero());} do_remove_cert_noop { - }: {Pallet::<T, I>::do_remove_cert(100.into(), 101.into(), Some(T::BlockNumber::zero()));} + }: {Pallet::<T>::do_remove_cert(100.into(), 101.into(), Some(T::BlockNumber::zero()));} do_remove_cert { let issuer: T::IdtyIndex = 1.into(); let receiver: T::IdtyIndex = 0.into(); - Pallet::<T, I>::do_add_cert_checked(issuer, receiver, false)?; - let issuer_cert: u32 = StorageIdtyCertMeta::<T, I>::get(issuer).issued_count; - let receiver_cert: u32 = StorageIdtyCertMeta::<T, I>::get(receiver).received_count; + Pallet::<T>::do_add_cert_checked(issuer, receiver, false)?; + let issuer_cert: u32 = StorageIdtyCertMeta::<T>::get(issuer).issued_count; + let receiver_cert: u32 = StorageIdtyCertMeta::<T>::get(receiver).received_count; let block_number = T::ValidityPeriod::get(); frame_system::pallet::Pallet::<T>::set_block_number(block_number); - }: {Pallet::<T, I>::do_remove_cert(issuer, receiver, Some(block_number));} + }: {Pallet::<T>::do_remove_cert(issuer, receiver, Some(block_number));} verify { - assert_has_event::<T, I>(Event::<T, I>::CertRemoved{ issuer, receiver, expiration: true }.into()); + assert_has_event::<T>(Event::<T>::CertRemoved{ issuer, receiver, expiration: true }.into()); } impl_benchmark_test_suite!( diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs index fd60d814e7e8cef3591f1e174c434637267ec90e..aab81a26417bc6e1c7a4e4459537e121c840e140 100644 --- a/pallets/certification/src/lib.rs +++ b/pallets/certification/src/lib.rs @@ -53,10 +53,10 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] - pub struct Pallet<T, I = ()>(PhantomData<(T, I)>); + pub struct Pallet<T>(PhantomData<T>); #[pallet::config] - pub trait Config<I: 'static = ()>: frame_system::Config { + pub trait Config: frame_system::Config { #[pallet::constant] /// Minimum duration between two certifications issued by the same issuer type CertPeriod: Get<Self::BlockNumber>; @@ -86,8 +86,7 @@ pub mod pallet { /// Handler for Removed event type OnRemovedCert: OnRemovedCert<Self::IdtyIndex>; /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From<Event<Self, I>> - + IsType<<Self as frame_system::Config>::RuntimeEvent>; + type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; /// Type representing the weight of this pallet type WeightInfo: WeightInfo; #[pallet::constant] @@ -99,14 +98,14 @@ pub mod pallet { #[pallet::genesis_config] #[allow(clippy::type_complexity)] - pub struct GenesisConfig<T: Config<I>, I: 'static = ()> { + pub struct GenesisConfig<T: Config> { pub apply_cert_period_at_genesis: bool, pub certs_by_receiver: BTreeMap<T::IdtyIndex, BTreeMap<T::IdtyIndex, Option<T::BlockNumber>>>, } #[cfg(feature = "std")] - impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> { + impl<T: Config> Default for GenesisConfig<T> { fn default() -> Self { Self { apply_cert_period_at_genesis: false, @@ -116,7 +115,7 @@ pub mod pallet { } #[pallet::genesis_build] - impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> { + impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { fn build(&self) { let mut cert_meta_by_issuer = BTreeMap::<T::IdtyIndex, IdtyCertMeta<T::BlockNumber>>::new(); @@ -175,7 +174,7 @@ pub mod pallet { // Write CertsByReceiver issuers_.sort(); - CertsByReceiver::<T, I>::insert(receiver, issuers_); + CertsByReceiver::<T>::insert(receiver, issuers_); } // Write StorageIdtyCertMeta @@ -190,11 +189,11 @@ pub mod pallet { "Identity n°{:?} not respect MinReceivedCertToBeAbleToIssueCert.", issuer ); - StorageIdtyCertMeta::<T, I>::insert(issuer, cert_meta); + StorageIdtyCertMeta::<T>::insert(issuer, cert_meta); } // Write storage StorageCertsRemovableOn for (removable_on, certs) in certs_removable_on { - StorageCertsRemovableOn::<T, I>::insert(removable_on, certs); + StorageCertsRemovableOn::<T>::insert(removable_on, certs); } } } @@ -204,26 +203,26 @@ pub mod pallet { /// Certifications metada by issuer #[pallet::storage] #[pallet::getter(fn idty_cert_meta)] - pub type StorageIdtyCertMeta<T: Config<I>, I: 'static = ()> = + pub type StorageIdtyCertMeta<T: Config> = StorageMap<_, Twox64Concat, T::IdtyIndex, IdtyCertMeta<T::BlockNumber>, ValueQuery>; /// Certifications by receiver #[pallet::storage] #[pallet::getter(fn certs_by_receiver)] - pub type CertsByReceiver<T: Config<I>, I: 'static = ()> = + pub type CertsByReceiver<T: Config> = StorageMap<_, Twox64Concat, T::IdtyIndex, Vec<(T::IdtyIndex, T::BlockNumber)>, ValueQuery>; /// Certifications removable on #[pallet::storage] #[pallet::getter(fn certs_removable_on)] - pub type StorageCertsRemovableOn<T: Config<I>, I: 'static = ()> = + pub type StorageCertsRemovableOn<T: Config> = StorageMap<_, Twox64Concat, T::BlockNumber, Vec<(T::IdtyIndex, T::IdtyIndex)>, OptionQuery>; // EVENTS // #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event<T: Config<I>, I: 'static = ()> { + pub enum Event<T: Config> { /// A new certification was added. CertAdded { issuer: T::IdtyIndex, @@ -245,7 +244,7 @@ pub mod pallet { // ERRORS // #[pallet::error] - pub enum Error<T, I = ()> { + pub enum Error<T> { /// Identity cannot certify itself CannotCertifySelf, /// Identity has already issued the maximum number of certifications @@ -259,7 +258,7 @@ pub mod pallet { } #[pallet::hooks] - impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> { + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { fn on_initialize(n: T::BlockNumber) -> Weight { Self::prune_certifications(n).saturating_add(T::WeightInfo::on_initialize()) } @@ -268,7 +267,7 @@ pub mod pallet { // CALLS // #[pallet::call] - impl<T: Config<I>, I: 'static> Pallet<T, I> { + impl<T: Config> Pallet<T> { /// Add a new certification or renew an existing one /// /// - `receiver`: the account receiving the certification from the origin @@ -303,13 +302,13 @@ pub mod pallet { /// remove all certifications received by an identity (only root) #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::remove_all_certs_received_by(CertsByReceiver::<T, I>::get(idty_index).len() as u32))] + #[pallet::weight(T::WeightInfo::remove_all_certs_received_by(CertsByReceiver::<T>::get(idty_index).len() as u32))] pub fn remove_all_certs_received_by( origin: OriginFor<T>, idty_index: T::IdtyIndex, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - for (issuer, _) in CertsByReceiver::<T, I>::get(idty_index) { + for (issuer, _) in CertsByReceiver::<T>::get(idty_index) { Self::do_remove_cert(issuer, idty_index, None); } Ok(().into()) @@ -318,7 +317,7 @@ pub mod pallet { // INTERNAL FUNCTIONS // - impl<T: Config<I>, I: 'static> Pallet<T, I> { + impl<T: Config> Pallet<T> { /// add a certification without checks pub fn do_add_cert_checked( issuer: T::IdtyIndex, @@ -326,29 +325,29 @@ pub mod pallet { verify_rules: bool, ) -> DispatchResultWithPostInfo { // Forbid self cert - ensure!(issuer != receiver, Error::<T, I>::CannotCertifySelf); + ensure!(issuer != receiver, Error::<T>::CannotCertifySelf); let block_number = frame_system::pallet::Pallet::<T>::block_number(); if verify_rules { // Verify rule MinReceivedCertToBeAbleToIssueCert - let issuer_idty_cert_meta = StorageIdtyCertMeta::<T, I>::get(issuer); + let issuer_idty_cert_meta = StorageIdtyCertMeta::<T>::get(issuer); ensure!( issuer_idty_cert_meta.received_count >= T::MinReceivedCertToBeAbleToIssueCert::get(), - Error::<T, I>::NotEnoughCertReceived + Error::<T>::NotEnoughCertReceived ); // Verify rule MaxByIssuer ensure!( issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(), - Error::<T, I>::IssuedTooManyCert + Error::<T>::IssuedTooManyCert ); // Verify rule CertPeriod ensure!( block_number >= issuer_idty_cert_meta.next_issuable_on, - Error::<T, I>::NotRespectCertPeriod + Error::<T>::NotRespectCertPeriod ); }; @@ -362,11 +361,11 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { // Write StorageCertsRemovableOn let removable_on = block_number + T::ValidityPeriod::get(); - <StorageCertsRemovableOn<T, I>>::append(removable_on, (issuer, receiver)); + <StorageCertsRemovableOn<T>>::append(removable_on, (issuer, receiver)); // Write CertsByReceiver let mut created = false; - CertsByReceiver::<T, I>::mutate_exists(receiver, |maybe_issuers| { + CertsByReceiver::<T>::mutate_exists(receiver, |maybe_issuers| { let issuers = maybe_issuers.get_or_insert(Vec::with_capacity(0)); match issuers.binary_search_by(|(issuer_, _)| issuer_.cmp(&issuer)) { // cert exists, must be renewed @@ -384,7 +383,7 @@ pub mod pallet { if created { // Write StorageIdtyCertMeta for issuer let issuer_issued_count = - StorageIdtyCertMeta::<T, I>::mutate(issuer, |issuer_idty_cert_meta| { + StorageIdtyCertMeta::<T>::mutate(issuer, |issuer_idty_cert_meta| { issuer_idty_cert_meta.issued_count = issuer_idty_cert_meta.issued_count.saturating_add(1); issuer_idty_cert_meta.next_issuable_on = @@ -394,7 +393,7 @@ pub mod pallet { // Write StorageIdtyCertMeta for receiver let receiver_received_count = - <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| { + <StorageIdtyCertMeta<T>>::mutate_exists(receiver, |cert_meta_opt| { let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default()); cert_meta.received_count = cert_meta.received_count.saturating_add(1); cert_meta.received_count @@ -410,7 +409,7 @@ pub mod pallet { ); } else { // Update next_issuable_on in StorageIdtyCertMeta for issuer - StorageIdtyCertMeta::<T, I>::mutate(issuer, |issuer_idty_cert_meta| { + StorageIdtyCertMeta::<T>::mutate(issuer, |issuer_idty_cert_meta| { issuer_idty_cert_meta.next_issuable_on = block_number + T::CertPeriod::get(); }); // emit CertRenewed event @@ -425,7 +424,7 @@ pub mod pallet { // See on initialize for the overhead weight accounting let mut total_weight = Weight::zero(); - if let Some(certs) = StorageCertsRemovableOn::<T, I>::take(block_number) { + if let Some(certs) = StorageCertsRemovableOn::<T>::take(block_number) { for (issuer, receiver) in certs { total_weight += Self::do_remove_cert(issuer, receiver, Some(block_number)); } @@ -442,7 +441,7 @@ pub mod pallet { ) -> Weight { let mut total_weight = Weight::zero(); let mut removed = false; - CertsByReceiver::<T, I>::mutate_exists(receiver, |issuers_opt| { + CertsByReceiver::<T>::mutate_exists(receiver, |issuers_opt| { let issuers = issuers_opt.get_or_insert(Vec::with_capacity(0)); if let Ok(index) = issuers.binary_search_by(|(issuer_, _)| issuer_.cmp(&issuer)) { if let Some(block_number) = block_number_opt { @@ -463,13 +462,13 @@ pub mod pallet { }); if removed { let issuer_issued_count = - <StorageIdtyCertMeta<T, I>>::mutate_exists(issuer, |cert_meta_opt| { + <StorageIdtyCertMeta<T>>::mutate_exists(issuer, |cert_meta_opt| { let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default()); cert_meta.issued_count = cert_meta.issued_count.saturating_sub(1); cert_meta.issued_count }); let receiver_received_count = - <StorageIdtyCertMeta<T, I>>::mutate_exists(receiver, |cert_meta_opt| { + <StorageIdtyCertMeta<T>>::mutate_exists(receiver, |cert_meta_opt| { let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default()); cert_meta.received_count = cert_meta.received_count.saturating_sub(1); cert_meta.received_count @@ -506,32 +505,32 @@ pub mod pallet { ) -> DispatchResult { // --- first internal checks // 1. Forbid self cert - ensure!(issuer != receiver, Error::<T, I>::CannotCertifySelf); + ensure!(issuer != receiver, Error::<T>::CannotCertifySelf); // 2. Verify caller ownership let issuer_owner_key = - T::OwnerKeyOf::convert(issuer).ok_or(Error::<T, I>::IssuerNotFound)?; + T::OwnerKeyOf::convert(issuer).ok_or(Error::<T>::IssuerNotFound)?; ensure!(issuer_owner_key == caller_key, DispatchError::BadOrigin); // 3. Verify rule MinReceivedCertToBeAbleToIssueCert // (this number can differ from the one necessary to be member) - let issuer_idty_cert_meta = <StorageIdtyCertMeta<T, I>>::get(issuer); + let issuer_idty_cert_meta = <StorageIdtyCertMeta<T>>::get(issuer); ensure!( issuer_idty_cert_meta.received_count >= T::MinReceivedCertToBeAbleToIssueCert::get(), - Error::<T, I>::NotEnoughCertReceived + Error::<T>::NotEnoughCertReceived ); // 4. Verify rule MaxByIssuer ensure!( issuer_idty_cert_meta.issued_count < T::MaxByIssuer::get(), - Error::<T, I>::IssuedTooManyCert + Error::<T>::IssuedTooManyCert ); // 5. Verify rule CertPeriod ensure!( block_number >= issuer_idty_cert_meta.next_issuable_on, - Error::<T, I>::NotRespectCertPeriod + Error::<T>::NotRespectCertPeriod ); // --- then external checks @@ -546,9 +545,9 @@ pub mod pallet { } // implement setting next_issuable_on for certification period -impl<T: Config<I>, I: 'static> SetNextIssuableOn<T::BlockNumber, T::IdtyIndex> for Pallet<T, I> { +impl<T: Config> SetNextIssuableOn<T::BlockNumber, T::IdtyIndex> for Pallet<T> { fn set_next_issuable_on(idty_index: T::IdtyIndex, next_issuable_on: T::BlockNumber) { - <StorageIdtyCertMeta<T, I>>::mutate_exists(idty_index, |cert_meta_opt| { + <StorageIdtyCertMeta<T>>::mutate_exists(idty_index, |cert_meta_opt| { let cert_meta = cert_meta_opt.get_or_insert(IdtyCertMeta::default()); cert_meta.next_issuable_on = next_issuable_on; }); diff --git a/pallets/certification/src/tests.rs b/pallets/certification/src/tests.rs index cf09fa72de745ddf9eafd3eaa9718866b196cfcd..c1abd06b9df5ea8d9c16ea9cdbdde820f02e776e 100644 --- a/pallets/certification/src/tests.rs +++ b/pallets/certification/src/tests.rs @@ -29,7 +29,7 @@ fn test_must_receive_cert_before_can_issue() { .execute_with(|| { assert_eq!( DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 1), - Err(Error::<Test, _>::NotEnoughCertReceived.into()) + Err(Error::<Test>::NotEnoughCertReceived.into()) ); }); } @@ -50,7 +50,7 @@ fn test_cannot_certify_self() { assert_eq!( DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 0), - Err(Error::<Test, _>::CannotCertifySelf.into()) + Err(Error::<Test>::CannotCertifySelf.into()) ); }); } @@ -152,7 +152,7 @@ fn test_cert_period() { ); assert_eq!( DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 3), - Err(Error::<Test, _>::NotRespectCertPeriod.into()) + Err(Error::<Test>::NotRespectCertPeriod.into()) ); run_to_block(CertPeriod::get()); assert_ok!(DefaultCertification::add_cert( @@ -163,7 +163,7 @@ fn test_cert_period() { run_to_block(CertPeriod::get() + 1); assert_eq!( DefaultCertification::add_cert(RuntimeOrigin::signed(0), 0, 4), - Err(Error::<Test, _>::NotRespectCertPeriod.into()) + Err(Error::<Test>::NotRespectCertPeriod.into()) ); run_to_block((2 * CertPeriod::get()) + 1); assert_ok!(DefaultCertification::add_cert( @@ -290,7 +290,7 @@ fn test_cert_renewal_cert_delay() { // try to renew again assert_noop!( DefaultCertification::add_cert(RuntimeOrigin::signed(1), 1, 0), - Error::<Test, _>::NotRespectCertPeriod, + Error::<Test>::NotRespectCertPeriod, ); // no renewal event should be emitted assert_eq!(System::events().last(), None); diff --git a/pallets/distance/src/mock.rs b/pallets/distance/src/mock.rs index bcdbd095db31767691af200b13e0358a73ef8b2c..ef477a8c8fb954bf324b2b0936b092492ff05831 100644 --- a/pallets/distance/src/mock.rs +++ b/pallets/distance/src/mock.rs @@ -185,10 +185,11 @@ impl pallet_authority_members::Config for Test { type MemberId = u32; type MemberIdOf = IdentityIndexOf<Self>; type OnNewSession = (); - type OnRemovedMember = (); type RemoveMemberOrigin = system::EnsureRoot<AccountId>; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + type OnOutgoingMember = (); + type OnIncomingMember = (); } parameter_types! { diff --git a/pallets/duniter-test-parameters/src/lib.rs b/pallets/duniter-test-parameters/src/lib.rs index 0f75c3296a6272358c75333984b7f7bae308c24f..4da26974ba7202c4dce8476d415e965d54276878 100644 --- a/pallets/duniter-test-parameters/src/lib.rs +++ b/pallets/duniter-test-parameters/src/lib.rs @@ -35,6 +35,7 @@ pub mod types { BlockNumber: Default + Parameter, CertCount: Default + Parameter, PeriodCount: Default + Parameter, + SessionCount: Default + Parameter, > { pub babe_epoch_duration: PeriodCount, pub cert_period: BlockNumber, @@ -47,14 +48,9 @@ pub mod types { pub pending_membership_period: BlockNumber, pub ud_creation_period: PeriodCount, pub ud_reeval_period: PeriodCount, - pub smith_cert_period: BlockNumber, pub smith_cert_max_by_issuer: CertCount, - pub smith_cert_min_received_cert_to_issue_cert: CertCount, - pub smith_cert_validity_period: BlockNumber, - pub smith_membership_period: BlockNumber, - pub smith_pending_membership_period: BlockNumber, - pub smith_wot_first_cert_issuable_on: BlockNumber, pub smith_wot_min_cert_for_membership: CertCount, + pub smith_inactivity_max_duration: SessionCount, pub wot_first_cert_issuable_on: BlockNumber, pub wot_min_cert_for_create_idty_right: CertCount, pub wot_min_cert_for_membership: CertCount, @@ -81,20 +77,24 @@ pub mod pallet { pub trait Config: frame_system::Config { type CertCount: Default + MaybeSerializeDeserialize + Parameter; type PeriodCount: Default + MaybeSerializeDeserialize + Parameter; + type SessionCount: Default + MaybeSerializeDeserialize + Parameter; } // STORAGE // #[pallet::storage] #[pallet::getter(fn parameters)] - pub type ParametersStorage<T: Config> = - StorageValue<_, Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>, ValueQuery>; + pub type ParametersStorage<T: Config> = StorageValue< + _, + Parameters<T::BlockNumber, T::CertCount, T::PeriodCount, T::SessionCount>, + ValueQuery, + >; // GENESIS #[pallet::genesis_config] pub struct GenesisConfig<T: Config> { - pub parameters: Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>, + pub parameters: Parameters<T::BlockNumber, T::CertCount, T::PeriodCount, T::SessionCount>, } #[cfg(feature = "std")] diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs index 41ad8db138320591f987b6a4c00870164d03bd62..eb127c0cc0979c1064910b791c89d70df89f44b5 100644 --- a/pallets/duniter-wot/src/lib.rs +++ b/pallets/duniter-wot/src/lib.rs @@ -36,7 +36,6 @@ use frame_support::pallet_prelude::*; use pallet_certification::traits::SetNextIssuableOn; use pallet_identity::{IdtyEvent, IdtyStatus}; use pallet_membership::MembershipRemovalReason; -use sp_runtime::traits::IsMember; type IdtyIndex = u32; @@ -51,24 +50,22 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] - pub struct Pallet<T, I = ()>(_); + pub struct Pallet<T>(_); // CONFIG // #[pallet::config] - pub trait Config<I: 'static = ()>: + pub trait Config: frame_system::Config - + pallet_certification::Config<I, IdtyIndex = IdtyIndex> + + pallet_certification::Config<IdtyIndex = IdtyIndex> + pallet_identity::Config<IdtyIndex = IdtyIndex> - + pallet_membership::Config<I, IdtyId = IdtyIndex> + + pallet_membership::Config<IdtyId = IdtyIndex> { /// Distance evaluation provider type IsDistanceOk: IsDistanceOk<IdtyIndex>; #[pallet::constant] type FirstIssuableOn: Get<Self::BlockNumber>; #[pallet::constant] - type IsSubWot: Get<bool>; - #[pallet::constant] type MinCertForMembership: Get<u32>; #[pallet::constant] type MinCertForCreateIdtyRight: Get<u32>; @@ -76,10 +73,10 @@ pub mod pallet { // INTERNAL FUNCTIONS // - impl<T: Config<I>, I: 'static> Pallet<T, I> { + impl<T: Config> Pallet<T> { pub(super) fn do_apply_first_issuable_on(idty_index: IdtyIndex) { let block_number = frame_system::pallet::Pallet::<T>::block_number(); - pallet_certification::Pallet::<T, I>::set_next_issuable_on( + pallet_certification::Pallet::<T>::set_next_issuable_on( idty_index, block_number + T::FirstIssuableOn::get(), ); @@ -89,7 +86,7 @@ pub mod pallet { // ERRORS // #[pallet::error] - pub enum Error<T, I = ()> { + pub enum Error<T> { /// Insufficient certifications received to claim membership. NotEnoughCertsToClaimMembership, /// Distance is invalid. @@ -126,61 +123,37 @@ pub mod pallet { } // implement identity call checks -impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::CheckIdtyCallAllowed<T> - for Pallet<T, I> +impl<AccountId, T: Config> pallet_identity::traits::CheckIdtyCallAllowed<T> for Pallet<T> where - T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config<I>, + T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config, { // identity creation checks fn check_create_identity(creator: IdtyIndex) -> Result<(), DispatchError> { - // main WoT constraints - if !T::IsSubWot::get() { - let cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator); - // perform all checks - // 1. check that identity has the right to create an identity - // identity can be member with 5 certifications and still not reach identity creation threshold which could be higher (6, 7...) - ensure!( - cert_meta.received_count >= T::MinCertForCreateIdtyRight::get(), - Error::<T, I>::NotEnoughReceivedCertsToCreateIdty - ); - // 2. check that issuer can emit one more certification - // (this is only a partial check) - ensure!( - cert_meta.issued_count < T::MaxByIssuer::get(), - Error::<T, I>::MaxEmittedCertsReached - ); - // 3. check that issuer respects certification creation period - ensure!( - cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number(), - Error::<T, I>::IdtyCreationPeriodNotRespected - ); - } - // TODO (#136) make these trait implementation work on instances rather than static to avoid checking IsSubWot - // smith subwot can never prevent from creating identity - Ok(()) - } - - // identity change owner key cheks - fn change_owner_key(idty_index: IdtyIndex) -> Result<(), DispatchError> { - // sub WoT prevents from changing identity - if T::IsSubWot::get() { - ensure!( - !pallet_membership::Pallet::<T, I>::is_member(&idty_index), - Error::<T, I>::NotAllowedToChangeIdtyAddress - ); - } - // no constraints for main wot + let cert_meta = pallet_certification::Pallet::<T>::idty_cert_meta(creator); + // perform all checks + // 1. check that identity has the right to create an identity + // identity can be member with 5 certifications and still not reach identity creation threshold which could be higher (6, 7...) + ensure!( + cert_meta.received_count >= T::MinCertForCreateIdtyRight::get(), + Error::<T>::NotEnoughReceivedCertsToCreateIdty + ); + // 2. check that issuer can emit one more certification + // (this is only a partial check) + ensure!( + cert_meta.issued_count < T::MaxByIssuer::get(), + Error::<T>::MaxEmittedCertsReached + ); + // 3. check that issuer respects certification creation period + ensure!( + cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number(), + Error::<T>::IdtyCreationPeriodNotRespected + ); Ok(()) } } // implement cert call checks -impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<IdtyIndex> - for Pallet<T, I> -// TODO (#136) add the following where clause once checks can be done on pallet instance -// where -// T: pallet_membership::Config<I>, -{ +impl<T: Config> pallet_certification::traits::CheckCertAllowed<IdtyIndex> for Pallet<T> { // check the following: // - issuer has identity // - issuer identity is member @@ -192,10 +165,10 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) { ensure!( issuer_data.status == IdtyStatus::Member, - Error::<T, I>::IssuerNotMember + Error::<T>::IssuerNotMember ); } else { - return Err(Error::<T, I>::IdtyNotFound.into()); + return Err(Error::<T>::IdtyNotFound.into()); } // receiver checks @@ -204,26 +177,24 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id match receiver_data.status { // able to receive cert IdtyStatus::Unvalidated | IdtyStatus::Member | IdtyStatus::NotMember => {} - IdtyStatus::Unconfirmed => return Err(Error::<T, I>::CertToUnconfirmed.into()), - IdtyStatus::Revoked => return Err(Error::<T, I>::CertToRevoked.into()), + IdtyStatus::Unconfirmed => return Err(Error::<T>::CertToUnconfirmed.into()), + IdtyStatus::Revoked => return Err(Error::<T>::CertToRevoked.into()), }; } else { - return Err(Error::<T, I>::IdtyNotFound.into()); + return Err(Error::<T>::IdtyNotFound.into()); } Ok(()) } } // implement membership call checks -impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed<IdtyIndex> - for Pallet<T, I> -{ +impl<T: Config> sp_membership::traits::CheckMembershipCallAllowed<IdtyIndex> for Pallet<T> { // membership claim is only possible when enough certs are received (both wots) and distance is ok fn check_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> { - let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index); + let idty_cert_meta = pallet_certification::Pallet::<T>::idty_cert_meta(idty_index); ensure!( idty_cert_meta.received_count >= T::MinCertForMembership::get(), - Error::<T, I>::NotEnoughCertsToClaimMembership + Error::<T>::NotEnoughCertsToClaimMembership ); T::IsDistanceOk::is_distance_ok(idty_index)?; Ok(()) @@ -234,35 +205,31 @@ impl<T: Config<I>, I: 'static> sp_membership::traits::CheckMembershipCallAllowed if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) { ensure!( idty_value.status == IdtyStatus::Member, - Error::<T, I>::IdtyNotAllowedToRenewMembership + Error::<T>::IdtyNotAllowedToRenewMembership ); T::IsDistanceOk::is_distance_ok(idty_index)?; } else { - return Err(Error::<T, I>::IdtyNotFound.into()); + return Err(Error::<T>::IdtyNotFound.into()); } Ok(()) } } // implement membership event handler -impl<T: Config<I>, I: 'static> sp_membership::traits::OnEvent<IdtyIndex> for Pallet<T, I> +impl<T: Config> sp_membership::traits::OnEvent<IdtyIndex> for Pallet<T> where - T: pallet_membership::Config<I>, + T: pallet_membership::Config, { fn on_event(membership_event: &sp_membership::Event<IdtyIndex>) { match membership_event { sp_membership::Event::<IdtyIndex>::MembershipAdded(idty_index) => { - if !T::IsSubWot::get() { - // when main membership is acquired, tell identity - // (only used on first membership acquiry) - pallet_identity::Pallet::<T>::membership_added(*idty_index); - } + // when main membership is acquired, tell identity + // (only used on first membership acquiry) + pallet_identity::Pallet::<T>::membership_added(*idty_index); } sp_membership::Event::<IdtyIndex>::MembershipRemoved(idty_index) => { - if !T::IsSubWot::get() { - // when main membership is lost, tell identity - pallet_identity::Pallet::<T>::membership_removed(*idty_index); - } + // when main membership is lost, tell identity + pallet_identity::Pallet::<T>::membership_removed(*idty_index); } sp_membership::Event::<IdtyIndex>::MembershipRenewed(_) => {} } @@ -270,12 +237,12 @@ where } // implement identity event handler -impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pallet<T, I> { +impl<T: Config> pallet_identity::traits::OnIdtyChange<T> for Pallet<T> { fn on_idty_change(idty_index: IdtyIndex, idty_event: &IdtyEvent<T>) { match idty_event { // identity just has been created, a cert must be added IdtyEvent::Created { creator, .. } => { - if let Err(e) = <pallet_certification::Pallet<T, I>>::do_add_cert_checked( + if let Err(e) = <pallet_certification::Pallet<T>>::do_add_cert_checked( *creator, idty_index, true, ) { sp_std::if_std! { @@ -288,7 +255,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall // if identity is removed also remove certs IdtyEvent::Removed { status } => { // try remove membership in any case - <pallet_membership::Pallet<T, I>>::do_remove_membership( + <pallet_membership::Pallet<T>>::do_remove_membership( idty_index, MembershipRemovalReason::Revoked, ); @@ -297,7 +264,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall match status { IdtyStatus::Unconfirmed | IdtyStatus::Unvalidated => { if let Err(e) = - <pallet_certification::Pallet<T, I>>::remove_all_certs_received_by( + <pallet_certification::Pallet<T>>::remove_all_certs_received_by( frame_system::Origin::<T>::Root.into(), idty_index, ) @@ -321,7 +288,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall // implement certification event handlers // new cert handler -impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T, I> { +impl<T: Config> pallet_certification::traits::OnNewcert<IdtyIndex> for Pallet<T> { fn on_new_cert( _issuer: IdtyIndex, _issuer_issued_count: u32, @@ -335,9 +302,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex } // remove cert handler -impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyIndex> - for Pallet<T, I> -{ +impl<T: Config> pallet_certification::traits::OnRemovedCert<IdtyIndex> for Pallet<T> { fn on_removed_cert( _issuer: IdtyIndex, _issuer_issued_count: u32, @@ -346,10 +311,10 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI _expiration: bool, ) { if receiver_received_count < T::MinCertForMembership::get() - && pallet_membership::Pallet::<T, I>::is_member(&receiver) + && pallet_membership::Pallet::<T>::is_member(&receiver) { // expire receiver membership - <pallet_membership::Pallet<T, I>>::do_remove_membership( + <pallet_membership::Pallet<T>>::do_remove_membership( receiver, MembershipRemovalReason::NotEnoughCerts, ) diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs index 268a6bf01a9805254cdf1d0c70ee90cafc8a668a..c043ef76448f72bcf18013fd168b8d9c232c1bee 100644 --- a/pallets/duniter-wot/src/mock.rs +++ b/pallets/duniter-wot/src/mock.rs @@ -46,13 +46,10 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event<T>}, - DuniterWot: pallet_duniter_wot::<Instance1>::{Pallet}, + DuniterWot: pallet_duniter_wot::{Pallet}, Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>}, - Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>}, - Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>}, - SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet}, - SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>}, - SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>}, + Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>}, + Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>}, } ); @@ -96,8 +93,7 @@ parameter_types! { pub const FirstIssuableOn: u64 = 2; } -impl pallet_duniter_wot::Config<Instance1> for Test { - type IsSubWot = frame_support::traits::ConstBool<false>; +impl pallet_duniter_wot::Config for Test { type MinCertForMembership = MinCertForMembership; type MinCertForCreateIdtyRight = MinCertForCreateIdtyRight; type FirstIssuableOn = FirstIssuableOn; @@ -124,7 +120,7 @@ impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl { impl pallet_identity::Config for Test { type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod; type ConfirmPeriod = ConfirmPeriod; - type CheckIdtyCallAllowed = (DuniterWot, SmithSubWot); + type CheckIdtyCallAllowed = DuniterWot; type IdtyCreationPeriod = IdtyCreationPeriod; type ValidationPeriod = ValidationPeriod; type AutorevocationPeriod = AutorevocationPeriod; @@ -135,7 +131,7 @@ impl pallet_identity::Config for Test { type AccountLinker = (); type Signer = UintAuthorityId; type Signature = TestSignature; - type OnIdtyChange = (DuniterWot, SmithSubWot); + type OnIdtyChange = DuniterWot; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -145,7 +141,7 @@ parameter_types! { pub const MembershipPeriod: u64 = 8; } -impl pallet_membership::Config<Instance1> for Test { +impl pallet_membership::Config for Test { type CheckMembershipCallAllowed = DuniterWot; type IdtyId = IdtyIndex; type IdtyIdOf = IdentityIndexOf<Self>; @@ -166,7 +162,7 @@ parameter_types! { pub const ValidityPeriod: u64 = 20; } -impl pallet_certification::Config<Instance1> for Test { +impl pallet_certification::Config for Test { type CertPeriod = CertPeriod; type IdtyIndex = IdtyIndex; type OwnerKeyOf = Identity; @@ -180,68 +176,10 @@ impl pallet_certification::Config<Instance1> for Test { type ValidityPeriod = ValidityPeriod; } -// SMITHS SUB-WOT // - -parameter_types! { - pub const SmithMinCertForMembership: u32 = 2; - pub const SmithFirstIssuableOn: u64 = 2; -} - -impl pallet_duniter_wot::Config<Instance2> for Test { - type IsSubWot = frame_support::traits::ConstBool<true>; - type MinCertForMembership = SmithMinCertForMembership; - type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>; - type FirstIssuableOn = SmithFirstIssuableOn; - type IsDistanceOk = crate::traits::DistanceAlwaysOk; -} - -// SmithMembership -parameter_types! { - pub const SmithMembershipPeriod: u64 = 20; -} - -impl pallet_membership::Config<Instance2> for Test { - type CheckMembershipCallAllowed = SmithSubWot; - type IdtyId = IdtyIndex; - type IdtyIdOf = IdentityIndexOf<Self>; - type AccountIdOf = (); - type MembershipPeriod = SmithMembershipPeriod; - type OnEvent = SmithSubWot; - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkSetupHandler = (); -} - -// SmithCert -parameter_types! { - pub const SmithMaxByIssuer: u8 = 8; - pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 2; - pub const SmithCertPeriod: u64 = 2; - pub const SmithValidityPeriod: u64 = 10; -} - -impl pallet_certification::Config<Instance2> for Test { - type CertPeriod = SmithCertPeriod; - type IdtyIndex = IdtyIndex; - type OwnerKeyOf = Identity; - type CheckCertAllowed = SmithSubWot; - type MaxByIssuer = SmithMaxByIssuer; - type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert; - type OnNewcert = SmithSubWot; - type OnRemovedCert = SmithSubWot; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type ValidityPeriod = SmithValidityPeriod; -} - pub const NAMES: [&str; 6] = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"]; // Build genesis storage according to the mock runtime. -pub fn new_test_ext( - initial_identities_len: usize, - initial_smiths_len: usize, -) -> sp_io::TestExternalities { +pub fn new_test_ext(initial_identities_len: usize) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default() .build_storage::<Test>() .unwrap(); @@ -265,7 +203,7 @@ pub fn new_test_ext( .assimilate_storage(&mut t) .unwrap(); - pallet_membership::GenesisConfig::<Test, Instance1> { + pallet_membership::GenesisConfig::<Test> { memberships: (1..=initial_identities_len) .map(|i| { ( @@ -280,35 +218,13 @@ pub fn new_test_ext( .assimilate_storage(&mut t) .unwrap(); - pallet_certification::GenesisConfig::<Test, Instance1> { + pallet_certification::GenesisConfig::<Test> { apply_cert_period_at_genesis: true, certs_by_receiver: clique_wot(initial_identities_len, ValidityPeriod::get()), } .assimilate_storage(&mut t) .unwrap(); - pallet_membership::GenesisConfig::<Test, Instance2> { - memberships: (1..=initial_smiths_len) - .map(|i| { - ( - i as u32, - sp_membership::MembershipData { - expire_on: SmithMembershipPeriod::get(), - }, - ) - }) - .collect(), - } - .assimilate_storage(&mut t) - .unwrap(); - - pallet_certification::GenesisConfig::<Test, Instance2> { - apply_cert_period_at_genesis: true, - certs_by_receiver: clique_wot(initial_smiths_len, SmithValidityPeriod::get()), - } - .assimilate_storage(&mut t) - .unwrap(); - frame_support::BasicExternalities::execute_with_storage(&mut t, || { // manually increment genesis identities sufficient counter // In real world, this is done by pallet-identity @@ -330,9 +246,6 @@ pub fn run_to_block(n: u64) { Identity::on_finalize(System::block_number()); Membership::on_finalize(System::block_number()); Cert::on_finalize(System::block_number()); - SmithSubWot::on_finalize(System::block_number()); - 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(); @@ -343,9 +256,6 @@ pub fn run_to_block(n: u64) { Identity::on_initialize(System::block_number()); Membership::on_initialize(System::block_number()); Cert::on_initialize(System::block_number()); - SmithSubWot::on_initialize(System::block_number()); - SmithMembership::on_initialize(System::block_number()); - SmithCert::on_initialize(System::block_number()); } } diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs index 3645f1979fca7d946fbddf0b408c7361467d9f3e..2b86ee97f6dd1258126a035a3ca166a95b13eb69 100644 --- a/pallets/duniter-wot/src/tests.rs +++ b/pallets/duniter-wot/src/tests.rs @@ -17,11 +17,9 @@ use crate::mock::*; use crate::pallet as pallet_duniter_wot; use codec::Encode; -use frame_support::instances::{Instance1, Instance2}; use frame_support::{assert_noop, assert_ok}; use pallet_identity::{ - IdtyIndexAccountIdPayload, IdtyName, IdtyStatus, RevocationPayload, RevocationReason, - NEW_OWNER_KEY_PAYLOAD_PREFIX, REVOCATION_PAYLOAD_PREFIX, + IdtyName, IdtyStatus, RevocationPayload, RevocationReason, REVOCATION_PAYLOAD_PREFIX, }; use pallet_membership::MembershipRemovalReason; use sp_runtime::testing::TestSignature; @@ -30,13 +28,13 @@ use sp_runtime::testing::TestSignature; /// and good identity and certification metadate #[test] fn test_genesis_build() { - new_test_ext(3, 2).execute_with(|| { + new_test_ext(3).execute_with(|| { run_to_block(1); // Verify state assert_eq!(Identity::identities_count(), 3); assert_eq!(Identity::identity(1).unwrap().next_creatable_identity_on, 0); assert_eq!( - pallet_certification::Pallet::<Test, Instance1>::idty_cert_meta(1).next_issuable_on, + pallet_certification::Pallet::<Test>::idty_cert_meta(1).next_issuable_on, 2 ); }); @@ -45,7 +43,7 @@ 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(|| { + new_test_ext(3).execute_with(|| { run_to_block(1); // Alice did not receive enough certs @@ -53,7 +51,7 @@ fn test_creator_not_allowed_to_create_idty() { // because Alice.next_issuable_on = 2) assert_noop!( Identity::create_identity(RuntimeOrigin::signed(1), 4), - pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty + pallet_duniter_wot::Error::<Test>::NotEnoughReceivedCertsToCreateIdty ); }); } @@ -61,123 +59,21 @@ 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(|| { + new_test_ext(5).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 + // pallet_duniter_wot::Error::<Test>::NotEnoughReceivedCertsToCreateIdty ); }); } -/// test smith joining workflow -#[test] -fn test_join_smiths() { - new_test_ext(5, 3).execute_with(|| { - run_to_block(2); - - // Alice should be able to send a smith cert to Dave - run_to_block(3); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4)); - - // Bob should be able to send a smith cert to Dave - run_to_block(4); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4)); - - // Dave should be able to claim his membership - run_to_block(4); - assert_ok!(SmithMembership::claim_membership(RuntimeOrigin::signed(4),)); - System::assert_has_event(RuntimeEvent::SmithMembership( - pallet_membership::Event::MembershipAdded { - member: 4, - expire_on: 4 - + <Test as pallet_membership::Config<Instance2>>::MembershipPeriod::get(), - }, - )); - }); -} - -/// test smith membership expiry after cert expiration -#[test] -fn test_smith_certs_expirations_should_expire_smith_membership() { - new_test_ext(5, 3).execute_with(|| { - // After block #10, alice membership should be revoked due to smith certs expiration - run_to_block(10); - System::assert_has_event(RuntimeEvent::SmithMembership( - pallet_membership::Event::MembershipRemoved { - member: 1, - reason: MembershipRemovalReason::NotEnoughCerts, - }, - )); - }); -} - -/// test that smith can not change owner key -#[test] -fn test_smith_member_cant_change_its_idty_address() { - new_test_ext(5, 3).execute_with(|| { - run_to_block(2); - - let genesis_hash = System::block_hash(0); - let new_key_payload = IdtyIndexAccountIdPayload { - genesis_hash: &genesis_hash, - idty_index: 3u32, - old_owner_key: &3u64, - }; - - // Identity 3 can't change it's address - assert_noop!( - Identity::change_owner_key( - RuntimeOrigin::signed(3), - 13, - TestSignature(13, (NEW_OWNER_KEY_PAYLOAD_PREFIX, new_key_payload).encode()) - ), - pallet_duniter_wot::Error::<Test, Instance2>::NotAllowedToChangeIdtyAddress - ); - }); -} - -/// members of the smith subwot can revoke their identity -#[test] -fn test_smith_member_can_revoke_its_idty() { - new_test_ext(5, 3).execute_with(|| { - run_to_block(2); - - let revocation_payload = RevocationPayload { - idty_index: 3u32, - genesis_hash: System::block_hash(0), - }; - - // Identity 3 can't change it's address - assert_ok!(Identity::revoke_identity( - RuntimeOrigin::signed(3), - 3, - 3, - TestSignature(3, (REVOCATION_PAYLOAD_PREFIX, revocation_payload).encode()) - )); - // membership should be removed - System::assert_has_event(RuntimeEvent::Membership( - pallet_membership::Event::MembershipRemoved { - member: 3, - reason: pallet_membership::MembershipRemovalReason::Revoked, - }, - )); - // smith membership should be removed as well - System::assert_has_event(RuntimeEvent::SmithMembership( - pallet_membership::Event::MembershipRemoved { - member: 3, - reason: pallet_membership::MembershipRemovalReason::Revoked, - }, - )); - }); -} - /// test identity creation and that a first cert is emitted #[test] fn test_create_idty_ok() { - new_test_ext(5, 2).execute_with(|| { + new_test_ext(5).execute_with(|| { run_to_block(2); // Alice should be able to create an identity at block #2 @@ -205,7 +101,7 @@ fn test_create_idty_ok() { /// test identity validation #[test] fn test_new_idty_validation() { - new_test_ext(5, 2).execute_with(|| { + new_test_ext(5).execute_with(|| { // Alice creates Ferdie identity run_to_block(2); assert_ok!(Identity::create_identity(RuntimeOrigin::signed(1), 6)); @@ -231,8 +127,7 @@ fn test_new_idty_validation() { System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipAdded { member: 6, - expire_on: 5 - + <Test as pallet_membership::Config<Instance1>>::MembershipPeriod::get(), + expire_on: 5 + <Test as pallet_membership::Config>::MembershipPeriod::get(), }, )); System::assert_has_event(RuntimeEvent::Identity( @@ -258,7 +153,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(|| { + new_test_ext(5).execute_with(|| { run_to_block(2); // Alice creates Ferdie identity @@ -282,11 +177,10 @@ 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(|| { + new_test_ext(5).execute_with(|| { run_to_block(2); // Alice identity can be revoked @@ -313,13 +207,6 @@ fn test_revoke_idty() { reason: pallet_membership::MembershipRemovalReason::Revoked, }, )); - // and her smith membership should be removed as well - System::assert_has_event(RuntimeEvent::SmithMembership( - pallet_membership::Event::MembershipRemoved { - member: 1, - reason: pallet_membership::MembershipRemovalReason::Revoked, - }, - )); // Anyone should be able to submit Bob revocation certificate assert_ok!(Identity::revoke_identity( @@ -351,7 +238,7 @@ fn test_revoke_idty() { /// test that expired membership lose the identity after a delay #[test] fn test_idty_membership_expire() { - new_test_ext(3, 2).execute_with(|| { + new_test_ext(3).execute_with(|| { run_to_block(4); // Alice renews her membership @@ -411,7 +298,7 @@ fn test_idty_membership_expire() { // Alice can't certify revoked identity assert_noop!( Cert::add_cert(RuntimeOrigin::signed(1), 1, 3), - pallet_duniter_wot::Error::<Test, Instance1>::CertToRevoked + pallet_duniter_wot::Error::<Test>::CertToRevoked ); run_to_block(21); @@ -424,7 +311,7 @@ fn test_idty_membership_expire() { // Alice can't certify removed identity assert_noop!( Cert::add_cert(RuntimeOrigin::signed(1), 1, 3), - pallet_duniter_wot::Error::<Test, Instance1>::IdtyNotFound + pallet_duniter_wot::Error::<Test>::IdtyNotFound ); }); } @@ -432,7 +319,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(|| { + new_test_ext(5).execute_with(|| { // Alice creates Ferdie identity run_to_block(2); assert_ok!(Identity::create_identity(RuntimeOrigin::signed(1), 6)); @@ -455,50 +342,24 @@ fn test_unvalidated_idty_certs_removal() { /// test what happens when certification expire #[test] fn test_certification_expire() { - new_test_ext(3, 3).execute_with(|| { + new_test_ext(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::CertRemoved { - issuer: 2, // Bob - receiver: 1, // Alice - 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::MembershipRemoved { - member: 1, - reason: MembershipRemovalReason::NotEnoughCerts, - }, - )); - // --- BLOCK 14 --- run_to_block(14); assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); @@ -532,13 +393,13 @@ fn test_certification_expire() { // Alice can not renew her membership which does not exist assert_noop!( Membership::renew_membership(RuntimeOrigin::signed(1)), - pallet_membership::Error::<Test, Instance1>::MembershipNotFound + pallet_membership::Error::<Test>::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>::NotEnoughCertsToClaimMembership + pallet_duniter_wot::Error::<Test>::NotEnoughCertsToClaimMembership ); // --- BLOCK 23 --- @@ -559,78 +420,27 @@ fn test_certification_expire() { // - when source or target membership is pending (both wot) #[test] fn test_cert_can_not_be_issued() { - new_test_ext(4, 3).execute_with(|| { + new_test_ext(4).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)); // +10 - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +10 - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 2)); // +20 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +20 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 4)); // +20 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 1)); // +20 // --- BLOCK 4 --- run_to_block(4); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 3)); // +10 - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +10 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 4)); // +20 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +20 assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 3)); // +20 // --- BLOCK 7 --- run_to_block(7); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10 - assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(1))); // +20 - assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(2))); // +20 - assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(3))); // +20 assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8 assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8 assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); // + 8 assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(4))); // + 8 - // smith cert Bob → Alice expires at block 10 - run_to_block(10); - // println!("{:?}", System::events()); - System::assert_has_event(RuntimeEvent::SmithCert( - pallet_certification::Event::CertRemoved { - issuer: 2, // Bob - receiver: 1, // Alice - 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::MembershipRemoved { - member: 1, - reason: MembershipRemovalReason::NotEnoughCerts, - }, - )); - - run_to_block(11); - // Dave should be able to receive a smith cert since - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4)); - // Bob renews his smith certification towards Alice - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 1)); - // now Alice has enough certs - assert_eq!( - SmithCert::idty_cert_meta(1), - pallet_certification::IdtyCertMeta { - issued_count: 2, // → Bob, → Charlie - // since Alice got back to min number of received certs to be able to issue cert - // her next_issuable_on was updated to block_number (11) + cert_period (2) - next_issuable_on: 13, // 11 + 2 - received_count: 2 // ↠Bob, ↠Charlie - } - ); - - // because Alice did not claim membership, she is not member at this point - assert_eq!(SmithMembership::membership(1), None); - run_to_block(13); - // /!\ COUNTERINTUITIVE BEHAVIOR - // Alice is not smith member, she should not be able to issue cert - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2)); - run_to_block(14); assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8 assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8 @@ -669,54 +479,3 @@ fn test_cert_can_not_be_issued() { // she would have been able to emit a cert without being member }) } - -/// test non smith identity can not emit smith cert -#[test] -fn test_non_smith_can_not_issue_smith_cert() { - new_test_ext(4, 3).execute_with(|| { - assert_noop!( - SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1), - pallet_certification::Error::<Test, Instance2>::NotEnoughCertReceived - ); - }) -} - -/// FIXME this test should not fail with NotRespectCertPeriod but NotSmith or somthing like that -/// test non smith identity can not emit smith cert -#[test] -fn test_non_smith_with_certs_can_not_issue_smith_cert() { - new_test_ext(4, 3).execute_with(|| { - run_to_block(2); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4)); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4)); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4)); - assert_noop!( - SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1), - pallet_certification::Error::<Test, Instance2>::NotRespectCertPeriod - ); - }) -} - -/// FIXME this test should not succeed because Dave should not be able to issue cert -/// after revocation of his smith membership -/// test non smith identity can not emit smith cert -#[test] -fn test_revoked_smith_with_certs_can_not_issue_smith_cert() { - new_test_ext(4, 3).execute_with(|| { - run_to_block(2); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 4)); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 4)); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4)); - assert_ok!(SmithMembership::claim_membership(RuntimeOrigin::signed(4))); - assert_noop!( - SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1), - pallet_certification::Error::<Test, Instance2>::NotRespectCertPeriod - ); - run_to_block(4); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),); - run_to_block(5); - assert_ok!(SmithMembership::revoke_membership(RuntimeOrigin::signed(4))); - run_to_block(6); - assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(4), 4, 1),); - }) -} diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs index c9656a498241438b2cb16196ae8398b6090f7359..01998e0c5dc056155f3059575c3939b71c320c16 100644 --- a/pallets/identity/src/lib.rs +++ b/pallets/identity/src/lib.rs @@ -410,8 +410,6 @@ pub mod pallet { Error::<T>::OwnerKeyAlreadyUsed ); - T::CheckIdtyCallAllowed::change_owner_key(idty_index)?; - let block_number = frame_system::Pallet::<T>::block_number(); let maybe_old_old_owner_key = if let Some((old_owner_key, last_change)) = idty_value.old_owner_key { diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs index 925714813793a69a99b22438043e3cc92ab60a4c..6a1b457c1850bef852ac42bc0c160fc759b3f039 100644 --- a/pallets/identity/src/traits.rs +++ b/pallets/identity/src/traits.rs @@ -20,7 +20,6 @@ use impl_trait_for_tuples::impl_for_tuples; pub trait CheckIdtyCallAllowed<T: Config> { fn check_create_identity(creator: T::IdtyIndex) -> Result<(), DispatchError>; - fn change_owner_key(idty_index: T::IdtyIndex) -> Result<(), DispatchError>; } #[impl_for_tuples(5)] @@ -29,10 +28,6 @@ impl<T: Config> CheckIdtyCallAllowed<T> for Tuple { for_tuples!( #( Tuple::check_create_identity(creator)?; )* ); Ok(()) } - fn change_owner_key(idty_index: T::IdtyIndex) -> Result<(), DispatchError> { - for_tuples!( #( Tuple::change_owner_key(idty_index)?; )* ); - Ok(()) - } } pub trait IdtyNameValidator { diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs index 20120f25c68a99791db7ca3ef76b2d0b26ad0b97..f8bff333c804b2a17f0152703ea267861d45cc0e 100644 --- a/pallets/identity/src/types.rs +++ b/pallets/identity/src/types.rs @@ -38,6 +38,7 @@ pub enum IdtyEvent<T: crate::Config> { /// removing an identity (unvalidated or revoked) // pallet wot removes associated certifications if status is not revoked // pallet quota removes associated quota + // pallet smith-members exclude smith Removed { status: IdtyStatus }, // TODO add a way to unlink accounts corresponding to revoked or removed identities } diff --git a/pallets/membership/src/benchmarking.rs b/pallets/membership/src/benchmarking.rs index d07f4661b788592244c6d290103126cc5bac0192..1bdf5edf6c75666c3c2fc1acd901d2b3ad642733 100644 --- a/pallets/membership/src/benchmarking.rs +++ b/pallets/membership/src/benchmarking.rs @@ -18,7 +18,7 @@ use super::*; -use frame_benchmarking::benchmarks_instance_pallet; +use frame_benchmarking::benchmarks; use frame_system::pallet_prelude::BlockNumberFor; use frame_system::RawOrigin; use sp_runtime::traits::{Convert, One}; @@ -28,11 +28,11 @@ use maplit::btreemap; use crate::Pallet; -fn assert_has_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) { +fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) { frame_system::Pallet::<T>::assert_has_event(generic_event.into()); } -benchmarks_instance_pallet! { +benchmarks! { where_clause { where T::IdtyId: From<u32>, @@ -42,13 +42,13 @@ benchmarks_instance_pallet! { // claim membership claim_membership { let idty: T::IdtyId = 3.into(); - Membership::<T, I>::take(idty); + Membership::<T>::take(idty); let caller: T::AccountId = T::AccountIdOf::convert(idty).unwrap(); let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); T::BenchmarkSetupHandler::force_status_ok(&idty, &caller); }: _<T::RuntimeOrigin>(caller_origin) verify { - assert_has_event::<T, I>(Event::<T, I>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into()); + assert_has_event::<T>(Event::<T>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into()); } // renew membership @@ -59,7 +59,7 @@ benchmarks_instance_pallet! { T::BenchmarkSetupHandler::force_status_ok(&idty, &caller); }: _<T::RuntimeOrigin>(caller_origin) verify { - assert_has_event::<T, I>(Event::<T, I>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into()); + assert_has_event::<T>(Event::<T>::MembershipAdded{member: idty, expire_on: BlockNumberFor::<T>::one() + T::MembershipPeriod::get()}.into()); } // revoke membership @@ -70,12 +70,12 @@ benchmarks_instance_pallet! { frame_system::pallet::Pallet::<T>::set_block_number(10_000_000.into()); // Arbitrarily high, to be in the worst case of wot instance. }: _<T::RuntimeOrigin>(caller_origin) verify { - assert_has_event::<T, I>(Event::<T, I>::MembershipRemoved{member: idty, reason: MembershipRemovalReason::Revoked}.into()); + assert_has_event::<T>(Event::<T>::MembershipRemoved{member: idty, reason: MembershipRemovalReason::Revoked}.into()); } // Base weight of an empty initialize on_initialize { - }: {Pallet::<T, I>::on_initialize(BlockNumberFor::<T>::zero());} + }: {Pallet::<T>::on_initialize(BlockNumberFor::<T>::zero());} expire_memberships { let i in 0..3; // Limited by the number of validators @@ -86,14 +86,14 @@ benchmarks_instance_pallet! { let mut idties: Vec<T::IdtyId> = Vec::new(); for j in 1..i+1 { let j: T::IdtyId = j.into(); - Membership::<T, I>::insert(j, MembershipData::<T::BlockNumber>::default()); + Membership::<T>::insert(j, MembershipData::<T::BlockNumber>::default()); idties.push(j); } - MembershipsExpireOn::<T, I>::insert(block_number, idties); - assert_eq!(MembershipsExpireOn::<T, I>::get(block_number).len(), i as usize); - }: {Pallet::<T, I>::expire_memberships(block_number);} + MembershipsExpireOn::<T>::insert(block_number, idties); + assert_eq!(MembershipsExpireOn::<T>::get(block_number).len(), i as usize); + }: {Pallet::<T>::expire_memberships(block_number);} verify { - assert_eq!(MembershipsExpireOn::<T, I>::get(block_number).len(), 0_usize); + assert_eq!(MembershipsExpireOn::<T>::get(block_number).len(), 0_usize); } impl_benchmark_test_suite!( diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs index 08bbb81ad94295f46691fde78233a633b42ad687..cba39e37ee5abb5fc058fcdea588e74f7dced747 100644 --- a/pallets/membership/src/lib.rs +++ b/pallets/membership/src/lib.rs @@ -79,12 +79,12 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] - pub struct Pallet<T, I = ()>(_); + pub struct Pallet<T>(_); // CONFIG // #[pallet::config] - pub trait Config<I: 'static = ()>: frame_system::Config { + pub trait Config: frame_system::Config { /// Ask the runtime whether the identity can perform membership operations type CheckMembershipCallAllowed: CheckMembershipCallAllowed<Self::IdtyId>; /// Something that identifies an identity @@ -99,8 +99,7 @@ pub mod pallet { /// On event handler type OnEvent: OnEvent<Self::IdtyId>; /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From<Event<Self, I>> - + IsType<<Self as frame_system::Config>::RuntimeEvent>; + type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; type WeightInfo: WeightInfo; #[cfg(feature = "runtime-benchmarks")] type BenchmarkSetupHandler: SetupBenchmark<Self::IdtyId, Self::AccountId>; @@ -109,12 +108,12 @@ pub mod pallet { // GENESIS STUFF // #[pallet::genesis_config] - pub struct GenesisConfig<T: Config<I>, I: 'static = ()> { + pub struct GenesisConfig<T: Config> { pub memberships: BTreeMap<T::IdtyId, MembershipData<T::BlockNumber>>, } #[cfg(feature = "std")] - impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> { + impl<T: Config> Default for GenesisConfig<T> { fn default() -> Self { Self { memberships: Default::default(), @@ -123,11 +122,11 @@ pub mod pallet { } #[pallet::genesis_build] - impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig<T, I> { + impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { fn build(&self) { for (idty_id, membership_data) in &self.memberships { - MembershipsExpireOn::<T, I>::append(membership_data.expire_on, idty_id); - Membership::<T, I>::insert(idty_id, membership_data); + MembershipsExpireOn::<T>::append(membership_data.expire_on, idty_id); + Membership::<T>::insert(idty_id, membership_data); } } } @@ -138,20 +137,20 @@ pub mod pallet { // (expiration block for instance) #[pallet::storage] #[pallet::getter(fn membership)] - pub type Membership<T: Config<I>, I: 'static = ()> = + pub type Membership<T: Config> = CountedStorageMap<_, Twox64Concat, T::IdtyId, MembershipData<T::BlockNumber>, OptionQuery>; /// maps block number to the list of identity id set to expire at this block #[pallet::storage] #[pallet::getter(fn memberships_expire_on)] - pub type MembershipsExpireOn<T: Config<I>, I: 'static = ()> = + pub type MembershipsExpireOn<T: Config> = StorageMap<_, Twox64Concat, T::BlockNumber, Vec<T::IdtyId>, ValueQuery>; // EVENTS // #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event<T: Config<I>, I: 'static = ()> { + pub enum Event<T: Config> { /// A membership was added. MembershipAdded { member: T::IdtyId, @@ -167,7 +166,7 @@ pub mod pallet { // ERRORS// #[pallet::error] - pub enum Error<T, I = ()> { + pub enum Error<T> { /// Identity ID not found. IdtyIdNotFound, /// Membership already acquired. @@ -179,7 +178,7 @@ pub mod pallet { // HOOKS // #[pallet::hooks] - impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> { + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { fn on_initialize(n: T::BlockNumber) -> Weight { if n > T::BlockNumber::zero() { T::WeightInfo::on_initialize().saturating_add(Self::expire_memberships(n)) @@ -192,7 +191,7 @@ pub mod pallet { // CALLS // #[pallet::call] - impl<T: Config<I>, I: 'static> Pallet<T, I> { + impl<T: Config> Pallet<T> { /// claim membership /// it must fullfill the requirements (certs, distance) /// TODO #159 for main wot claim_membership is called automatically when distance is evaluated positively @@ -215,7 +214,7 @@ pub mod pallet { // Verify phase let idty_id = Self::get_idty_id(origin)?; let membership_data = - Membership::<T, I>::get(idty_id).ok_or(Error::<T, I>::MembershipNotFound)?; + Membership::<T>::get(idty_id).ok_or(Error::<T>::MembershipNotFound)?; T::CheckMembershipCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?; @@ -244,14 +243,14 @@ pub mod pallet { // INTERNAL FUNCTIONS // - impl<T: Config<I>, I: 'static> Pallet<T, I> { + impl<T: Config> Pallet<T> { /// unschedule membership expiry fn unschedule_membership_expiry(idty_id: T::IdtyId, block_number: T::BlockNumber) { - let mut scheduled = MembershipsExpireOn::<T, I>::get(block_number); + let mut scheduled = MembershipsExpireOn::<T>::get(block_number); if let Some(pos) = scheduled.iter().position(|x| *x == idty_id) { scheduled.swap_remove(pos); - MembershipsExpireOn::<T, I>::set(block_number, scheduled); + MembershipsExpireOn::<T>::set(block_number, scheduled); } } /// schedule membership expiry @@ -259,8 +258,8 @@ pub mod pallet { let block_number = frame_system::pallet::Pallet::<T>::block_number(); let expire_on = block_number + T::MembershipPeriod::get(); - Membership::<T, I>::insert(idty_id, MembershipData { expire_on }); - MembershipsExpireOn::<T, I>::append(expire_on, idty_id); + Membership::<T>::insert(idty_id, MembershipData { expire_on }); + MembershipsExpireOn::<T>::append(expire_on, idty_id); Self::deposit_event(Event::MembershipAdded { member: idty_id, expire_on, @@ -282,7 +281,7 @@ pub mod pallet { /// perform membership removal pub fn do_remove_membership(idty_id: T::IdtyId, reason: MembershipRemovalReason) { - if let Some(membership_data) = Membership::<T, I>::take(idty_id) { + if let Some(membership_data) = Membership::<T>::take(idty_id) { Self::unschedule_membership_expiry(idty_id, membership_data.expire_on); Self::deposit_event(Event::MembershipRemoved { member: idty_id, @@ -295,7 +294,7 @@ pub mod pallet { /// check the origin and get identity id if valid fn get_idty_id(origin: OriginFor<T>) -> Result<T::IdtyId, DispatchError> { if let Ok(RawOrigin::Signed(account_id)) = origin.into() { - T::IdtyIdOf::convert(account_id).ok_or_else(|| Error::<T, I>::IdtyIdNotFound.into()) + T::IdtyIdOf::convert(account_id).ok_or_else(|| Error::<T>::IdtyIdNotFound.into()) } else { Err(BadOrigin.into()) } @@ -305,7 +304,7 @@ pub mod pallet { pub fn expire_memberships(block_number: T::BlockNumber) -> Weight { let mut expired_idty_count = 0u32; - for idty_id in MembershipsExpireOn::<T, I>::take(block_number) { + for idty_id in MembershipsExpireOn::<T>::take(block_number) { // remove membership (take) Self::do_remove_membership(idty_id, MembershipRemovalReason::Expired); expired_idty_count += 1; @@ -314,22 +313,22 @@ pub mod pallet { } /// check if identity is member - pub(super) fn is_member(idty_id: &T::IdtyId) -> bool { - Membership::<T, I>::contains_key(idty_id) + pub fn is_member(idty_id: &T::IdtyId) -> bool { + Membership::<T>::contains_key(idty_id) } } } // implement traits -impl<T: Config<I>, I: 'static> sp_runtime::traits::IsMember<T::IdtyId> for Pallet<T, I> { +impl<T: Config> sp_runtime::traits::IsMember<T::IdtyId> for Pallet<T> { fn is_member(idty_id: &T::IdtyId) -> bool { Self::is_member(idty_id) } } -impl<T: Config<I>, I: 'static> MembersCount for Pallet<T, I> { +impl<T: Config> MembersCount for Pallet<T> { fn members_count() -> u32 { - Membership::<T, I>::count() + Membership::<T>::count() } } diff --git a/pallets/membership/src/tests.rs b/pallets/membership/src/tests.rs index d3ea561676c7df75c9037da79ec8b5f2a47b232b..53da60336bb6cefa94a5897836a38871929f7503 100644 --- a/pallets/membership/src/tests.rs +++ b/pallets/membership/src/tests.rs @@ -106,7 +106,7 @@ fn test_membership_renewal_nope() { // Membership 1 can not be renewed assert_noop!( DefaultMembership::renew_membership(RuntimeOrigin::signed(1)), - Error::<Test, _>::MembershipNotFound, + Error::<Test>::MembershipNotFound, ); run_to_block(3); assert!(!DefaultMembership::is_member(&1)); diff --git a/pallets/smith-members/Cargo.toml b/pallets/smith-members/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5ced90e2c20a197003523b374e1bcf7928d904c0 --- /dev/null +++ b/pallets/smith-members/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "pallet-smith-members" +authors = ["c-geek <https://forum.duniter.org/u/cgeek>"] +description = 'duniter pallet to handle offences.' +edition = "2021" +homepage = 'https://duniter.org' +license = 'AGPL-3.0' +repository = 'https://git.duniter.org/nodes/rust/duniter-v2s' +version = '3.0.0' +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"], default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.101", default-features = false, optional = true } +pallet-authority-members = { path = "../authority-members", default-features = false } +frame-support = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +frame-system = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +pallet-balances = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +sp-runtime = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +sp-staking = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +sp-std = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } + +[dev-dependencies] +maplit = "1.0.2" +sp-core = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42', default-features = false } +sp-io = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42' } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + 'frame-benchmarking/std', + "log/std", + "pallet-balances/std", + "pallet-authority-members/std", + "scale-info/std", + "serde", + "sp-runtime/std", + "sp-staking/std", + "sp-std/std", +] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] +try-runtime = ["frame-support/try-runtime"] + +[dependencies.frame-benchmarking] +default-features = false +git = 'https://github.com/duniter/substrate' +optional = true +branch = 'duniter-substrate-v0.9.42' \ No newline at end of file diff --git a/pallets/smith-members/README.md b/pallets/smith-members/README.md new file mode 100644 index 0000000000000000000000000000000000000000..655534a2a74d357c3d0f856dd3e4de6493eddd44 --- /dev/null +++ b/pallets/smith-members/README.md @@ -0,0 +1,3 @@ +# Duniter smith pallet + +The bridge between `identity` and `authority-members` pallet. \ No newline at end of file diff --git a/pallets/smith-members/src/benchmarking.rs b/pallets/smith-members/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..071d73905ff8d416f472eca8b5700dccb65d975f --- /dev/null +++ b/pallets/smith-members/src/benchmarking.rs @@ -0,0 +1,105 @@ +// Copyright 2021-2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::benchmarks; +use frame_system::RawOrigin; +use sp_runtime::traits::Convert; + +#[cfg(test)] +use maplit::btreemap; + +use crate::Pallet; + +fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) { + frame_system::Pallet::<T>::assert_has_event(generic_event.into()); +} + +benchmarks! { + where_clause { + where + T::IdtyIndex: From<u32> + } + invite_smith { + let issuer: T::IdtyIndex = 1.into(); + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + Pallet::<T>::on_smith_goes_online(1.into()); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + let receiver: T::IdtyIndex = 4.into(); + }: _<T::RuntimeOrigin>(caller_origin, receiver) + verify { + assert_has_event::<T>(Event::<T>::InvitationSent{ + idty_index: receiver, + invited_by: issuer, + }.into()); + } + accept_invitation { + // Worst case preparation + let issuer: T::IdtyIndex = 1.into(); + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + Pallet::<T>::on_smith_goes_online(1.into()); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + let receiver: T::IdtyIndex = 4.into(); + Pallet::<T>::invite_smith(caller_origin, receiver)?; + // test + let issuer: T::IdtyIndex = 4.into(); + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + }: _<T::RuntimeOrigin>(caller_origin) + verify { + assert_has_event::<T>(Event::<T>::InvitationAccepted{ + idty_index: receiver, + }.into()); + } + certify_smith { + // Worst case preparation + let issuer: T::IdtyIndex = 1.into(); + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + Pallet::<T>::on_smith_goes_online(1.into()); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + let receiver: T::IdtyIndex = 4.into(); + Pallet::<T>::invite_smith(caller_origin, receiver)?; + let issuer: T::IdtyIndex = receiver; + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + Pallet::<T>::accept_invitation(caller_origin)?; + // test + let issuer: T::IdtyIndex = 1.into(); + let caller: T::AccountId = T::OwnerKeyOf::convert(issuer).unwrap(); + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + }: _<T::RuntimeOrigin>(caller_origin, receiver) + verify { + assert_has_event::<T>(Event::<T>::CertificationReceived{ + idty_index: receiver, + issued_by: issuer, + }.into()); + } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3]), + 2 => (false, vec![1, 3]), + 3 => (false, vec![1, 2]), + ], + }), + crate::mock::Runtime + ); +} diff --git a/pallets/smith-members/src/impls.rs b/pallets/smith-members/src/impls.rs new file mode 100644 index 0000000000000000000000000000000000000000..95a1e49dfd63d25acd45e8a5b5f7c983bad89aef --- /dev/null +++ b/pallets/smith-members/src/impls.rs @@ -0,0 +1,28 @@ +use crate::{Config, CurrentSession, Pallet}; +use pallet_authority_members::SessionIndex; +use sp_runtime::traits::Convert; + +impl<T: Config> pallet_authority_members::OnOutgoingMember<T::MemberId> for Pallet<T> { + fn on_outgoing_member(member_id: T::MemberId) { + if let Some(member_id) = T::IdtyIdOfAuthorityId::convert(member_id) { + Pallet::<T>::on_smith_goes_offline(member_id); + } + } +} + +/// As long as a Smith is in the authority set, he will not expire. +impl<T: Config> pallet_authority_members::OnIncomingMember<T::MemberId> for Pallet<T> { + fn on_incoming_member(member_id: T::MemberId) { + if let Some(member_id) = T::IdtyIdOfAuthorityId::convert(member_id) { + Pallet::<T>::on_smith_goes_online(member_id); + } + } +} + +/// +impl<T: Config> pallet_authority_members::OnNewSession for Pallet<T> { + fn on_new_session(index: SessionIndex) { + CurrentSession::<T>::put(index); + Pallet::<T>::on_exclude_expired_smiths(index); + } +} diff --git a/pallets/smith-members/src/lib.rs b/pallets/smith-members/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..95dd31177915c5dd19b8872c363c7c524ee39d52 --- /dev/null +++ b/pallets/smith-members/src/lib.rs @@ -0,0 +1,552 @@ +// Copyright 2021-2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +mod impls; +pub mod traits; +mod types; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +use codec::{Codec, Decode, Encode}; +use frame_support::dispatch::{DispatchResultWithPostInfo, TypeInfo}; +use frame_support::pallet_prelude::Get; +use frame_support::{ensure, RuntimeDebug}; +use frame_system::ensure_signed; +use frame_system::pallet_prelude::OriginFor; +use sp_runtime::traits::AtLeast32BitUnsigned; +use sp_runtime::traits::IsMember; +use sp_std::fmt::Debug; +use sp_std::prelude::*; + +use crate::traits::OnSmithDelete; +pub use crate::weights::WeightInfo; +pub use pallet::*; +use pallet_authority_members::SessionIndex; +pub use types::*; + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum SmithRemovalReason { + LostMembership, + OfflineTooLong, + Blacklisted, +} + +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum SmithStatus { + /// The identity has been invited by a smith but has not accepted yet + Invited, + /// The identity has accepted to eventually become a smith + Pending, + /// The identity has reached the requirements to become a smith and can now goGoOnline() or invite/certify other smiths + Smith, + /// The identity has been removed from the smiths set but is kept to keep track of its certifications + Excluded, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_support::traits::StorageVersion; + use pallet_authority_members::SessionIndex; + use sp_runtime::traits::{Convert, IsMember}; + use sp_std::collections::btree_map::BTreeMap; + use sp_std::vec; + use sp_std::vec::Vec; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet<T>(_); + + /// The pallet's config trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// To only allow WoT members to be invited + type IsWoTMember: IsMember<Self::IdtyIndex>; + /// Notify when a smith is removed (for authority-members to react) + type OnSmithDelete: traits::OnSmithDelete<Self::IdtyIndex>; + /// The overarching event type. + type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; + /// A short identity index. + type IdtyIndex: Parameter + + Member + + AtLeast32BitUnsigned + + Codec + + Default + + Copy + + MaybeSerializeDeserialize + + Debug + + MaxEncodedLen; + /// Identifier for an authority-member + type MemberId: Copy + Ord + MaybeSerializeDeserialize + Parameter; + /// Something that gives the IdtyId of an AccountId + type IdtyIdOf: Convert<Self::AccountId, Option<Self::IdtyIndex>>; + /// Something that give the owner key of an identity + type OwnerKeyOf: Convert<Self::IdtyIndex, Option<Self::AccountId>>; + /// Something that gives the IdtyId of an AccountId + type IdtyIdOfAuthorityId: Convert<Self::MemberId, Option<Self::IdtyIndex>>; + /// Maximum number of active certifications by issuer + #[pallet::constant] + type MaxByIssuer: Get<u32>; + /// Minimum number of certifications to become a Smith + #[pallet::constant] + type MinCertForMembership: Get<u32>; + /// Maximum duration of inactivity before a smith is removed + #[pallet::constant] + type SmithInactivityMaxDuration: Get<u32>; + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; + } + + /// Events type. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event<T: Config> { + /// An identity is being inivited to become a smith + InvitationSent { + idty_index: T::IdtyIndex, + invited_by: T::IdtyIndex, + }, + /// The invitation has been accepted + InvitationAccepted { idty_index: T::IdtyIndex }, + /// Certification received + CertificationReceived { + idty_index: T::IdtyIndex, + issued_by: T::IdtyIndex, + }, + /// A smith gathered enough certifications to become an authority (can call `go_online()`). + PromotedToSmith { idty_index: T::IdtyIndex }, + /// A smith has been removed from the smiths set + SmithExcluded { idty_index: T::IdtyIndex }, + } + + #[pallet::genesis_config] + pub struct GenesisConfig<T: Config> { + pub initial_smiths: BTreeMap<T::IdtyIndex, (bool, Vec<T::IdtyIndex>)>, + } + + #[cfg(feature = "std")] + impl<T: Config> Default for GenesisConfig<T> { + fn default() -> Self { + Self { + initial_smiths: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { + fn build(&self) { + CurrentSession::<T>::put(0); + let mut cert_meta_by_issuer = BTreeMap::<T::IdtyIndex, Vec<T::IdtyIndex>>::new(); + for (receiver, (is_online, issuers)) in &self.initial_smiths { + // Forbid self-cert + assert!( + !issuers.contains(receiver), + "Identity cannot certify it-self." + ); + + let mut issuers_: Vec<_> = Vec::with_capacity(issuers.len()); + for issuer in issuers { + // Count issued certs + cert_meta_by_issuer + .entry(*issuer) + .or_insert(vec![]) + .push(*receiver); + issuers_.push(*issuer); + } + + // Write CertsByReceiver + issuers_.sort(); + let issuers_count = issuers_.len(); + let smith_status = if issuers_count >= T::MinCertForMembership::get() as usize { + SmithStatus::Smith + } else { + SmithStatus::Pending + }; + Smiths::<T>::insert( + receiver, + SmithMeta { + status: smith_status, + expires_on: if *is_online { + None + } else { + Some(CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get()) + }, + issued_certs: vec![], + received_certs: issuers_, + }, + ); + ExpiresOn::<T>::append( + CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get(), + receiver, + ); + } + + for (issuer, issued_certs) in cert_meta_by_issuer { + // Write CertsByIssuer + Smiths::<T>::mutate(issuer, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + smith_meta.issued_certs = issued_certs; + } + }); + } + } + } + + /// maps identity index to smith status + #[pallet::storage] + #[pallet::getter(fn smiths)] + pub type Smiths<T: Config> = + StorageMap<_, Twox64Concat, T::IdtyIndex, SmithMeta<T::IdtyIndex>, OptionQuery>; + + /// maps session index to possible smith removals + #[pallet::storage] + #[pallet::getter(fn expires_on)] + pub type ExpiresOn<T: Config> = + StorageMap<_, Twox64Concat, SessionIndex, Vec<T::IdtyIndex>, OptionQuery>; + + /// stores the current session index + #[pallet::storage] + #[pallet::getter(fn current_session)] + pub type CurrentSession<T: Config> = StorageValue<_, SessionIndex, ValueQuery>; + + // ERRORS // + + #[pallet::error] + pub enum Error<T> { + /// Issuer of anything (invitation, acceptance, certification) must have an identity ID + OriginMustHaveAnIdentity, + /// Issuer must be known as a potential smith + OriginHasNeverBeenInvited, + /// Invitation is reseverd to smiths + InvitationIsASmithPrivilege, + /// Invitation is reseverd to online smiths + InvitationIsAOnlineSmithPrivilege, + /// Invitation must not have been accepted yet + InvitationAlreadyAccepted, + /// Invitation of an already known smith is forbidden except if it has been excluded + InvitationOfExistingNonExcluded, + /// Invitation of a non-member (of the WoT) is forbidden + InvitationOfNonMember, + /// Certification cannot be made on someone who has not accepted an invitation + CertificationMustBeAgreed, + /// Certification cannot be made on excluded + CertificationOnExcludedIsForbidden, + /// Issuer must be a smith + CertificationIsASmithPrivilege, + /// Only online smiths can certify + CertificationIsAOnlineSmithPrivilege, + /// Smith cannot certify itself + CertificationOfSelfIsForbidden, + /// Receiver must be invited by another smith + CertificationReceiverMustHaveBeenInvited, + /// Receiver must not already have this certification + CertificationAlreadyExists, + /// A smith has a limited stock of certifications + CertificationStockFullyConsumed, + } + + #[pallet::call] + impl<T: Config> Pallet<T> { + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::invite_smith())] + pub fn invite_smith( + origin: OriginFor<T>, + receiver: T::IdtyIndex, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin.clone())?; + let issuer = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; + Self::check_invite_smith(issuer, receiver)?; + Self::do_invite_smith(issuer, receiver); + Ok(().into()) + } + + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::accept_invitation())] + pub fn accept_invitation(origin: OriginFor<T>) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin.clone())?; + let receiver = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; + Self::check_accept_invitation(receiver)?; + Self::do_accept_invitation(receiver)?; + Ok(().into()) + } + + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::certify_smith())] + pub fn certify_smith( + origin: OriginFor<T>, + receiver: T::IdtyIndex, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let issuer = + T::IdtyIdOf::convert(who.clone()).ok_or(Error::<T>::OriginMustHaveAnIdentity)?; + Self::check_certify_smith(issuer, receiver)?; + Self::do_certify_smith(receiver, issuer); + Ok(().into()) + } + } +} + +impl<T: Config> Pallet<T> { + fn check_invite_smith( + issuer: T::IdtyIndex, + receiver: T::IdtyIndex, + ) -> DispatchResultWithPostInfo { + let issuer = Smiths::<T>::get(issuer).ok_or(Error::<T>::OriginHasNeverBeenInvited)?; + ensure!( + issuer.status == SmithStatus::Smith, + Error::<T>::InvitationIsASmithPrivilege + ); + ensure!( + issuer.expires_on.is_none(), + Error::<T>::InvitationIsAOnlineSmithPrivilege + ); + if let Some(receiver_meta) = Smiths::<T>::get(receiver) { + ensure!( + receiver_meta.status == SmithStatus::Excluded, + Error::<T>::InvitationOfExistingNonExcluded + ); + } + ensure!( + T::IsWoTMember::is_member(&receiver), + Error::<T>::InvitationOfNonMember + ); + + Ok(().into()) + } + + fn do_invite_smith(issuer: T::IdtyIndex, receiver: T::IdtyIndex) { + let new_expires_on = CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get(); + let mut existing = Smiths::<T>::get(receiver).unwrap_or_default(); + existing.status = SmithStatus::Invited; + existing.expires_on = Some(new_expires_on); + existing.received_certs = vec![]; + Smiths::<T>::insert(receiver, existing); + ExpiresOn::<T>::append(new_expires_on, receiver); + Self::deposit_event(Event::<T>::InvitationSent { + idty_index: receiver, + invited_by: issuer, + }); + } + + fn check_accept_invitation(receiver: T::IdtyIndex) -> DispatchResultWithPostInfo { + let pretender_status = Smiths::<T>::get(receiver) + .ok_or(Error::<T>::OriginHasNeverBeenInvited)? + .status; + ensure!( + pretender_status == SmithStatus::Invited, + Error::<T>::InvitationAlreadyAccepted + ); + Ok(().into()) + } + + fn do_accept_invitation(receiver: T::IdtyIndex) -> DispatchResultWithPostInfo { + Smiths::<T>::mutate(receiver, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + smith_meta.status = SmithStatus::Pending; + } + }); + Self::deposit_event(Event::<T>::InvitationAccepted { + idty_index: receiver, + }); + Ok(().into()) + } + + fn check_certify_smith( + issuer_index: T::IdtyIndex, + receiver_index: T::IdtyIndex, + ) -> DispatchResultWithPostInfo { + ensure!( + issuer_index != receiver_index, + Error::<T>::CertificationOfSelfIsForbidden + ); + let issuer = Smiths::<T>::get(issuer_index).ok_or(Error::<T>::OriginHasNeverBeenInvited)?; + ensure!( + issuer.status == SmithStatus::Smith, + Error::<T>::CertificationIsASmithPrivilege + ); + ensure!( + issuer.expires_on.is_none(), + Error::<T>::CertificationIsAOnlineSmithPrivilege + ); + let issued_certs = issuer.issued_certs.len(); + ensure!( + issued_certs < T::MaxByIssuer::get() as usize, + Error::<T>::CertificationStockFullyConsumed + ); + let receiver = Smiths::<T>::get(receiver_index) + .ok_or(Error::<T>::CertificationReceiverMustHaveBeenInvited)?; + ensure!( + receiver.status != SmithStatus::Invited, + Error::<T>::CertificationMustBeAgreed + ); + ensure!( + receiver.status != SmithStatus::Excluded, + Error::<T>::CertificationOnExcludedIsForbidden + ); + ensure!( + receiver + .received_certs + .binary_search(&issuer_index) + .is_err(), + Error::<T>::CertificationAlreadyExists + ); + + Ok(().into()) + } + + fn do_certify_smith(receiver: T::IdtyIndex, issuer: T::IdtyIndex) { + Smiths::<T>::mutate(issuer, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + smith_meta.issued_certs.push(receiver); + smith_meta.issued_certs.sort(); + } + }); + Smiths::<T>::mutate(receiver, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + smith_meta.received_certs.push(issuer); + smith_meta.received_certs.sort(); + smith_meta.status = + if smith_meta.received_certs.len() >= T::MinCertForMembership::get() as usize { + SmithStatus::Smith + } else { + SmithStatus::Pending + }; + // expiry postponed + let new_expires_on = + CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get(); + smith_meta.expires_on = Some(new_expires_on); + Self::deposit_event(Event::<T>::CertificationReceived { + idty_index: receiver, + issued_by: issuer, + }); + if smith_meta.status == SmithStatus::Smith { + Self::deposit_event(Event::<T>::PromotedToSmith { + idty_index: receiver, + }); + } + // TODO: unschedule old expiry + } + }); + } + + fn on_exclude_expired_smiths(at: SessionIndex) { + if let Some(smiths_to_remove) = ExpiresOn::<T>::get(at) { + for smith in smiths_to_remove { + if let Some(smith_meta) = Smiths::<T>::get(smith) { + if let Some(expires_on) = smith_meta.expires_on { + if expires_on == at { + Self::_do_exclude_smith(smith, SmithRemovalReason::OfflineTooLong); + } + } + } + } + } + } + + pub fn on_removed_wot_member(idty_index: T::IdtyIndex) { + if Smiths::<T>::get(idty_index).is_some() { + Self::_do_exclude_smith(idty_index, SmithRemovalReason::LostMembership); + } + } + + fn _do_exclude_smith(idty_index: T::IdtyIndex, reason: SmithRemovalReason) { + let mut lost_certs = vec![]; + Smiths::<T>::mutate(idty_index, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + smith_meta.expires_on = None; + smith_meta.status = SmithStatus::Excluded; + for cert in &smith_meta.received_certs { + lost_certs.push(*cert); + } + smith_meta.received_certs = vec![]; + // N.B.: the issued certs are kept in case the smith joins back + } + }); + // We remove the lost certs from their issuer's stock + for lost_cert in lost_certs { + Smiths::<T>::mutate(lost_cert, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + if let Ok(index) = smith_meta.issued_certs.binary_search(&idty_index) { + smith_meta.issued_certs.remove(index); + } + } + }); + } + // Deletion done: notify (authority-members) for cascading + T::OnSmithDelete::on_smith_delete(idty_index, reason); + Self::deposit_event(Event::<T>::SmithExcluded { idty_index }); + } + + pub fn on_smith_goes_online(idty_index: T::IdtyIndex) { + if let Some(smith_meta) = Smiths::<T>::get(idty_index) { + if smith_meta.expires_on.is_some() { + Smiths::<T>::mutate(idty_index, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + // As long as the smith is online, it cannot expire + smith_meta.expires_on = None; + // FIXME: unschedule old expiry + } + }); + } + } + } + + pub fn on_smith_goes_offline(idty_index: T::IdtyIndex) { + if let Some(smith_meta) = Smiths::<T>::get(idty_index) { + if smith_meta.expires_on.is_none() { + Smiths::<T>::mutate(idty_index, |maybe_smith_meta| { + if let Some(smith_meta) = maybe_smith_meta { + // As long as the smith is online, it cannot expire + let new_expires_on = + CurrentSession::<T>::get() + T::SmithInactivityMaxDuration::get(); + smith_meta.expires_on = Some(new_expires_on); + ExpiresOn::<T>::append(new_expires_on, idty_index); + } + }); + } + } + } + + fn provide_is_member(idty_id: &T::IdtyIndex) -> bool { + let Some(smith) = Smiths::<T>::get(idty_id) else { + return false; + }; + smith.status == SmithStatus::Smith + } +} + +impl<T: Config> sp_runtime::traits::IsMember<T::IdtyIndex> for Pallet<T> { + fn is_member(idty_id: &T::IdtyIndex) -> bool { + Self::provide_is_member(idty_id) + } +} diff --git a/pallets/smith-members/src/mock.rs b/pallets/smith-members/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..cd2398e4dc2ed48618d6f24b50b0186e3d34bba2 --- /dev/null +++ b/pallets/smith-members/src/mock.rs @@ -0,0 +1,123 @@ +// Copyright 2021-2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![cfg(test)] + +use crate::{self as pallet_smith_members}; +use frame_support::pallet_prelude::Hooks; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_core::H256; +use sp_runtime::traits::{ConvertInto, IsMember}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, Perbill, +}; + +parameter_types! { + pub static OnOffencePerbill: Vec<Perbill> = Default::default(); + pub static OffenceWeight: Weight = Default::default(); +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>; +type Block = frame_system::mocking::MockBlock<Runtime>; + +frame_support::construct_runtime!( + pub struct Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event<T>}, + Smith: pallet_smith_members::{Pallet, Config<T>, Storage, Event<T>}, + } +); + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup<Self::AccountId>; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +pub struct EveryoneExceptIdZero; +impl IsMember<u64> for EveryoneExceptIdZero { + fn is_member(member_id: &u64) -> bool { + member_id != &0 && member_id != &10 + } +} + +impl pallet_smith_members::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type IdtyIndex = u64; + type IsWoTMember = EveryoneExceptIdZero; + type IdtyIdOf = ConvertInto; + type MinCertForMembership = ConstU32<2>; + type MaxByIssuer = ConstU32<3>; + type SmithInactivityMaxDuration = ConstU32<5>; + type OnSmithDelete = (); + type IdtyIdOfAuthorityId = ConvertInto; + type MemberId = u64; + type OwnerKeyOf = ConvertInto; + type WeightInfo = (); +} + +pub fn new_test_ext( + genesis_config: crate::pallet::GenesisConfig<Runtime>, +) -> sp_io::TestExternalities { + GenesisConfig { + system: SystemConfig::default(), + smith: genesis_config, + } + .build_storage() + .unwrap() + .into() +} + +pub fn run_to_block(n: u64) { + while System::block_number() < n { + Smith::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::reset_events(); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Smith::on_initialize(System::block_number()); + } +} diff --git a/pallets/smith-members/src/tests.rs b/pallets/smith-members/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..a843a17a962cdf2f5e2d044ac283ee6695ba5760 --- /dev/null +++ b/pallets/smith-members/src/tests.rs @@ -0,0 +1,577 @@ +// Copyright 2021-2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![cfg(test)] + +use super::*; +use crate::mock::{new_test_ext, run_to_block, Runtime, RuntimeEvent, RuntimeOrigin, System}; +use frame_support::{assert_err, assert_ok}; + +use crate::SmithStatus::{Excluded, Invited, Pending, Smith}; +#[cfg(test)] +use maplit::btreemap; +use pallet_authority_members::OnNewSession; + +#[test] +fn process_to_become_a_smith_and_lose_it() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![]), + 4 => (false, vec![]), + ], + }) + .execute_with(|| { + // Go online to be able to invite+certify + Pallet::<Runtime>::on_smith_goes_online(1); + Pallet::<Runtime>::on_smith_goes_online(2); + // Events cannot be recorded on genesis + run_to_block(1); + // State before + assert_eq!(Smiths::<Runtime>::get(5), None); + // Try to invite + assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 5)); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::InvitationSent { + idty_index: 5, + invited_by: 1, + })); + // Accept invitation + assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed( + 5 + ))); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::InvitationAccepted { + idty_index: 5, + })); + // State after + assert_eq!( + Smiths::<Runtime>::get(5).unwrap(), + SmithMeta { + status: SmithStatus::Pending, + expires_on: Some(5), + issued_certs: vec![], + received_certs: vec![], + } + ); + // Then certification 1/2 + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(1), + 5 + )); + System::assert_has_event(RuntimeEvent::Smith( + Event::<Runtime>::CertificationReceived { + idty_index: 5, + issued_by: 1, + }, + )); + assert_eq!( + Smiths::<Runtime>::get(5).unwrap(), + SmithMeta { + status: SmithStatus::Pending, + expires_on: Some(5), + issued_certs: vec![], + received_certs: vec![1], + } + ); + // Then certification 2/2 + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(2), + 5 + )); + System::assert_has_event(RuntimeEvent::Smith( + Event::<Runtime>::CertificationReceived { + idty_index: 5, + issued_by: 1, + }, + )); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::PromotedToSmith { + idty_index: 5, + })); + assert_eq!( + Smiths::<Runtime>::get(5).unwrap(), + SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(5), + issued_certs: vec![], + received_certs: vec![1, 2], + } + ); + // Go online to be able to invite+certify + Pallet::<Runtime>::on_smith_goes_offline(1); + Pallet::<Runtime>::on_smith_goes_offline(2); + + // On session 4 everything if fine + Pallet::<Runtime>::on_new_session(4); + assert!(Smiths::<Runtime>::get(1).is_some()); + assert!(Smiths::<Runtime>::get(2).is_some()); + assert!(Smiths::<Runtime>::get(5).is_some()); + // On session 5 no more smiths because of lack of activity + Pallet::<Runtime>::on_new_session(5); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded { + idty_index: 1, + })); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded { + idty_index: 2, + })); + System::assert_has_event(RuntimeEvent::Smith(Event::<Runtime>::SmithExcluded { + idty_index: 5, + })); + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + assert_eq!( + Smiths::<Runtime>::get(5), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + }); +} + +#[test] +fn should_have_checks_on_certify() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![4]), + 4 => (false, vec![1, 2]), + ], + }) + .execute_with(|| { + // Go online to be able to invite+certify + Pallet::<Runtime>::on_smith_goes_online(1); + // Initially + assert_eq!( + Smiths::<Runtime>::get(1).unwrap(), + SmithMeta { + status: Smith, + expires_on: None, + issued_certs: vec![4], + received_certs: vec![2, 3, 4], + } + ); + assert_eq!( + Smiths::<Runtime>::get(2).unwrap(), + SmithMeta { + status: Smith, + expires_on: Some(5), + issued_certs: vec![1, 4], + received_certs: vec![3, 4], + } + ); + assert_eq!( + Smiths::<Runtime>::get(3).unwrap(), + SmithMeta { + status: Pending, + expires_on: Some(5), + issued_certs: vec![1, 2], + received_certs: vec![4], + } + ); + assert_eq!( + Smiths::<Runtime>::get(4).unwrap(), + SmithMeta { + status: Smith, + expires_on: Some(5), + issued_certs: vec![1, 2, 3], + received_certs: vec![1, 2], + } + ); + + // Tries all possible errors + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(0), 1), + Error::<Runtime>::OriginHasNeverBeenInvited + ); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 1), + Error::<Runtime>::CertificationOfSelfIsForbidden + ); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(3), 5), + Error::<Runtime>::CertificationIsASmithPrivilege + ); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 6), + Error::<Runtime>::CertificationReceiverMustHaveBeenInvited + ); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 4), + Error::<Runtime>::CertificationAlreadyExists + ); + + // #3: state before + assert_eq!( + Smiths::<Runtime>::get(3).unwrap(), + SmithMeta { + status: Pending, + expires_on: Some(5), + issued_certs: vec![1, 2], + received_certs: vec![4], + } + ); + // Try to certify #3 + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(1), + 3 + )); + // #3: state after + assert_eq!( + Smiths::<Runtime>::get(3).unwrap(), + SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(5), + issued_certs: vec![1, 2], + received_certs: vec![1, 4], + } + ); + }); +} + +#[test] +fn smith_activity_postpones_expiration() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![]), + 4 => (false, vec![]) + ], + }) + .execute_with(|| { + // On session 4 everything is fine + Pallet::<Runtime>::on_new_session(4); + assert!(Smiths::<Runtime>::get(1).is_some()); + assert!(Smiths::<Runtime>::get(2).is_some()); + + // Smith #2 is online but not #1 + Pallet::<Runtime>::on_smith_goes_online(2); + + // On session 5: exclusion for lack of activity + Pallet::<Runtime>::on_new_session(5); + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + // issued_certs is empty because #1 was excluded + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: None, + issued_certs: vec![], + received_certs: vec![3, 4], + }) + ); + + // Smith #2 goes offline + Pallet::<Runtime>::on_new_session(6); + Pallet::<Runtime>::on_smith_goes_offline(2); + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(11), + issued_certs: vec![], + received_certs: vec![3, 4], + }) + ); + // Still not expired on session 10 + Pallet::<Runtime>::on_new_session(10); + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(11), + issued_certs: vec![], + received_certs: vec![3, 4], + }) + ); + // But expired on session 11 + Pallet::<Runtime>::on_new_session(11); + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: vec![], + received_certs: vec![] + }) + ); + }); +} + +#[test] +fn smith_coming_back_recovers_its_issued_certs() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![1, 4]), + 4 => (false, vec![]), + ], + }) + .execute_with(|| { + // Not activity for Smith #2 + Pallet::<Runtime>::on_smith_goes_online(1); + Pallet::<Runtime>::on_smith_goes_online(3); + Pallet::<Runtime>::on_smith_goes_online(4); + // Smith #2 gets excluded + Pallet::<Runtime>::on_new_session(5); + // The issued certs are preserved + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: Excluded, + expires_on: None, + issued_certs: vec![1], + received_certs: vec![] + }) + ); + // Smith #2 comes back + assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 2)); + assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed( + 2 + ))); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(1), + 2 + )); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(3), + 2 + )); + // Smith #2 is back with its issued certs recovered, but not its received certs + assert_eq!( + Smiths::<Runtime>::get(2), + Some(SmithMeta { + status: Smith, + expires_on: Some(10), + issued_certs: vec![1], + received_certs: vec![1, 3] + }) + ); + Pallet::<Runtime>::on_smith_goes_online(2); + // We can verify it with the stock rule + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(2), + 3 + )); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(2), + 4 + )); + // Max stock is reached (3 = 1 recovered + 2 new) + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(2), 5), + Error::<Runtime>::CertificationStockFullyConsumed + ); + }); +} + +#[test] +fn certifying_on_different_status() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![1, 2]), + 4 => (false, vec![]), + ], + }) + .execute_with(|| { + // Go online to be able to invite+certify + Pallet::<Runtime>::on_smith_goes_online(1); + Pallet::<Runtime>::on_smith_goes_online(2); + Pallet::<Runtime>::on_smith_goes_online(3); + // State before + assert_eq!(Smiths::<Runtime>::get(5), None); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationReceiverMustHaveBeenInvited + ); + + // After invitation + assert_ok!(Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 5)); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Invited); + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationMustBeAgreed + ); + + // After acceptation + assert_ok!(Pallet::<Runtime>::accept_invitation(RuntimeOrigin::signed( + 5 + ))); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(1), + 5 + )); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Pending); + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(2), + 5 + )); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Smith); + + // After being a smith + assert_ok!(Pallet::<Runtime>::certify_smith( + RuntimeOrigin::signed(3), + 5 + )); + + Pallet::<Runtime>::on_smith_goes_online(1); + Pallet::<Runtime>::on_smith_goes_online(2); + Pallet::<Runtime>::on_new_session(5); + assert_eq!(Smiths::<Runtime>::get(1).unwrap().status, Smith); + assert_eq!(Smiths::<Runtime>::get(2).unwrap().status, Smith); + assert_eq!(Smiths::<Runtime>::get(5).unwrap().status, Excluded); + + // After being excluded + assert_err!( + Pallet::<Runtime>::certify_smith(RuntimeOrigin::signed(1), 5), + Error::<Runtime>::CertificationOnExcludedIsForbidden + ); + }); +} + +#[test] +fn invitation_on_non_wot_member() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![1, 2]), + 4 => (false, vec![]), + ], + }) + .execute_with(|| { + // Go online to be able to invite+certify + Pallet::<Runtime>::on_smith_goes_online(1); + // State before + assert_eq!(Smiths::<Runtime>::get(10), None); + + // After invitation + assert_err!( + Pallet::<Runtime>::invite_smith(RuntimeOrigin::signed(1), 10), + Error::<Runtime>::InvitationOfNonMember + ); + }); +} + +#[test] +fn losing_wot_membership_cascades_to_smith_members() { + new_test_ext(GenesisConfig { + initial_smiths: btreemap![ + 1 => (false, vec![2, 3, 4]), + 2 => (false, vec![3, 4]), + 3 => (false, vec![1, 2]), + 4 => (false, vec![]), + ], + }) + .execute_with(|| { + // State before + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: Smith, + expires_on: Some(5), + issued_certs: vec![3], + received_certs: vec![2, 3, 4], + }) + ); + assert_eq!( + Smiths::<Runtime>::get(1).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(2).unwrap().issued_certs, + Vec::<u64>::from([1, 3]) + ); + assert_eq!( + Smiths::<Runtime>::get(3).unwrap().issued_certs, + Vec::<u64>::from([1, 2]) + ); + assert_eq!( + Smiths::<Runtime>::get(4).unwrap().issued_certs, + Vec::<u64>::from([1, 2]) + ); + + Pallet::<Runtime>::on_removed_wot_member(1); + + // Excluded + assert_eq!( + Smiths::<Runtime>::get(1), + Some(SmithMeta { + status: Excluded, + expires_on: None, + issued_certs: vec![3], + received_certs: vec![], + }) + ); + // Issued certifications updated for certifiers of 1 + assert_eq!( + Smiths::<Runtime>::get(1).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(2).unwrap().issued_certs, + Vec::<u64>::from([3]) + ); + assert_eq!( + Smiths::<Runtime>::get(3).unwrap().issued_certs, + Vec::<u64>::from([2]) + ); + assert_eq!( + Smiths::<Runtime>::get(4).unwrap().issued_certs, + Vec::<u64>::from([2]) + ); + }); +} diff --git a/pallets/smith-members/src/traits.rs b/pallets/smith-members/src/traits.rs new file mode 100644 index 0000000000000000000000000000000000000000..f59b6fc1c775e15ba69e32704da9238516a18db4 --- /dev/null +++ b/pallets/smith-members/src/traits.rs @@ -0,0 +1,8 @@ +use crate::SmithRemovalReason; + +pub trait OnSmithDelete<IdtyIndex> { + fn on_smith_delete(idty_index: IdtyIndex, reason: SmithRemovalReason); +} +impl<IdtyIndex> OnSmithDelete<IdtyIndex> for () { + fn on_smith_delete(_: IdtyIndex, _: SmithRemovalReason) {} +} diff --git a/pallets/smith-members/src/types.rs b/pallets/smith-members/src/types.rs new file mode 100644 index 0000000000000000000000000000000000000000..fcccd3468e8c6577e3dc68d9781fc3decc7b5c58 --- /dev/null +++ b/pallets/smith-members/src/types.rs @@ -0,0 +1,49 @@ +// Copyright 2021 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +//! Various basic types for use in the identity pallet. + +use crate::SmithStatus; +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::*; +use scale_info::TypeInfo; +use sp_staking::SessionIndex; +use sp_std::vec::Vec; + +/// certification metadata attached to an identity +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct SmithMeta<IdtyIndex> { + /// current status of the smith + pub status: SmithStatus, + /// the session at which the smith will expire (for lack of validation activity) + pub expires_on: Option<SessionIndex>, + /// the certifications issued to other smiths + pub issued_certs: Vec<IdtyIndex>, + /// the certifications received from other smiths + pub received_certs: Vec<IdtyIndex>, +} + +/// By default, a smith has the least possible privileges +impl<IdtyIndex> Default for SmithMeta<IdtyIndex> { + fn default() -> Self { + Self { + status: SmithStatus::Excluded, + expires_on: None, + issued_certs: Vec::<IdtyIndex>::new(), + received_certs: Vec::<IdtyIndex>::new(), + } + } +} diff --git a/pallets/smith-members/src/weights.rs b/pallets/smith-members/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..b18e0cef9fe76aa09afbd4b3544cfcd21652ac0d --- /dev/null +++ b/pallets/smith-members/src/weights.rs @@ -0,0 +1,38 @@ +// Copyright 2021-2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![allow(clippy::unnecessary_cast)] + +use frame_support::weights::Weight; + +/// Weight functions needed for pallet. +pub trait WeightInfo { + fn invite_smith() -> Weight; + fn accept_invitation() -> Weight; + fn certify_smith() -> Weight; +} + +impl WeightInfo for () { + fn invite_smith() -> Weight { + Weight::zero() + } + fn accept_invitation() -> Weight { + Weight::zero() + } + fn certify_smith() -> Weight { + Weight::zero() + } +} diff --git a/resources/gdev.yaml b/resources/gdev.yaml index 80296c9699bd4309bd795bcd3ea1e1bc74075a78..a901457535966732d744522220a1b26ce5dfe1ee 100644 --- a/resources/gdev.yaml +++ b/resources/gdev.yaml @@ -41,20 +41,10 @@ parameters: wot_min_cert_for_create_idty_right: 3 # ----- SMITH WOT ----- - # Duration to wait between two emitted certifications, in blocks. 14400 blocks = 24h = 1 day. - smith_cert_period: 14400 # Maximum quantity of currently valid certifications emitted by a same issuer. 15 certs. smith_cert_max_by_issuer: 15 - # Minimum quantity of smith certifications received to be able to smith certify someone else. - smith_cert_min_received_cert_to_issue_cert: 3 - # Validity duration of a certification, in blocks. 2102400 blocks = 146 days. - smith_cert_validity_period: 2102400 - # Validity duration of a membership. 1051200 blocks = 73 days. - smith_membership_period: 1051200 - # Validity duration of a pending membership. 172800 blocks = 12 days. - smith_pending_membership_period: 172800 - # Delay a new smith member must observe before being able to emit a smith certification. 14400 blocks = 24h = 1 day. - smith_wot_first_cert_issuable_on: 14400 + # Maximum duration a smith can be offline without being excluded + smith_inactivity_max_duration: 48 # Number of required received smith certs to become a smith member smith_wot_min_cert_for_membership: 3 diff --git a/resources/metadata.scale b/resources/metadata.scale index 86dc5fa76adcc7628a8dd62903866e06603f0719..d9b927842841c74ddf26cd400b3b4a304a3c6eeb 100644 Binary files a/resources/metadata.scale and b/resources/metadata.scale differ diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index 620eb3c8c23fbc1ebbc97cec505f161934325897..04ca8dd0cb301d281b95f7a23ae3e6821c12f2d4 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -35,6 +35,7 @@ std = [ 'frame-system/std', 'log/std', 'pallet-authority-members/std', + 'pallet-smith-members/std', 'pallet-babe/std', 'pallet-balances/std', 'pallet-certification/std', @@ -73,6 +74,7 @@ try-runtime = [ [dependencies] duniter-primitives = { path = '../../primitives/duniter', default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } +pallet-smith-members = { path = '../../pallets/smith-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } pallet-distance = { path = "../../pallets/distance", default-features = false } pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false } diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs index 8cb679c6680d6a74ac760d6a4556dc6744fbc4df..c529252726f47da3cdfd6754e6b067047bd63d56 100644 --- a/runtime/common/src/handlers.rs +++ b/runtime/common/src/handlers.rs @@ -17,9 +17,8 @@ use super::entities::*; use super::{AccountId, IdtyIndex}; use frame_support::dispatch::UnfilteredDispatchable; -use frame_support::instances::{Instance1, Instance2}; use frame_support::pallet_prelude::Weight; -use frame_support::Parameter; +use pallet_smith_members::SmithRemovalReason; // new session handler pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>); @@ -39,7 +38,8 @@ impl< Inner: sp_membership::traits::OnEvent<IdtyIndex>, Runtime: frame_system::Config<AccountId = AccountId> + pallet_identity::Config<IdtyData = IdtyData, IdtyIndex = IdtyIndex> - + pallet_membership::Config<Instance1> + + pallet_membership::Config + + pallet_smith_members::Config<IdtyIndex = IdtyIndex> + pallet_universal_dividend::Config, > sp_membership::traits::OnEvent<IdtyIndex> for OnMembershipEventHandler<Inner, Runtime> { @@ -55,6 +55,7 @@ impl< ); } } + pallet_smith_members::Pallet::<Runtime>::on_removed_wot_member(*idty_index); } // when main membership is acquired, it starts getting right to UD sp_membership::Event::MembershipAdded(idty_index) => { @@ -75,60 +76,6 @@ impl< } } -// smith membership event handler -pub struct OnSmithMembershipEventHandler<Inner, Runtime>( - core::marker::PhantomData<(Inner, Runtime)>, -); -impl< - IdtyIndex: Copy + Parameter, - Inner: sp_membership::traits::OnEvent<IdtyIndex>, - Runtime: frame_system::Config<AccountId = AccountId> - + pallet_identity::Config<IdtyIndex = IdtyIndex> - + pallet_authority_members::Config<MemberId = IdtyIndex> - + pallet_membership::Config<Instance2>, - > sp_membership::traits::OnEvent<IdtyIndex> for OnSmithMembershipEventHandler<Inner, Runtime> -{ - fn on_event(membership_event: &sp_membership::Event<IdtyIndex>) { - (match membership_event { - sp_membership::Event::MembershipAdded(_idty_index) => { - // nothing when smith membership acquired - // user will have to claim authority membership - } - sp_membership::Event::MembershipRemoved(idty_index) => { - let call = pallet_authority_members::Call::<Runtime>::remove_member { - member_id: *idty_index, - }; - if let Err(e) = - call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into()) - { - sp_std::if_std! { - println!("faid to remove member: {:?}", e) - } - } - } - _ => (), - }); - Inner::on_event(membership_event) - } -} - -// authority member removal handler -// TODO refac smith wot -// or document the link between smith membership and authority member -pub struct OnRemovedAuthorityMemberHandler<Runtime>(core::marker::PhantomData<Runtime>); -impl<Runtime> pallet_authority_members::traits::OnRemovedMember<IdtyIndex> - for OnRemovedAuthorityMemberHandler<Runtime> -where - Runtime: frame_system::Config + pallet_membership::Config<Instance2, IdtyId = IdtyIndex>, -{ - fn on_removed_member(idty_index: IdtyIndex) { - pallet_membership::Pallet::<Runtime, Instance2>::do_remove_membership( - idty_index, - pallet_membership::MembershipRemovalReason::System, - ); - } -} - // spend treasury handler pub struct TreasurySpendFunds<Runtime>(core::marker::PhantomData<Runtime>); impl<Runtime> pallet_treasury::SpendFunds<Runtime> for TreasurySpendFunds<Runtime> @@ -144,3 +91,21 @@ where *missed_any = true; } } + +pub struct OnSmithDeletedHandler<Runtime>(core::marker::PhantomData<Runtime>); +impl<Runtime> pallet_smith_members::traits::OnSmithDelete<Runtime::MemberId> + for OnSmithDeletedHandler<Runtime> +where + Runtime: pallet_authority_members::Config, +{ + fn on_smith_delete(idty_index: Runtime::MemberId, _reason: SmithRemovalReason) { + let call = pallet_authority_members::Call::<Runtime>::remove_member { + member_id: idty_index, + }; + if let Err(e) = call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into()) { + sp_std::if_std! { + println!("faid to remove member: {:?}", e) + } + } + } +} diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs index e61c1996d27c25bf6d78855917b6e09e5b954944..f1cfbf2995723fa7e5fdd2bae33afb1dfeea721b 100644 --- a/runtime/common/src/pallets_config.rs +++ b/runtime/common/src/pallets_config.rs @@ -236,14 +236,15 @@ macro_rules! pallets_config { } impl pallet_authority_members::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type IsMember = SmithMembership; + type IsMember = SmithMembers; type OnNewSession = OnNewSessionHandler<Runtime>; - type OnRemovedMember = OnRemovedAuthorityMemberHandler<Runtime>; type MemberId = IdtyIndex; type MemberIdOf = common_runtime::providers::IdentityIndexOf<Self>; type MaxAuthorities = MaxAuthorities; type RemoveMemberOrigin = EnsureRoot<Self::AccountId>; type WeightInfo = common_runtime::weights::pallet_authority_members::WeightInfo<Runtime>; + type OnIncomingMember = SmithMembers; + type OnOutgoingMember = SmithMembers; } impl pallet_authorship::Config for Runtime { type EventHandler = ImOnline; @@ -453,11 +454,9 @@ macro_rules! pallets_config { // WEB OF TRUST // - use frame_support::instances::Instance1; - impl pallet_duniter_wot::Config<Instance1> for Runtime { + impl pallet_duniter_wot::Config for Runtime { type FirstIssuableOn = WotFirstCertIssuableOn; type IsDistanceOk = common_runtime::providers::MainWotIsDistanceOk<Runtime>; - type IsSubWot = frame_support::traits::ConstBool<false>; type MinCertForMembership = WotMinCertForMembership; type MinCertForCreateIdtyRight = WotMinCertForCreateIdtyRight; } @@ -473,7 +472,7 @@ macro_rules! pallets_config { type ValidationPeriod = ValidationPeriod; type AutorevocationPeriod = AutorevocationPeriod; type DeletionPeriod = DeletionPeriod; - type CheckIdtyCallAllowed = (Wot, SmithSubWot); + type CheckIdtyCallAllowed = Wot; type IdtyCreationPeriod = IdtyCreationPeriod; type IdtyData = IdtyData; type IdtyIndex = IdtyIndex; @@ -481,12 +480,12 @@ macro_rules! pallets_config { type IdtyNameValidator = IdtyNameValidatorImpl; type Signer = <Signature as sp_runtime::traits::Verify>::Signer; type Signature = Signature; - type OnIdtyChange = (Wot, SmithSubWot, Quota); + type OnIdtyChange = (Wot, Quota); type RuntimeEvent = RuntimeEvent; type WeightInfo = common_runtime::weights::pallet_identity::WeightInfo<Runtime>; } - impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime { + impl pallet_membership::Config for Runtime { type CheckMembershipCallAllowed = Wot; type IdtyId = IdtyIndex; type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>; @@ -499,7 +498,7 @@ macro_rules! pallets_config { type BenchmarkSetupHandler = common_runtime::providers::BenchmarkSetupHandler<Runtime>; } - impl pallet_certification::Config<Instance1> for Runtime { + impl pallet_certification::Config for Runtime { type CertPeriod = CertPeriod; type IdtyIndex = IdtyIndex; type OwnerKeyOf = Identity; @@ -525,42 +524,21 @@ macro_rules! pallets_config { type WeightInfo = common_runtime::weights::pallet_distance::WeightInfo<Runtime>; } - // SMITHS SUB-WOT // - - use frame_support::instances::Instance2; - impl pallet_duniter_wot::Config<Instance2> for Runtime { - type FirstIssuableOn = SmithWotFirstCertIssuableOn; - type IsDistanceOk = pallet_duniter_wot::traits::DistanceAlwaysOk; - type IsSubWot = frame_support::traits::ConstBool<true>; - type MinCertForMembership = SmithWotMinCertForMembership; - type MinCertForCreateIdtyRight = frame_support::traits::ConstU32<0>; - } - - impl pallet_membership::Config<Instance2> for Runtime { - type CheckMembershipCallAllowed = SmithSubWot; - type IdtyId = IdtyIndex; - type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>; - type AccountIdOf = common_runtime::providers::IdentityAccountIdProvider<Self>; - type MembershipPeriod = SmithMembershipPeriod; - type OnEvent = OnSmithMembershipEventHandler<SmithSubWot, Runtime>; + // SMITH-MEMBERS + impl pallet_smith_members::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = common_runtime::weights::pallet_membership_smith_membership::WeightInfo<Runtime>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkSetupHandler = common_runtime::providers::BenchmarkSetupHandler<Runtime>; - } - - impl pallet_certification::Config<Instance2> for Runtime { - type CertPeriod = SmithCertPeriod; type IdtyIndex = IdtyIndex; - type OwnerKeyOf = Identity; - type CheckCertAllowed = SmithSubWot; + type IsWoTMember = common_runtime::providers::IsWoTMemberProvider<Runtime>; + type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>; + type MinCertForMembership = SmithWotMinCertForMembership; type MaxByIssuer = SmithMaxByIssuer; - type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert; - type OnNewcert = SmithSubWot; - type OnRemovedCert = SmithSubWot; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = common_runtime::weights::pallet_certification_smith_cert::WeightInfo<Runtime>; - type ValidityPeriod = SmithValidityPeriod; + type SmithInactivityMaxDuration = SmithInactivityMaxDuration; + type OnSmithDelete = OnSmithDeletedHandler<Runtime>; + type IdtyIdOfAuthorityId = sp_runtime::traits::ConvertInto; + type MemberId = IdtyIndex; + type WeightInfo = common_runtime::weights::pallet_smith_members::WeightInfo<Runtime>; + // TODO: remove as it is only used for benchmarking + type OwnerKeyOf = Identity; } pub struct TechnicalCommitteeDefaultVote; diff --git a/runtime/common/src/providers.rs b/runtime/common/src/providers.rs index 1518c1060e265e01dd49ba6a02e1b1418405a93a..ca631988e74cfd3b19417be348605c4bd58d5574 100644 --- a/runtime/common/src/providers.rs +++ b/runtime/common/src/providers.rs @@ -76,7 +76,7 @@ pub struct MainWotIsDistanceOk<T>(PhantomData<T>); impl<T> pallet_duniter_wot::traits::IsDistanceOk<<T as pallet_identity::Config>::IdtyIndex> for MainWotIsDistanceOk<T> where - T: pallet_distance::Config + pallet_duniter_wot::Config<frame_support::instances::Instance1>, + T: pallet_distance::Config + pallet_duniter_wot::Config, { fn is_distance_ok( idty_id: &<T as pallet_identity::Config>::IdtyIndex, @@ -84,11 +84,27 @@ where match pallet_distance::Pallet::<T>::identity_distance_status(idty_id) { Some((_, status)) => match status { pallet_distance::DistanceStatus::Valid => Ok(()), - pallet_distance::DistanceStatus::Invalid => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceIsInvalid.into()), - pallet_distance::DistanceStatus::Pending => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationPending.into()), + pallet_distance::DistanceStatus::Invalid => { + Err(pallet_duniter_wot::Error::<T>::DistanceIsInvalid.into()) + } + pallet_distance::DistanceStatus::Pending => { + Err(pallet_duniter_wot::Error::<T>::DistanceEvaluationPending.into()) + } }, - None => Err(pallet_duniter_wot::Error::<T, frame_support::instances::Instance1>::DistanceEvaluationNotRequested.into()), - } + None => Err(pallet_duniter_wot::Error::<T>::DistanceEvaluationNotRequested.into()), + } + } +} + +pub struct IsWoTMemberProvider<T>(PhantomData<T>); +impl<T: pallet_smith_members::Config> + sp_runtime::traits::IsMember<<T as pallet_membership::Config>::IdtyId> + for IsWoTMemberProvider<T> +where + T: pallet_distance::Config + pallet_membership::Config, +{ + fn is_member(idty_id: &T::IdtyId) -> bool { + pallet_membership::Pallet::<T>::is_member(idty_id) } } @@ -102,8 +118,8 @@ macro_rules! impl_benchmark_setup_handler { impl<T> $t for BenchmarkSetupHandler<T> where T: pallet_distance::Config, - T: pallet_certification::Config<frame_support::instances::Instance1>, - <T as pallet_certification::Config<frame_support::instances::Instance1>>::IdtyIndex: From<u32>, + T: pallet_certification::Config, + <T as pallet_certification::Config>::IdtyIndex: From<u32>, { fn force_status_ok( idty_id: &IdtyIndex, @@ -115,7 +131,11 @@ macro_rules! impl_benchmark_setup_handler { ); } fn add_cert(issuer: &IdtyIndex, receiver: &IdtyIndex) { - let _ = pallet_certification::Pallet::<T, frame_support::instances::Instance1>::do_add_cert_checked((*issuer).into(), (*receiver).into(), false); + let _ = pallet_certification::Pallet::<T>::do_add_cert_checked( + (*issuer).into(), + (*receiver).into(), + false, + ); } } }; diff --git a/runtime/common/src/weights.rs b/runtime/common/src/weights.rs index 60201d11e1e880b00a73b7a0042abd3315d76cf4..bf1e188a998c36de5146576e3317b1f0627d16b4 100644 --- a/runtime/common/src/weights.rs +++ b/runtime/common/src/weights.rs @@ -44,8 +44,7 @@ pub mod pallet_duniter_account; pub mod pallet_quota; pub mod pallet_oneshot_account; pub mod pallet_certification_cert; -pub mod pallet_certification_smith_cert; pub mod pallet_membership_membership; -pub mod pallet_membership_smith_membership; +pub mod pallet_smith_members; pub mod pallet_authority_members; pub mod paritydb_weights; diff --git a/runtime/common/src/weights/pallet_certification_smith_cert.rs b/runtime/common/src/weights/pallet_certification_smith_cert.rs deleted file mode 100644 index 7403ec2d9d9d0ad2b5eaca27b031942da3ce8477..0000000000000000000000000000000000000000 --- a/runtime/common/src/weights/pallet_certification_smith_cert.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2021-2022 Axiom-Team -// -// This file is part of Duniter-v2S. -// -// Duniter-v2S is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, version 3 of the License. -// -// Duniter-v2S is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. - -//! Autogenerated weights for `pallet_certification` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// target/release/duniter -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=* -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --header=file_header.txt -// --output=runtime/common/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_certification`. -pub struct WeightInfo<T>(PhantomData<T>); -impl<T: frame_system::Config> pallet_certification::WeightInfo for WeightInfo<T> { - /// Storage: Identity Identities (r:2 w:0) - /// Proof Skipped: Identity Identities (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2) - /// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: SmithCert StorageCertsRemovableOn (r:1 w:1) - /// Proof Skipped: SmithCert StorageCertsRemovableOn (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert CertsByReceiver (r:1 w:1) - /// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured) - fn add_cert() -> Weight { - // Proof Size summary in bytes: - // Measured: `769` - // Estimated: `6709` - // Minimum execution time: 38_312_000 picoseconds. - Weight::from_parts(39_872_000, 0) - .saturating_add(Weight::from_parts(0, 6709)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: SmithCert CertsByReceiver (r:1 w:1) - /// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2) - /// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:0) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - fn del_cert() -> Weight { - // Proof Size summary in bytes: - // Measured: `638` - // Estimated: `6578` - // Minimum execution time: 25_005_000 picoseconds. - Weight::from_parts(26_178_000, 0) - .saturating_add(Weight::from_parts(0, 6578)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: SmithCert CertsByReceiver (r:1 w:1) - /// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert StorageIdtyCertMeta (r:1000 w:1000) - /// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:0) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[2, 1000]`. - /// The range of component `i` is `[2, 1000]`. - fn remove_all_certs_received_by(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `546 + i * (35 ±0)` - // Estimated: `4020 + i * (2511 ±0)` - // Minimum execution time: 26_616_000 picoseconds. - Weight::from_parts(27_240_000, 0) - .saturating_add(Weight::from_parts(0, 4020)) - // Standard Error: 15_842 - .saturating_add(Weight::from_parts(10_835_042, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 2511).saturating_mul(i.into())) - } - /// Storage: SmithCert StorageCertsRemovableOn (r:1 w:0) - /// Proof Skipped: SmithCert StorageCertsRemovableOn (max_values: None, max_size: None, mode: Measured) - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `181` - // Estimated: `3646` - // Minimum execution time: 4_084_000 picoseconds. - Weight::from_parts(4_316_000, 0) - .saturating_add(Weight::from_parts(0, 3646)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: SmithCert CertsByReceiver (r:1 w:1) - /// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured) - fn do_remove_cert_noop() -> Weight { - // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3700` - // Minimum execution time: 5_261_000 picoseconds. - Weight::from_parts(5_742_000, 0) - .saturating_add(Weight::from_parts(0, 3700)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: SmithCert CertsByReceiver (r:1 w:1) - /// Proof Skipped: SmithCert CertsByReceiver (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert StorageIdtyCertMeta (r:2 w:2) - /// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:0) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - fn do_remove_cert() -> Weight { - // Proof Size summary in bytes: - // Measured: `638` - // Estimated: `6578` - // Minimum execution time: 22_342_000 picoseconds. - Weight::from_parts(23_355_000, 0) - .saturating_add(Weight::from_parts(0, 6578)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/runtime/common/src/weights/pallet_membership_smith_membership.rs b/runtime/common/src/weights/pallet_membership_smith_membership.rs deleted file mode 100644 index d0bd9f66811ae0a58d7d101a6250d6cf0e86eea9..0000000000000000000000000000000000000000 --- a/runtime/common/src/weights/pallet_membership_smith_membership.rs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2021-2022 Axiom-Team -// -// This file is part of Duniter-v2S. -// -// Duniter-v2S is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, version 3 of the License. -// -// Duniter-v2S is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. - -//! Autogenerated weights for `pallet_membership` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// target/release/duniter -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=* -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --header=file_header.txt -// --output=runtime/common/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_membership`. -pub struct WeightInfo<T>(PhantomData<T>); -impl<T: frame_system::Config> pallet_membership::WeightInfo for WeightInfo<T> { - /// Storage: Identity IdentityIndexOf (r:1 w:0) - /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithCert StorageIdtyCertMeta (r:1 w:0) - /// Proof Skipped: SmithCert StorageIdtyCertMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:1) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership CounterForMembership (r:1 w:1) - /// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: SmithMembership MembershipsExpireOn (r:1 w:1) - /// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured) - fn claim_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `704` - // Estimated: `4169` - // Minimum execution time: 27_429_000 picoseconds. - Weight::from_parts(28_797_000, 0) - .saturating_add(Weight::from_parts(0, 4169)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Identity IdentityIndexOf (r:1 w:0) - /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:1) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - /// Storage: Identity Identities (r:1 w:0) - /// Proof Skipped: Identity Identities (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership MembershipsExpireOn (r:2 w:2) - /// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured) - /// Storage: Parameters ParametersStorage (r:1 w:0) - /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) - fn renew_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `717` - // Estimated: `6657` - // Minimum execution time: 28_139_000 picoseconds. - Weight::from_parts(28_982_000, 0) - .saturating_add(Weight::from_parts(0, 6657)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Identity IdentityIndexOf (r:1 w:0) - /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:1 w:1) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership CounterForMembership (r:1 w:1) - /// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: SmithMembership MembershipsExpireOn (r:1 w:1) - /// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured) - /// Storage: AuthorityMembers Members (r:1 w:1) - /// Proof Skipped: AuthorityMembers Members (max_values: None, max_size: None, mode: Measured) - /// Storage: AuthorityMembers OnlineAuthorities (r:1 w:1) - /// Proof Skipped: AuthorityMembers OnlineAuthorities (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AuthorityMembers AuthoritiesCounter (r:1 w:1) - /// Proof Skipped: AuthorityMembers AuthoritiesCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AuthorityMembers IncomingAuthorities (r:1 w:1) - /// Proof Skipped: AuthorityMembers IncomingAuthorities (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session NextKeys (r:1 w:1) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(126), added: 2601, mode: MaxEncodedLen) - /// Storage: Session KeyOwner (r:0 w:4) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - fn revoke_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `1183` - // Estimated: `4648` - // Minimum execution time: 60_153_000 picoseconds. - Weight::from_parts(62_834_000, 0) - .saturating_add(Weight::from_parts(0, 4648)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(13)) - } - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 133_000 picoseconds. - Weight::from_parts(157_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: SmithMembership MembershipsExpireOn (r:2 w:2) - /// Proof Skipped: SmithMembership MembershipsExpireOn (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership Membership (r:3 w:3) - /// Proof Skipped: SmithMembership Membership (max_values: None, max_size: None, mode: Measured) - /// Storage: SmithMembership CounterForMembership (r:1 w:1) - /// Proof: SmithMembership CounterForMembership (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: AuthorityMembers Members (r:3 w:3) - /// Proof Skipped: AuthorityMembers Members (max_values: None, max_size: None, mode: Measured) - /// Storage: AuthorityMembers OnlineAuthorities (r:1 w:1) - /// Proof Skipped: AuthorityMembers OnlineAuthorities (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AuthorityMembers OutgoingAuthorities (r:1 w:1) - /// Proof Skipped: AuthorityMembers OutgoingAuthorities (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AuthorityMembers AuthoritiesCounter (r:1 w:1) - /// Proof Skipped: AuthorityMembers AuthoritiesCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: AuthorityMembers IncomingAuthorities (r:1 w:1) - /// Proof Skipped: AuthorityMembers IncomingAuthorities (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Session NextKeys (r:3 w:3) - /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(126), added: 2601, mode: MaxEncodedLen) - /// Storage: Session KeyOwner (r:0 w:12) - /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 3]`. - /// The range of component `i` is `[0, 3]`. - fn expire_memberships(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `133 + i * (515 ±0)` - // Estimated: `4157 + i * (2692 ±0)` - // Minimum execution time: 4_794_000 picoseconds. - Weight::from_parts(9_091_363, 0) - .saturating_add(Weight::from_parts(0, 4157)) - // Standard Error: 191_583 - .saturating_add(Weight::from_parts(46_909_320, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(i.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(T::DbWeight::get().writes((11_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 2692).saturating_mul(i.into())) - } -} diff --git a/runtime/common/src/weights/pallet_smith_members.rs b/runtime/common/src/weights/pallet_smith_members.rs new file mode 100644 index 0000000000000000000000000000000000000000..a0c5d8bda61e2c89b577347e220cf7b04355ecc5 --- /dev/null +++ b/runtime/common/src/weights/pallet_smith_members.rs @@ -0,0 +1,105 @@ +// Copyright 2021-2022 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +//! Autogenerated weights for `pallet_smith_members` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `MacBook-Pro-de-Cedric.local`, CPU: `<UNKNOWN>` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/duniter +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet-smith-members +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --header=./file_header.txt +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_smith_members`. +pub struct WeightInfo<T>(PhantomData<T>); +impl<T: frame_system::Config> pallet_smith_members::WeightInfo for WeightInfo<T> { + /// Storage: Identity IdentityIndexOf (r:1 w:0) + /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) + /// Storage: SmithMembers Smiths (r:2 w:1) + /// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured) + /// Storage: Membership Membership (r:1 w:0) + /// Proof Skipped: Membership Membership (max_values: None, max_size: None, mode: Measured) + /// Storage: SmithMembers CurrentSession (r:1 w:0) + /// Proof Skipped: SmithMembers CurrentSession (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Parameters ParametersStorage (r:1 w:0) + /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: SmithMembers ExpiresOn (r:1 w:1) + /// Proof Skipped: SmithMembers ExpiresOn (max_values: None, max_size: None, mode: Measured) + fn invite_smith() -> Weight { + // Proof Size summary in bytes: + // Measured: `731` + // Estimated: `6671` + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(28_000_000, 0) + .saturating_add(Weight::from_parts(0, 6671)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Identity IdentityIndexOf (r:1 w:0) + /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) + /// Storage: SmithMembers Smiths (r:1 w:1) + /// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured) + fn accept_invitation() -> Weight { + // Proof Size summary in bytes: + // Measured: `463` + // Estimated: `3928` + // Minimum execution time: 15_000_000 picoseconds. + Weight::from_parts(15_000_000, 0) + .saturating_add(Weight::from_parts(0, 3928)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: Identity IdentityIndexOf (r:1 w:0) + /// Proof Skipped: Identity IdentityIndexOf (max_values: None, max_size: None, mode: Measured) + /// Storage: SmithMembers Smiths (r:2 w:2) + /// Proof Skipped: SmithMembers Smiths (max_values: None, max_size: None, mode: Measured) + /// Storage: Parameters ParametersStorage (r:1 w:0) + /// Proof Skipped: Parameters ParametersStorage (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: SmithMembers CurrentSession (r:1 w:0) + /// Proof Skipped: SmithMembers CurrentSession (max_values: Some(1), max_size: None, mode: Measured) + fn certify_smith() -> Weight { + // Proof Size summary in bytes: + // Measured: `576` + // Estimated: `6516` + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(26_000_000, 0) + .saturating_add(Weight::from_parts(0, 6516)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml index e96b7a0843152daba2cc0b0414dda1942e52494e..65207b28d2d50149694689d9dd2ba701d6fb339a 100644 --- a/runtime/g1/Cargo.toml +++ b/runtime/g1/Cargo.toml @@ -23,6 +23,7 @@ runtime-benchmarks = [ 'frame-system/runtime-benchmarks', 'hex-literal', 'pallet-authority-members/runtime-benchmarks', + 'pallet-smith-members/runtime-benchmarks', 'pallet-babe/runtime-benchmarks', 'pallet-balances/runtime-benchmarks', 'pallet-certification/runtime-benchmarks', @@ -61,6 +62,7 @@ std = [ 'log/std', 'pallet-authority-discovery/std', 'pallet-authority-members/std', + 'pallet-smith-members/std', 'pallet-babe/std', 'pallet-balances/std', 'pallet-certification/std', @@ -134,6 +136,7 @@ sp-keyring = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s # local common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } +pallet-smith-members = { path = '../../pallets/smith-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } pallet-distance = { path = "../../pallets/distance", default-features = false } pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false } diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs index 8cef6bfcb4ef5219da5aa82056d79b3f256c8cf8..695fb3d39694e9decde7144b01f7de75d38d4d2c 100644 --- a/runtime/g1/src/lib.rs +++ b/runtime/g1/src/lib.rs @@ -66,6 +66,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. +use frame_support::instances::Instance2; pub use frame_support::{ construct_runtime, parameter_types, traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness}, @@ -139,7 +140,6 @@ pub type TechnicalCommitteeInstance = Instance2; mod benches { define_benchmarks!( [pallet_certification, Cert] - [pallet_certification, SmithCert] [pallet_distance, Distance] [pallet_oneshot_account, OneshotAccount] [pallet_universal_dividend, UniversalDividend] @@ -148,7 +148,7 @@ mod benches { [pallet_duniter_account, Account] [pallet_identity, Identity] [pallet_membership, Membership] - [pallet_membership, SmithMembership] + [pallet_smith_members, SmithMembers] [pallet_authority_members, AuthorityMembers] // Substrate [pallet_balances, Balances] @@ -214,7 +214,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType { // Some calls are never authorized from a proxied account !matches!( c, - RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..) + RuntimeCall::Cert(..) + | RuntimeCall::Identity(..) + | RuntimeCall::SmithMembers(..) ) } ProxyType::TransferOnly => { @@ -263,14 +265,15 @@ construct_runtime!( Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66, // Consensus support. - AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, - Authorship: pallet_authorship::{Pallet, Storage} = 11, - Offences: pallet_offences::{Pallet, Storage, Event} = 12, - Historical: session_historical::{Pallet} = 13, - Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17, + SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, + AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11, + Authorship: pallet_authorship::{Pallet, Storage} = 12, + Offences: pallet_offences::{Pallet, Storage, Event} = 13, + Historical: session_historical::{Pallet} = 14, + Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16, + ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17, + AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18, // Governance stuff. Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20, @@ -282,24 +285,19 @@ construct_runtime!( UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30, // Web Of Trust - Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40, + Wot: pallet_duniter_wot::{Pallet} = 40, Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41, - Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, - Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, + Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, + Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44, - // Smith Sub-Wot - SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50, - SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52, - SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53, - // Utilities - AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61, - ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63, - Utility: pallet_utility::{Pallet, Call, Event} = 64, - Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65, + AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51, + ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53, + Utility: pallet_utility::{Pallet, Call, Event} = 54, + Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55, } ); diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs index 11315f7fce15a178460901522ace74a2a33b977b..22ef4efa43e1bf4424bbd86c5b6bf00daeb62586 100644 --- a/runtime/g1/src/parameters.rs +++ b/runtime/g1/src/parameters.rs @@ -117,26 +117,13 @@ parameter_types! { } /******************/ -/* SMITHS SUB-WOT */ +/* SMITH-MEMBERS */ /******************/ parameter_types! { - pub const SmithWotFirstCertIssuableOn: BlockNumber = 30 * DAYS; pub const SmithWotMinCertForMembership: u32 = 3; -} - -// Membership -parameter_types! { - pub const SmithMembershipPeriod: BlockNumber = 73 * DAYS; - pub const SmithPendingMembershipPeriod: BlockNumber = 12 * DAYS; -} - -// Certification -parameter_types! { - pub const SmithCertPeriod: BlockNumber = 5 * DAYS; pub const SmithMaxByIssuer: u32 = 12; - pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 5; - pub const SmithValidityPeriod: BlockNumber = 146 * DAYS; + pub const SmithInactivityMaxDuration: u32 = 48; } /*************/ diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml index 976999d23464736b73a55792f68b3feef4b686d4..716482251ac1f1a734150a12717684cd25317179 100644 --- a/runtime/gdev/Cargo.toml +++ b/runtime/gdev/Cargo.toml @@ -23,6 +23,7 @@ runtime-benchmarks = [ 'frame-system/runtime-benchmarks', 'hex-literal', 'pallet-authority-members/runtime-benchmarks', + 'pallet-smith-members/runtime-benchmarks', 'pallet-babe/runtime-benchmarks', 'pallet-balances/runtime-benchmarks', 'pallet-certification/runtime-benchmarks', @@ -62,6 +63,7 @@ std = [ 'pallet-atomic-swap/std', 'pallet-authority-discovery/std', 'pallet-authority-members/std', + 'pallet-smith-members/std', 'pallet-babe/std', 'pallet-balances/std', 'pallet-certification/std', @@ -141,6 +143,7 @@ sp-staking = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s # local common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } +pallet-smith-members = { path = '../../pallets/smith-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } pallet-distance = { path = "../../pallets/distance", default-features = false } pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false } diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs index 5b13dec4398a09ea8847f73c876dc4892c8d5c39..544ae962dc7ce8ffe38c59f0cc464501475152fd 100644 --- a/runtime/gdev/src/lib.rs +++ b/runtime/gdev/src/lib.rs @@ -67,6 +67,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. +use frame_support::instances::Instance2; pub use frame_support::{ construct_runtime, parameter_types, traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness}, @@ -141,7 +142,6 @@ pub type TechnicalCommitteeInstance = Instance2; mod benches { define_benchmarks!( [pallet_certification, Cert] - [pallet_certification, SmithCert] [pallet_distance, Distance] [pallet_oneshot_account, OneshotAccount] [pallet_universal_dividend, UniversalDividend] @@ -151,7 +151,7 @@ mod benches { [pallet_quota, Quota] [pallet_identity, Identity] [pallet_membership, Membership] - [pallet_membership, SmithMembership] + [pallet_smith_members, SmithMembers] [pallet_authority_members, AuthorityMembers] // Substrate [pallet_balances, Balances] @@ -218,7 +218,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType { // Some calls are never authorized from a proxied account !matches!( c, - RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..) + RuntimeCall::Cert(..) + | RuntimeCall::Identity(..) + | RuntimeCall::SmithMembers(..) ) } ProxyType::TransferOnly => { @@ -261,20 +263,16 @@ common_runtime::pallets_config! { pub type WotMinCertForMembership = pallet_duniter_test_parameters::WotMinCertForMembership<Runtime>; pub type WotMinCertForCreateIdtyRight = pallet_duniter_test_parameters::WotMinCertForCreateIdtyRight<Runtime>; - pub type SmithCertPeriod = pallet_duniter_test_parameters::SmithCertPeriod<Runtime>; pub type SmithMaxByIssuer = pallet_duniter_test_parameters::SmithCertMaxByIssuer<Runtime>; - pub type SmithMinReceivedCertToBeAbleToIssueCert = - pallet_duniter_test_parameters::SmithCertMinReceivedCertToIssueCert<Runtime>; - pub type SmithValidityPeriod = pallet_duniter_test_parameters::SmithCertValidityPeriod<Runtime>; - pub type SmithMembershipPeriod = pallet_duniter_test_parameters::SmithMembershipPeriod<Runtime>; - pub type SmithWotFirstCertIssuableOn = - pallet_duniter_test_parameters::SmithWotFirstCertIssuableOn<Runtime>; pub type SmithWotMinCertForMembership = pallet_duniter_test_parameters::SmithWotMinCertForMembership<Runtime>; + pub type SmithInactivityMaxDuration = + pallet_duniter_test_parameters::SmithInactivityMaxDuration<Runtime>; impl pallet_duniter_test_parameters::Config for Runtime { type CertCount = u32; type PeriodCount = Balance; + type SessionCount = u32; } impl pallet_sudo::Config for Runtime { @@ -309,14 +307,15 @@ construct_runtime!( Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66, // Consensus support - AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, - Authorship: pallet_authorship::{Pallet, Storage} = 11, - Offences: pallet_offences::{Pallet, Storage, Event} = 12, - Historical: session_historical::{Pallet} = 13, - Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17, + SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, + AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11, + Authorship: pallet_authorship::{Pallet, Storage} = 12, + Offences: pallet_offences::{Pallet, Storage, Event} = 13, + Historical: session_historical::{Pallet} = 14, + Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16, + ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17, + AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18, // Governance stuff Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20, @@ -328,24 +327,19 @@ construct_runtime!( UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30, // Web Of Trust - Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40, + Wot: pallet_duniter_wot::{Pallet} = 40, Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41, - Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, - Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, + Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, + Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44, - // Smith Sub-Wot - SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50, - SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52, - SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53, - // Utilities - AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61, - ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63, - Utility: pallet_utility::{Pallet, Call, Event} = 64, - Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65, + AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51, + ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53, + Utility: pallet_utility::{Pallet, Call, Event} = 54, + Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55, } ); diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs index 5c20cd6ab0b337c6989ae8eb1640c836b5424c27..a74493b34a02f8f680be2c32712341314b1858fe 100644 --- a/runtime/gdev/tests/common/mod.rs +++ b/runtime/gdev/tests/common/mod.rs @@ -18,11 +18,11 @@ use common_runtime::constants::*; use common_runtime::*; -use frame_support::instances::{Instance1, Instance2}; use frame_support::traits::{GenesisBuild, OnFinalize, OnInitialize}; use gdev_runtime::opaque::SessionKeys; use gdev_runtime::*; use pallet_authority_members::OnNewSession; +use pallet_smith_members::SmithMeta; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::{AuthorityId as BabeId, Slot}; use sp_consensus_babe::{VrfOutput, VrfProof}; @@ -54,7 +54,7 @@ pub struct ExtBuilder { initial_authorities_len: usize, initial_identities: BTreeMap<IdtyName, AccountId>, initial_smiths: Vec<AuthorityKeys>, - parameters: GenesisParameters<u32, u32, Balance>, + parameters: GenesisParameters<u32, u32, Balance, u32>, } impl ExtBuilder { @@ -108,14 +108,9 @@ impl ExtBuilder { pending_membership_period: 500, ud_creation_period: 60_000, ud_reeval_period: 60_000 * 20, - smith_cert_period: 15, smith_cert_max_by_issuer: 8, - smith_cert_min_received_cert_to_issue_cert: 2, - smith_cert_validity_period: 1_000, - smith_membership_period: 1_000, - smith_pending_membership_period: 500, - smith_wot_first_cert_issuable_on: 20, smith_wot_min_cert_for_membership: 2, + smith_inactivity_max_duration: 48, wot_first_cert_issuable_on: 20, wot_min_cert_for_create_idty_right: 2, wot_min_cert_for_membership: 2, @@ -142,7 +137,7 @@ impl ExtBuilder { }*/ pub fn change_parameters< - F: Fn(&mut pallet_duniter_test_parameters::Parameters<u32, u32, Balance>), + F: Fn(&mut pallet_duniter_test_parameters::Parameters<u32, u32, Balance, u32>), >( mut self, f: F, @@ -251,7 +246,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - pallet_membership::GenesisConfig::<Runtime, Instance1> { + pallet_membership::GenesisConfig::<Runtime> { memberships: (1..=initial_identities.len()) .map(|i| { ( @@ -266,7 +261,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - pallet_certification::GenesisConfig::<Runtime, Instance1> { + pallet_certification::GenesisConfig::<Runtime> { certs_by_receiver: clique_wot( initial_identities.len(), parameters.cert_validity_period, @@ -276,27 +271,8 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - pallet_membership::GenesisConfig::<Runtime, Instance2> { - memberships: (1..=initial_smiths.len()) - .map(|i| { - ( - i as u32, - MembershipData { - expire_on: parameters.smith_membership_period, - }, - ) - }) - .collect(), - } - .assimilate_storage(&mut t) - .unwrap(); - - pallet_certification::GenesisConfig::<Runtime, Instance2> { - apply_cert_period_at_genesis: false, - certs_by_receiver: clique_wot( - initial_smiths.len(), - parameters.smith_cert_validity_period, - ), + pallet_smith_members::GenesisConfig::<Runtime> { + initial_smiths: clique_smith_wot(initial_smiths.len()), } .assimilate_storage(&mut t) .unwrap(); @@ -393,9 +369,6 @@ pub fn run_to_block(n: u32) { Identity::on_initialize(System::block_number()); Membership::on_initialize(System::block_number()); Cert::on_initialize(System::block_number()); - SmithSubWot::on_initialize(System::block_number()); - SmithMembership::on_initialize(System::block_number()); - SmithCert::on_initialize(System::block_number()); Timestamp::set_timestamp(System::block_number() as u64 * BLOCK_TIME); Distance::on_initialize(System::block_number()); @@ -476,6 +449,22 @@ fn clique_wot( certs_by_issuer } +fn clique_smith_wot(initial_identities_len: usize) -> BTreeMap<IdtyIndex, (bool, Vec<IdtyIndex>)> { + let mut certs_by_issuer = BTreeMap::new(); + for i in 1..=initial_identities_len { + certs_by_issuer.insert( + i as IdtyIndex, + ( + true, + (1..=initial_identities_len) + .filter_map(|j| if i != j { Some(j as IdtyIndex) } else { None }) + .collect(), + ), + ); + } + certs_by_issuer +} + fn session_keys( babe: BabeId, grandpa: GrandpaId, diff --git a/runtime/gdev/tests/fixme_tests.rs b/runtime/gdev/tests/fixme_tests.rs index 028f23600ccebc7d1258815fb514717706143eaf..1ab0bd7a7c799d9ed6b9c8be655bb38106d3c7ad 100644 --- a/runtime/gdev/tests/fixme_tests.rs +++ b/runtime/gdev/tests/fixme_tests.rs @@ -43,10 +43,7 @@ fn can_still_issue_cert_when_membership_lost() { run_to_block(1); // expire Bob membership - Membership::do_remove_membership( - 2, - MembershipRemovalReason::System - ); + Membership::do_remove_membership(2, MembershipRemovalReason::System); System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipRemoved { member: 2, @@ -55,12 +52,13 @@ fn can_still_issue_cert_when_membership_lost() { )); // fixed :) - assert_noop!(Cert::add_cert( - frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(), + assert_noop!( + Cert::add_cert( + frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(), 2, // Bob 3, // Charlie ), - pallet_duniter_wot::Error::<gdev_runtime::Runtime, pallet_certification::Instance1>::IssuerNotMember + pallet_duniter_wot::Error::<gdev_runtime::Runtime>::IssuerNotMember ); // // not anymore // System::assert_has_event(RuntimeEvent::Cert( diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs index ef4dce191d85262ad341243a4758665bf623895f..ca90f99258221aa6cbadc7b9e7442c1e74b067e6 100644 --- a/runtime/gdev/tests/integration_tests.rs +++ b/runtime/gdev/tests/integration_tests.rs @@ -17,13 +17,14 @@ mod common; use common::*; -use frame_support::instances::Instance1; use frame_support::traits::StoredMap; use frame_support::traits::{Get, PalletInfo, StorageInfo, StorageInfoTrait}; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok}; use frame_support::{StorageHasher, Twox128}; use gdev_runtime::*; +use pallet_identity::{RevocationPayload, REVOCATION_PAYLOAD_PREFIX}; use pallet_membership::MembershipRemovalReason; +use pallet_smith_members::{SmithMeta, SmithStatus}; use sp_core::Encode; use sp_keyring::AccountKeyring; use sp_runtime::MultiAddress; @@ -367,9 +368,7 @@ fn test_validate_identity_when_claim() { System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipAdded { member: 5, - expire_on: 76 - + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get( - ), + expire_on: 76 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(), }, )); // not possible anymore to validate identity of someone else @@ -392,6 +391,7 @@ fn test_membership_expiry() { }); } +// TODO: use change_parameter to change autorevocation period #[test] #[ignore = "long to go to autorevocation period"] fn test_membership_expiry_with_identity_removal() { @@ -445,9 +445,7 @@ fn test_membership_renewal() { System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipAdded { member: 1, - expire_on: 76 - + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get( - ), + expire_on: 76 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(), }, )); @@ -459,9 +457,7 @@ fn test_membership_renewal() { System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipAdded { member: 1, - expire_on: 77 - + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get( - ), + expire_on: 77 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(), }, )); @@ -602,8 +598,7 @@ fn test_ud_claimed_membership_on_and_off() { System::assert_has_event(RuntimeEvent::Membership( pallet_membership::Event::MembershipAdded { member: 1, - expire_on: 14 - + <Runtime as pallet_membership::Config<Instance1>>::MembershipPeriod::get(), + expire_on: 14 + <Runtime as pallet_membership::Config>::MembershipPeriod::get(), }, )); @@ -647,12 +642,6 @@ fn test_revoke_smith_identity() { Identity::do_revoke_identity(3, pallet_identity::RevocationReason::Root); // Verify events - System::assert_has_event(RuntimeEvent::SmithMembership( - pallet_membership::Event::MembershipRemoved { - member: 3, - reason: MembershipRemovalReason::Revoked, - }, - )); System::assert_has_event(RuntimeEvent::AuthorityMembers( pallet_authority_members::Event::MemberRemoved { member: 3 }, )); @@ -679,26 +668,33 @@ fn test_smith_certification() { ExtBuilder::new(1, 3, 4).build().execute_with(|| { run_to_block(1); - // alice can renew smith cert to bob - assert_ok!(SmithCert::add_cert( - frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(), - 1, // alice - 2 // bob - )); + assert_noop!( + SmithMembers::certify_smith( + frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(), + 2 + ), + pallet_smith_members::Error::<Runtime>::CertificationAlreadyExists + ); - // charlie can not add new cert to eve (no identity) assert_noop!( - SmithCert::add_cert( - frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(), - 3, // charlie - 5 // eve + SmithMembers::certify_smith( + frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(), + 4 ), - // SmithSubWot::Error::IdtyNotFound, - pallet_duniter_wot::Error::<gdev_runtime::Runtime, pallet_certification::Instance2>::IdtyNotFound, + pallet_smith_members::Error::<Runtime>::CertificationReceiverMustHaveBeenInvited ); }); } +fn create_dummy_session_keys() -> gdev_runtime::opaque::SessionKeys { + gdev_runtime::opaque::SessionKeys { + grandpa: sp_core::ed25519::Public([0u8; 32]).into(), + babe: sp_core::sr25519::Public([0u8; 32]).into(), + im_online: sp_core::sr25519::Public([0u8; 32]).into(), + authority_discovery: sp_core::sr25519::Public([0u8; 32]).into(), + } +} + /// test the full process to join smith from main wot member to authority member #[test] fn test_smith_process() { @@ -711,6 +707,8 @@ fn test_smith_process() { let alice = AccountKeyring::Alice.to_account_id(); let bob = AccountKeyring::Bob.to_account_id(); let charlie = AccountKeyring::Charlie.to_account_id(); + let dave = AccountKeyring::Dave.to_account_id(); + let dummy_session_keys = create_dummy_session_keys(); // Eve can not request smith membership because not member of the smith wot // no more membership request @@ -718,45 +716,53 @@ fn test_smith_process() { // Dave can request smith membership (currently optional) // no more membership request - // Alice Bob and Charlie can certify Dave - assert_ok!(SmithCert::add_cert( - frame_system::RawOrigin::Signed(alice).into(), - 1, + assert_ok!(SmithMembers::invite_smith( + frame_system::RawOrigin::Signed(alice.clone()).into(), 4 )); - assert_ok!(SmithCert::add_cert( - frame_system::RawOrigin::Signed(bob).into(), - 2, + assert_ok!(SmithMembers::accept_invitation( + frame_system::RawOrigin::Signed(dave).into(), + )); + + // Dave cannot (yet) set his session keys + assert_err!( + AuthorityMembers::set_session_keys( + frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(), + dummy_session_keys.clone() + ), + pallet_authority_members::Error::<Runtime>::NotMember + ); + + // Alice Bob and Charlie can certify Dave + assert_ok!(SmithMembers::certify_smith( + frame_system::RawOrigin::Signed(alice.clone()).into(), 4 )); - assert_ok!(SmithCert::add_cert( - frame_system::RawOrigin::Signed(charlie).into(), - 3, + assert_ok!(SmithMembers::certify_smith( + frame_system::RawOrigin::Signed(bob.clone()).into(), 4 )); - - // with these three smith certs, Dave can claim membership - assert_ok!(SmithMembership::claim_membership( - frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(), + assert_ok!(SmithMembers::certify_smith( + frame_system::RawOrigin::Signed(charlie.clone()).into(), + 4 )); + // with these three smith certs, Dave has become smith // Dave is then member of the smith wot assert_eq!( - SmithMembership::membership(4), - Some(sp_membership::MembershipData { - expire_on: 1001, // 1 + 1000 + SmithMembers::smiths(4), + Some(pallet_smith_members::SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(48), + issued_certs: vec![], + received_certs: vec![1, 2, 3], }) ); // Dave can set his (dummy) session keys assert_ok!(AuthorityMembers::set_session_keys( frame_system::RawOrigin::Signed(AccountKeyring::Dave.to_account_id()).into(), - gdev_runtime::opaque::SessionKeys { - grandpa: sp_core::ed25519::Public([0u8; 32]).into(), - babe: sp_core::sr25519::Public([0u8; 32]).into(), - im_online: sp_core::sr25519::Public([0u8; 32]).into(), - authority_discovery: sp_core::sr25519::Public([0u8; 32]).into(), - } + dummy_session_keys )); // Dave can go online @@ -1235,14 +1241,26 @@ fn test_link_account() { fn test_change_owner_key() { ExtBuilder::new(1, 3, 4).build().execute_with(|| { let genesis_hash = System::block_hash(0); - let dave = AccountKeyring::Dave.to_account_id(); + let charlie = AccountKeyring::Charlie.to_account_id(); let ferdie = AccountKeyring::Ferdie.to_account_id(); - let payload = (b"icok", genesis_hash, 4u32, dave.clone()).encode(); + let payload = (b"icok", genesis_hash, 3u32, charlie.clone()).encode(); let signature = AccountKeyring::Ferdie.sign(&payload); + SmithMembers::on_smith_goes_offline(3); + // Charlie is now offline smith + assert_eq!( + SmithMembers::smiths(3), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(48), + issued_certs: vec![1, 2], + received_certs: vec![1, 2] + }) + ); + assert_eq!( - frame_system::Pallet::<Runtime>::get(&dave).linked_idty, - Some(4) + frame_system::Pallet::<Runtime>::get(&charlie).linked_idty, + Some(3) ); assert_eq!( frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty, @@ -1250,17 +1268,123 @@ fn test_change_owner_key() { ); // Dave can change his owner key to Ferdie's assert_ok!(Identity::change_owner_key( - frame_system::RawOrigin::Signed(dave.clone()).into(), + frame_system::RawOrigin::Signed(charlie.clone()).into(), ferdie.clone(), signature.into() )); assert_eq!( frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty, - Some(4) + Some(3) + ); + + // Charlie is still an offline smith + assert_eq!( + SmithMembers::smiths(3), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(48), + issued_certs: vec![1, 2], + received_certs: vec![1, 2] + }) + ); + + // Ferdie can set its session_keys and go online + frame_system::Pallet::<Runtime>::inc_providers(&ferdie); + assert_ok!(AuthorityMembers::set_session_keys( + frame_system::RawOrigin::Signed(AccountKeyring::Ferdie.to_account_id()).into(), + create_dummy_session_keys() + )); + assert_ok!(AuthorityMembers::go_online( + frame_system::RawOrigin::Signed(AccountKeyring::Ferdie.to_account_id()).into() + )); + + // Charlie is still an offline smith + assert_eq!( + SmithMembers::smiths(3), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: Some(48), + issued_certs: vec![1, 2], + received_certs: vec![1, 2] + }) + ); + + run_to_block(25); + + System::assert_has_event(RuntimeEvent::AuthorityMembers( + pallet_authority_members::Event::IncomingAuthorities { members: vec![3] }, + )); + System::assert_has_event(RuntimeEvent::AuthorityMembers( + pallet_authority_members::Event::OutgoingAuthorities { members: vec![1] }, + )); + + // "Charlie" (idty 3) is now online because its identity is mapped to Ferdies's key + assert_eq!( + SmithMembers::smiths(3), + Some(SmithMeta { + status: SmithStatus::Smith, + expires_on: None, + issued_certs: vec![1, 2], + received_certs: vec![1, 2] + }) ); }) } +/// members of the smith subwot can revoke their identity +#[test] +fn test_smith_member_can_revoke_its_idty() { + ExtBuilder::new(1, 3, 4).build().execute_with(|| { + run_to_block(2); + + // Charlie goes online + frame_system::Pallet::<Runtime>::inc_providers(&AccountKeyring::Charlie.to_account_id()); + assert_ok!(AuthorityMembers::set_session_keys( + frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(), + create_dummy_session_keys() + )); + assert_ok!(AuthorityMembers::go_online( + frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into() + )); + + run_to_block(25); + + // Charlie is in the authority members + System::assert_has_event(RuntimeEvent::AuthorityMembers( + pallet_authority_members::Event::IncomingAuthorities { members: vec![3] }, + )); + // Charlie is not going out + assert!(!pallet_authority_members::OutgoingAuthorities::<Runtime>::get().contains(&3)); + + let revocation_payload = RevocationPayload { + idty_index: 3u32, + genesis_hash: System::block_hash(0), + }; + let signature = + AccountKeyring::Charlie.sign(&(REVOCATION_PAYLOAD_PREFIX, revocation_payload).encode()); + + assert_ok!(Identity::revoke_identity( + frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(), + 3, + AccountKeyring::Charlie.to_account_id(), + signature.into() + )); + // membership should be removed + System::assert_has_event(RuntimeEvent::Membership( + pallet_membership::Event::MembershipRemoved { + member: 3, + reason: MembershipRemovalReason::Revoked, + }, + )); + // smith membership should be removed as well + System::assert_has_event(RuntimeEvent::SmithMembers( + pallet_smith_members::Event::SmithExcluded { idty_index: 3 }, + )); + // Now Charlie is going out + assert!(pallet_authority_members::OutgoingAuthorities::<Runtime>::get().contains(&3)); + }); +} + /// test genesis account of identity is linked to identity // (and account without identity is not linked) #[test] @@ -1328,11 +1452,10 @@ fn test_new_account_linked() { }) } #[test] +#[ignore = "what was this test supposed to do?"] fn smith_data_problem() { ExtBuilder::new(1, 3, 4) - .change_parameters(|parameters| { - parameters.smith_cert_validity_period = 3; - }) + .change_parameters(|_parameters| {}) .build() .execute_with(|| { run_to_block(4); diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml index 8f59a6ad6a39b54c0c0ca276e78ef76b5b346eb6..8e90489b73d8d7c6afd25dac6a15ca39ae03e524 100644 --- a/runtime/gtest/Cargo.toml +++ b/runtime/gtest/Cargo.toml @@ -23,6 +23,7 @@ runtime-benchmarks = [ 'frame-system/runtime-benchmarks', 'hex-literal', 'pallet-authority-members/runtime-benchmarks', + 'pallet-smith-members/runtime-benchmarks', 'pallet-babe/runtime-benchmarks', 'pallet-balances/runtime-benchmarks', 'pallet-certification/runtime-benchmarks', @@ -60,6 +61,7 @@ std = [ 'pallet-atomic-swap/std', 'pallet-authority-discovery/std', 'pallet-authority-members/std', + 'pallet-smith-members/std', 'pallet-babe/std', 'pallet-balances/std', 'pallet-certification/std', @@ -137,6 +139,7 @@ sp-keyring = { git = 'https://github.com/duniter/substrate', branch = 'duniter-s # local common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } +pallet-smith-members = { path = '../../pallets/smith-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } pallet-distance = { path = "../../pallets/distance", default-features = false } pallet-duniter-account = { path = '../../pallets/duniter-account', default-features = false } diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs index 88fbd282f83728cf10ee03e282715b7ec34ebf67..374cc0d7999e5b709b8e886bfa1d8f5db7e55f3a 100644 --- a/runtime/gtest/src/lib.rs +++ b/runtime/gtest/src/lib.rs @@ -66,6 +66,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. +use frame_support::instances::Instance2; pub use frame_support::{ construct_runtime, parameter_types, traits::{EqualPrivilegeOnly, KeyOwnerProofSystem, Randomness}, @@ -140,7 +141,6 @@ pub type TechnicalCommitteeInstance = Instance2; mod benches { define_benchmarks!( [pallet_certification, Cert] - [pallet_certification, SmithCert] [pallet_distance, Distance] [pallet_oneshot_account, OneshotAccount] [pallet_universal_dividend, UniversalDividend] @@ -149,7 +149,7 @@ mod benches { [pallet_duniter_account, Account] [pallet_identity, Identity] [pallet_membership, Membership] - [pallet_membership, SmithMembership] + [pallet_smith_members, SmithMembers] [pallet_authority_members, AuthorityMembers] // Substrate [pallet_balances, Balances] @@ -211,7 +211,9 @@ impl frame_support::traits::InstanceFilter<RuntimeCall> for ProxyType { // Some calls are never authorized from a proxied account !matches!( c, - RuntimeCall::Cert(..) | RuntimeCall::Identity(..) | RuntimeCall::SmithCert(..) + RuntimeCall::Cert(..) + | RuntimeCall::Identity(..) + | RuntimeCall::SmithMembers(..) ) } ProxyType::TransferOnly => { @@ -268,14 +270,15 @@ construct_runtime!( Quota: pallet_quota::{Pallet, Storage, Config<T>, Event<T>} = 66, // Consensus support - AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, - Authorship: pallet_authorship::{Pallet, Storage} = 11, - Offences: pallet_offences::{Pallet, Storage, Event} = 12, - Historical: session_historical::{Pallet} = 13, - Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 14, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 15, - ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 16, - AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 17, + SmithMembers: pallet_smith_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 10, + AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>} = 11, + Authorship: pallet_authorship::{Pallet, Storage} = 12, + Offences: pallet_offences::{Pallet, Storage, Event} = 13, + Historical: session_historical::{Pallet} = 14, + Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 15, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 16, + ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 17, + AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 18, // Governance stuff Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>} = 20, @@ -287,24 +290,19 @@ construct_runtime!( UniversalDividend: pallet_universal_dividend::{Pallet, Call, Config<T>, Storage, Event<T>} = 30, // Web Of Trust - Wot: pallet_duniter_wot::<Instance1>::{Pallet} = 40, + Wot: pallet_duniter_wot::{Pallet} = 40, Identity: pallet_identity::{Pallet, Call, Config<T>, Storage, Event<T>} = 41, - Membership: pallet_membership::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, - Cert: pallet_certification::<Instance1>::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, + Membership: pallet_membership::{Pallet, Call, Config<T>, Storage, Event<T>} = 42, + Cert: pallet_certification::{Pallet, Call, Config<T>, Storage, Event<T>} = 43, Distance: pallet_distance::{Pallet, Call, Storage, Inherent, Event<T>} = 44, - // Smith Sub-Wot - SmithSubWot: pallet_duniter_wot::<Instance2>::{Pallet} = 50, - SmithMembership: pallet_membership::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 52, - SmithCert: pallet_certification::<Instance2>::{Pallet, Call, Config<T>, Storage, Event<T>} = 53, - // Utilities - AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 61, - ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 62, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 63, - Utility: pallet_utility::{Pallet, Call, Event} = 64, - Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 65, + AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 50, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 51, + ProvideRandomness: pallet_provide_randomness::{Pallet, Call, Storage, Event} = 52, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 53, + Utility: pallet_utility::{Pallet, Call, Event} = 54, + Treasury: pallet_treasury::{Pallet, Call, Config, Storage, Event<T>} = 55, } ); diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs index 443e8cffa589424a5ed1fb69d40121c312e356ea..252ae211a2571ead87fa67ab4d13f64b98ae8c88 100644 --- a/runtime/gtest/src/parameters.rs +++ b/runtime/gtest/src/parameters.rs @@ -118,26 +118,13 @@ parameter_types! { } /******************/ -/* SMITHS SUB-WOT */ +/* SMITH-MEMBERS */ /******************/ parameter_types! { - pub const SmithWotFirstCertIssuableOn: BlockNumber = DAYS; pub const SmithWotMinCertForMembership: u32 = 3; -} - -// Membership -parameter_types! { - pub const SmithMembershipPeriod: BlockNumber = 73 * DAYS; - pub const SmithPendingMembershipPeriod: BlockNumber = 12 * DAYS; -} - -// Certification -parameter_types! { - pub const SmithCertPeriod: BlockNumber = DAYS; pub const SmithMaxByIssuer: u32 = 100; - pub const SmithMinReceivedCertToBeAbleToIssueCert: u32 = 5; - pub const SmithValidityPeriod: BlockNumber = 146 * DAYS; + pub const SmithInactivityMaxDuration: u32 = 48; } /*************/