From dac7547f14ef798f8de6030b1cfeb865f13c4b1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=89lo=C3=AFs?= <c@elo.tf>
Date: Wed, 19 Jan 2022 16:57:50 +0100
Subject: [PATCH] feat: make gdev parameters dynamic

---
 Cargo.lock                                    |  47 ++++++++
 Cargo.toml                                    |   2 +
 node/src/chain_spec/gdev.rs                   |  48 ++++++--
 node/src/chain_spec/gtest.rs                  |   2 +
 pallets/certification/src/lib.rs              |  18 +--
 pallets/certification/src/tests.rs            |   4 +
 pallets/duniter-test-parameters/Cargo.toml    |  72 ++++++++++++
 .../duniter-test-parameters/macro/Cargo.toml  |  18 +++
 .../duniter-test-parameters/macro/src/lib.rs  |  85 ++++++++++++++
 pallets/duniter-test-parameters/src/lib.rs    | 111 ++++++++++++++++++
 pallets/duniter-wot/src/mock.rs               |   1 +
 runtime/common/src/pallets_config.rs          |   8 +-
 runtime/g1/src/parameters.rs                  |   8 +-
 runtime/gdev/Cargo.toml                       |   2 +
 runtime/gdev/src/lib.rs                       |  30 ++++-
 runtime/gdev/src/parameters.rs                |  37 ------
 runtime/gtest/src/parameters.rs               |   8 +-
 17 files changed, 435 insertions(+), 66 deletions(-)
 create mode 100644 pallets/duniter-test-parameters/Cargo.toml
 create mode 100644 pallets/duniter-test-parameters/macro/Cargo.toml
 create mode 100644 pallets/duniter-test-parameters/macro/src/lib.rs
 create mode 100644 pallets/duniter-test-parameters/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index 7229b35a5..f8b3ac429 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1947,6 +1947,7 @@ dependencies = [
  "pallet-babe",
  "pallet-balances",
  "pallet-certification",
+ "pallet-duniter-test-parameters",
  "pallet-duniter-wot",
  "pallet-grandpa",
  "pallet-identity",
@@ -4068,6 +4069,26 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "num_enum"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "object"
 version = "0.27.1"
@@ -4232,6 +4253,32 @@ dependencies = [
  "sp-std",
 ]
 
+[[package]]
+name = "pallet-duniter-test-parameters"
+version = "3.0.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "pallet-duniter-test-parameters-macro",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
+name = "pallet-duniter-test-parameters-macro"
+version = "3.0.0"
+dependencies = [
+ "num_enum",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "pallet-duniter-wot"
 version = "3.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index 225f5d1f5..49847c107 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -98,6 +98,8 @@ resolver = "2"
 members = [
 	'integration-tests',
     'pallets/certification',
+    'pallets/duniter-test-parameters',
+    'pallets/duniter-test-parameters/macro',
     'pallets/duniter-wot',
     'pallets/identity',
 	'pallets/membership',
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index 133dddd49..0d0dcef7f 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -17,9 +17,9 @@
 use super::*;
 use common_runtime::entities::IdtyName;
 use gdev_runtime::{
-    AccountId, BalancesConfig, GenesisConfig, GrandpaConfig, IdentityConfig, IdtyRight, IdtyValue,
-    MembershipConfig, StrongCertConfig, SudoConfig, SystemConfig, UdAccountsStorageConfig,
-    UniversalDividendConfig, WASM_BINARY,
+    AccountId, BalancesConfig, GenesisConfig, GenesisParameters, GrandpaConfig, IdentityConfig,
+    IdtyRight, IdtyValue, MembershipConfig, ParametersConfig, StrongCertConfig, SudoConfig,
+    SystemConfig, UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY,
 };
 use maplit::btreemap;
 use sc_service::ChainType;
@@ -86,6 +86,12 @@ pub fn development_chain_spec() -> Result<ChainSpec, String> {
     ))
 }
 
+fn get_env_u32(env_var_name: &'static str, default_value: u32) -> u32 {
+    std::env::var(env_var_name)
+        .map_or(Ok(default_value), |s| s.parse())
+        .unwrap_or_else(|_| panic!("{} must be a number", env_var_name))
+}
+
 fn devnet_genesis(
     wasm_binary: &[u8],
     initial_authorities: Vec<GrandpaId>,
@@ -93,11 +99,37 @@ fn devnet_genesis(
     root_key: AccountId,
     _enable_println: bool,
 ) -> gdev_runtime::GenesisConfig {
+    let cert_validity_period = get_env_u32("DUNITER_CERT_VALIDITY_PERIOD", 1_000);
+    let membership_period = get_env_u32("DUNITER_MEMBERSHIP_PERIOD", 1_000);
+    let membership_renewable_period = get_env_u32("DUNITER_MEMBERSHIP_RENEWABLE_PERIOD", 50);
+
     gdev_runtime::GenesisConfig {
         system: SystemConfig {
             // Add Wasm runtime to storage.
             code: wasm_binary.to_vec(),
         },
+        parameters: ParametersConfig {
+            parameters: GenesisParameters {
+                cert_period: 15,
+                cert_max_by_issuer: 10,
+                cert_renewable_period: 50,
+                cert_validity_period: 200,
+                idty_confirm_period: 40,
+                idty_creation_period: 50,
+                idty_max_no_right_period: 1_000,
+                membership_period,
+                membership_renewable_period,
+                pending_membership_period: 500,
+                ud_creation_period: 10,
+                ud_first_reeval: 100,
+                ud_reeval_period: 20,
+                ud_reeval_period_in_blocks: 200,
+                wot_first_cert_issuable_on: 20,
+                wot_min_cert_for_ud_right: 2,
+                wot_min_cert_for_cert_right: 3,
+                wot_min_cert_for_create_idty_right: 3,
+            },
+        },
         balances: BalancesConfig {
             balances: Default::default(),
         },
@@ -132,18 +164,16 @@ fn devnet_genesis(
                     (
                         i as u32,
                         MembershipData {
-                            expire_on: gdev_runtime::MembershipPeriod::get(),
-                            renewable_on: gdev_runtime::RenewablePeriod::get(),
+                            expire_on: membership_period,
+                            renewable_on: membership_renewable_period,
                         },
                     )
                 })
                 .collect(),
         },
         strong_cert: StrongCertConfig {
-            certs_by_issuer: clique_wot(
-                initial_identities.len(),
-                gdev_runtime::parameters::ValidityPeriod::get(),
-            ),
+            apply_cert_period_at_genesis: false,
+            certs_by_issuer: clique_wot(initial_identities.len(), cert_validity_period),
         },
         ud_accounts_storage: UdAccountsStorageConfig {
             ud_accounts: initial_identities.values().cloned().collect(),
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 803554474..f601d2221 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -128,6 +128,7 @@ fn devnet_genesis(
                 .collect(),
         },
         strong_cert: StrongCertConfig {
+            apply_cert_period_at_genesis: false,
             certs_by_issuer: clique_wot(
                 initial_identities.len(),
                 gtest_runtime::parameters::ValidityPeriod::get(),
@@ -333,6 +334,7 @@ fn testnet_genesis(
                 .collect(),
         },
         strong_cert: StrongCertConfig {
+            apply_cert_period_at_genesis: false,
             certs_by_issuer: clique_wot(
                 initial_identities.len(),
                 gtest_runtime::parameters::ValidityPeriod::get(),
diff --git a/pallets/certification/src/lib.rs b/pallets/certification/src/lib.rs
index 3462440a0..2636ad729 100644
--- a/pallets/certification/src/lib.rs
+++ b/pallets/certification/src/lib.rs
@@ -39,6 +39,7 @@ pub mod pallet {
     use super::*;
     use frame_support::pallet_prelude::*;
     use frame_system::pallet_prelude::*;
+    use sp_runtime::traits::Saturating;
     use sp_std::collections::btree_map::BTreeMap;
 
     /// The current storage version.
@@ -89,6 +90,7 @@ pub mod pallet {
 
     #[pallet::genesis_config]
     pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
+        pub apply_cert_period_at_genesis: bool,
         pub certs_by_issuer: BTreeMap<T::IdtyIndex, BTreeMap<T::IdtyIndex, T::BlockNumber>>,
     }
 
@@ -96,6 +98,7 @@ pub mod pallet {
     impl<T: Config<I>, I: 'static> Default for GenesisConfig<T, I> {
         fn default() -> Self {
             Self {
+                apply_cert_period_at_genesis: false,
                 certs_by_issuer: Default::default(),
             }
         }
@@ -152,13 +155,14 @@ pub mod pallet {
                         .or_default()
                         .push((*issuer, *receiver));
 
-                    use sp_runtime::traits::Saturating as _;
-                    let issuer_next_issuable_on = removable_on
-                        .saturating_add(T::CertPeriod::get())
-                        .saturating_sub(T::ValidityPeriod::get());
-                    if let Some(cert_meta) = cert_meta_by_issuer.get_mut(issuer) {
-                        if cert_meta.next_issuable_on < issuer_next_issuable_on {
-                            cert_meta.next_issuable_on = issuer_next_issuable_on;
+                    if self.apply_cert_period_at_genesis {
+                        let issuer_next_issuable_on = removable_on
+                            .saturating_add(T::CertPeriod::get())
+                            .saturating_sub(T::ValidityPeriod::get());
+                        if let Some(cert_meta) = cert_meta_by_issuer.get_mut(issuer) {
+                            if cert_meta.next_issuable_on < issuer_next_issuable_on {
+                                cert_meta.next_issuable_on = issuer_next_issuable_on;
+                            }
                         }
                     }
                     let renewable_on = removable_on.saturating_sub(
diff --git a/pallets/certification/src/tests.rs b/pallets/certification/src/tests.rs
index 7c50f5768..1578279e6 100644
--- a/pallets/certification/src/tests.rs
+++ b/pallets/certification/src/tests.rs
@@ -25,6 +25,7 @@ use sp_std::collections::btree_map::BTreeMap;
 #[test]
 fn test_must_receive_cert_before_can_issue() {
     new_test_ext(DefaultCertificationConfig {
+        apply_cert_period_at_genesis: true,
         certs_by_issuer: BTreeMap::new(),
     })
     .execute_with(|| {
@@ -38,6 +39,7 @@ fn test_must_receive_cert_before_can_issue() {
 #[test]
 fn test_genesis_build() {
     new_test_ext(DefaultCertificationConfig {
+        apply_cert_period_at_genesis: true,
         certs_by_issuer: btreemap![
             0 => btreemap![
                 1 => 10,
@@ -111,6 +113,7 @@ fn test_genesis_build() {
 #[test]
 fn test_cert_period() {
     new_test_ext(DefaultCertificationConfig {
+        apply_cert_period_at_genesis: true,
         certs_by_issuer: btreemap![0 => btreemap![1 => 10]],
     })
     .execute_with(|| {
@@ -133,6 +136,7 @@ fn test_cert_period() {
 #[test]
 fn test_renewable_period() {
     new_test_ext(DefaultCertificationConfig {
+        apply_cert_period_at_genesis: true,
         certs_by_issuer: btreemap![0 => btreemap![1 => 10]],
     })
     .execute_with(|| {
diff --git a/pallets/duniter-test-parameters/Cargo.toml b/pallets/duniter-test-parameters/Cargo.toml
new file mode 100644
index 000000000..66193adea
--- /dev/null
+++ b/pallets/duniter-test-parameters/Cargo.toml
@@ -0,0 +1,72 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'Duniter test parameters.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-duniter-test-parameters'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[features]
+default = ['std']
+runtime-benchmarks = ['frame-benchmarking']
+std = [
+    'codec/std',
+    'frame-support/std',
+    'frame-system/std',
+    'frame-benchmarking/std',
+    'serde',
+    "sp-io/std",
+	"sp-std/std",
+]
+try-runtime = ['frame-support/try-runtime']
+
+[dependencies]
+pallet-duniter-test-parameters-macro = { path = "macro" }
+serde = { version = "1.0.101", features = ["derive"], optional = true }
+
+# substrate
+scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '2.3.1'
+
+[dependencies.frame-benchmarking]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+optional = true
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.frame-support]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.frame-system]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.sp-io]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.sp-std]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+[dependencies.sp-runtime]
+default-features = false
+git = 'https://github.com/librelois/substrate.git'
+branch = 'duniter-monthly-2022-01'
+
+### DOC ###
+
+[package.metadata.docs.rs]
+targets = ['x86_64-unknown-linux-gnu']
diff --git a/pallets/duniter-test-parameters/macro/Cargo.toml b/pallets/duniter-test-parameters/macro/Cargo.toml
new file mode 100644
index 000000000..ce0b5a32f
--- /dev/null
+++ b/pallets/duniter-test-parameters/macro/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+authors = ['librelois <c@elo.tf>']
+description = 'Duniter test parameters macro.'
+edition = '2018'
+homepage = 'https://substrate.dev'
+license = 'AGPL-3.0'
+name = 'pallet-duniter-test-parameters-macro'
+repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
+version = '3.0.0'
+
+[lib]
+proc-macro = true
+
+[dependencies]
+num_enum = { version = "0.5.3", default-features = false }
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0", features = [ "extra-traits", "fold", "full", "visit" ] }
diff --git a/pallets/duniter-test-parameters/macro/src/lib.rs b/pallets/duniter-test-parameters/macro/src/lib.rs
new file mode 100644
index 000000000..e969ef8e1
--- /dev/null
+++ b/pallets/duniter-test-parameters/macro/src/lib.rs
@@ -0,0 +1,85 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency 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.
+//
+// Substrate-Libre-Currency 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 Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+#![crate_type = "proc-macro"]
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::{parse_macro_input, spanned::Spanned, Fields, Ident, ItemStruct, Type};
+
+fn snake_to_class_case(ident: &Ident) -> Ident {
+    let span = ident.span();
+    let mut acc = String::new();
+    let mut prev = '_';
+    for ch in ident.to_string().chars() {
+        if ch != '_' {
+            if prev == '_' {
+                for chu in ch.to_uppercase() {
+                    acc.push(chu);
+                }
+            } else if prev.is_uppercase() {
+                for chl in ch.to_lowercase() {
+                    acc.push(chl);
+                }
+            } else {
+                acc.push(ch);
+            }
+        }
+        prev = ch;
+    }
+    Ident::new(&acc, span)
+}
+
+#[proc_macro_attribute]
+pub fn generate_fields_getters(_: TokenStream, input: TokenStream) -> TokenStream {
+    let item_struct = parse_macro_input!(input as ItemStruct);
+
+    let ItemStruct { fields, .. } = item_struct.clone();
+
+    let mut class_idents: Vec<Ident> = Vec::new();
+    let mut idents: Vec<Ident> = Vec::new();
+    let mut types: Vec<Type> = Vec::new();
+    if let Fields::Named(named_fields) = fields {
+        let named_fields = named_fields.named;
+        for field in named_fields.iter() {
+            if let Some(ref ident) = field.ident {
+                class_idents.push(snake_to_class_case(ident));
+                idents.push(ident.clone());
+                types.push(field.ty.clone());
+            }
+        }
+
+        (quote! {
+            #item_struct
+
+            #(
+                pub struct #class_idents<T: Config>(core::marker::PhantomData<T>);
+                impl<T: Config> Get<T::#types> for #class_idents<T> {
+                    fn get() -> T::#types {
+                        Pallet::<T>::parameters().#idents
+                    }
+                }
+            )*
+        })
+        .into()
+    } else {
+        (quote_spanned! {
+            fields.span() => compile_error("Expected named fields");
+        })
+        .into()
+    }
+}
diff --git a/pallets/duniter-test-parameters/src/lib.rs b/pallets/duniter-test-parameters/src/lib.rs
new file mode 100644
index 000000000..b5056f103
--- /dev/null
+++ b/pallets/duniter-test-parameters/src/lib.rs
@@ -0,0 +1,111 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency 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.
+//
+// Substrate-Libre-Currency 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 Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+pub use pallet::*;
+pub use types::*;
+
+pub mod types {
+    use super::{Config, Pallet};
+    use codec::{Decode, Encode};
+    use frame_support::pallet_prelude::*;
+    use pallet_duniter_test_parameters_macro::generate_fields_getters;
+    use scale_info::TypeInfo;
+    #[cfg(feature = "std")]
+    use serde::{Deserialize, Serialize};
+
+    #[generate_fields_getters]
+    #[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
+    #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
+    pub struct Parameters<
+        BlockNumber: Default + Parameter,
+        CertCount: Default + Parameter,
+        PeriodCount: Default + Parameter,
+    > {
+        pub cert_period: BlockNumber,
+        pub cert_max_by_issuer: CertCount,
+        pub cert_renewable_period: BlockNumber,
+        pub cert_validity_period: BlockNumber,
+        pub idty_confirm_period: BlockNumber,
+        pub idty_creation_period: BlockNumber,
+        pub idty_max_no_right_period: BlockNumber,
+        pub membership_period: BlockNumber,
+        pub membership_renewable_period: BlockNumber,
+        pub pending_membership_period: BlockNumber,
+        pub ud_creation_period: BlockNumber,
+        pub ud_first_reeval: BlockNumber,
+        pub ud_reeval_period: PeriodCount,
+        pub ud_reeval_period_in_blocks: BlockNumber,
+        pub wot_first_cert_issuable_on: BlockNumber,
+        pub wot_min_cert_for_ud_right: CertCount,
+        pub wot_min_cert_for_cert_right: CertCount,
+        pub wot_min_cert_for_create_idty_right: CertCount,
+    }
+}
+
+#[frame_support::pallet]
+pub mod pallet {
+    use super::*;
+    use frame_support::pallet_prelude::*;
+    use frame_support::traits::StorageVersion;
+
+    /// The current storage version.
+    const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+    #[pallet::pallet]
+    #[pallet::generate_store(pub(super) trait Store)]
+    #[pallet::storage_version(STORAGE_VERSION)]
+    pub struct Pallet<T>(_);
+
+    // CONFIG //
+
+    #[pallet::config]
+    pub trait Config: frame_system::Config {
+        type CertCount: Default + MaybeSerializeDeserialize + Parameter;
+        type PeriodCount: Default + MaybeSerializeDeserialize + Parameter;
+    }
+
+    // STORAGE //
+
+    #[pallet::storage]
+    #[pallet::getter(fn parameters)]
+    pub type ParametersStorage<T: Config> =
+        StorageValue<_, Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>, ValueQuery>;
+
+    // GENESIS
+
+    #[pallet::genesis_config]
+    pub struct GenesisConfig<T: Config> {
+        pub parameters: Parameters<T::BlockNumber, T::CertCount, T::PeriodCount>,
+    }
+
+    #[cfg(feature = "std")]
+    impl<T: Config> Default for GenesisConfig<T> {
+        fn default() -> Self {
+            Self {
+                parameters: Default::default(),
+            }
+        }
+    }
+
+    #[pallet::genesis_build]
+    impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
+        fn build(&self) {
+            <ParametersStorage<T>>::put(self.parameters.clone());
+        }
+    }
+}
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index fabecf7a6..ccc2ce6d0 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -212,6 +212,7 @@ pub fn new_test_ext(initial_identities_len: usize) -> sp_io::TestExternalities {
         },
         cert: CertConfig {
             certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()),
+            apply_cert_period_at_genesis: true,
         },
     }
     .build_storage()
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index df3e5a6a3..ff6973eb8 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -185,10 +185,10 @@ macro_rules! pallets_config {
 		// WEB OF TRUST //
 
 		impl pallet_duniter_wot::Config for Runtime {
-			type MinCertForUdRight = MinCertForUdRight;
-			type MinCertForCertRight = MinCertForCertRight;
-			type MinCertForCreateIdtyRight = MinCertForCreateIdtyRight;
-			type FirstIssuableOn = FirstIssuableOn;
+			type FirstIssuableOn = WotFirstCertIssuableOn;
+			type MinCertForUdRight = WotMinCertForUdRight;
+			type MinCertForCertRight = WotMinCertForCertRight;
+			type MinCertForCreateIdtyRight = WotMinCertForCreateIdtyRight;
 		}
 
 		impl pallet_identity::Config for Runtime {
diff --git a/runtime/g1/src/parameters.rs b/runtime/g1/src/parameters.rs
index 6cfd3ed99..170b7e5b4 100644
--- a/runtime/g1/src/parameters.rs
+++ b/runtime/g1/src/parameters.rs
@@ -93,16 +93,16 @@ parameter_types! {
 /*******/
 
 parameter_types! {
-    pub MinCertForUdRight: u8 = 5;
-    pub MinCertForCertRight: u8 = 5;
-    pub MinCertForCreateIdtyRight: u8 = 5;
+    pub WotFirstCertIssuableOn: BlockNumber = 30* DAYS;
+    pub WotMinCertForUdRight: u8 = 5;
+    pub WotMinCertForCertRight: u8 = 5;
+    pub WotMinCertForCreateIdtyRight: u8 = 5;
 }
 
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
 parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 14 * DAYS;
-    pub const FirstIssuableOn: BlockNumber = 30* DAYS;
     pub const IdtyCreationPeriod: BlockNumber = MONTHS;
     pub const MaxNoRightPeriod: BlockNumber = YEARS;
     pub const ValidationPeriod: BlockNumber = YEARS;
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index db07d67d8..f5e9dc5af 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -36,6 +36,7 @@ std = [
     'pallet-babe/std',
     'pallet-balances/std',
     'pallet-certification/std',
+    'pallet-duniter-test-parameters/std',
     'pallet-duniter-wot/std',
     'pallet-identity/std',
     'pallet-membership/std',
@@ -66,6 +67,7 @@ std = [
 [dependencies]
 common-runtime = { path = "../common", default-features = false }
 pallet-certification = { path = '../../pallets/certification', default-features = false }
+pallet-duniter-test-parameters = { path = '../../pallets/duniter-test-parameters', default-features = false }
 pallet-duniter-wot = { path = '../../pallets/duniter-wot', default-features = false }
 pallet-identity = { path = '../../pallets/identity', default-features = false }
 pallet-membership = { path = '../../pallets/membership', default-features = false }
diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs
index 468b82482..96973c22e 100644
--- a/runtime/gdev/src/lib.rs
+++ b/runtime/gdev/src/lib.rs
@@ -30,9 +30,9 @@ pub use common_runtime::{
     IdtyNameValidatorImpl, Index, Signature,
 };
 pub use pallet_balances::Call as BalancesCall;
+pub use pallet_duniter_test_parameters::Parameters as GenesisParameters;
 pub use pallet_duniter_wot::IdtyRight;
 pub use pallet_identity::{IdtyStatus, IdtyValue};
-use pallet_transaction_payment::CurrencyAdapter;
 pub use pallet_universal_dividend;
 #[cfg(any(feature = "std", test))]
 pub use sp_runtime::BuildStorage;
@@ -42,6 +42,7 @@ use common_runtime::handlers::OnRightKeyChangeHandler;
 use frame_system::EnsureRoot;
 use pallet_grandpa::fg_primitives;
 use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
+use pallet_transaction_payment::CurrencyAdapter;
 use sp_api::impl_runtime_apis;
 use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
 use sp_runtime::traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, NumberFor};
@@ -142,6 +143,30 @@ impl frame_support::traits::Contains<Call> for BaseCallFilter {
 
 // Configure FRAME pallets to include in runtime.
 common_runtime::pallets_config! {
+    // Dynamic parameters
+    pub type CertPeriod = pallet_duniter_test_parameters::CertPeriod<Runtime>;
+    pub type MaxByIssuer = pallet_duniter_test_parameters::CertMaxByIssuer<Runtime>;
+    pub type StrongCertRenewablePeriod = pallet_duniter_test_parameters::CertRenewablePeriod<Runtime>;
+    pub type ValidityPeriod = pallet_duniter_test_parameters::CertValidityPeriod<Runtime>;
+    pub type ConfirmPeriod = pallet_duniter_test_parameters::IdtyConfirmPeriod<Runtime>;
+    pub type IdtyCreationPeriod = pallet_duniter_test_parameters::IdtyCreationPeriod<Runtime>;
+    pub type MaxNoRightPeriod = pallet_duniter_test_parameters::IdtyMaxNoRightPeriod<Runtime>;
+    pub type MembershipPeriod = pallet_duniter_test_parameters::MembershipPeriod<Runtime>;
+    pub type RenewablePeriod = pallet_duniter_test_parameters::MembershipRenewablePeriod<Runtime>;
+    pub type PendingMembershipPeriod = pallet_duniter_test_parameters::PendingMembershipPeriod<Runtime>;
+    pub type UdCreationPeriod = pallet_duniter_test_parameters::UdCreationPeriod<Runtime>;
+    pub type UdFirstReeval = pallet_duniter_test_parameters::UdFirstReeval<Runtime>;
+    pub type UdReevalPeriod = pallet_duniter_test_parameters::UdReevalPeriod<Runtime>;
+    pub type UdReevalPeriodInBlocks = pallet_duniter_test_parameters::UdReevalPeriodInBlocks<Runtime>;
+    pub type WotFirstCertIssuableOn = pallet_duniter_test_parameters::WotFirstCertIssuableOn<Runtime>;
+    pub type WotMinCertForUdRight = pallet_duniter_test_parameters::WotMinCertForUdRight<Runtime>;
+    pub type WotMinCertForCertRight = pallet_duniter_test_parameters::WotMinCertForCertRight<Runtime>;
+    pub type WotMinCertForCreateIdtyRight = pallet_duniter_test_parameters::WotMinCertForCreateIdtyRight<Runtime>;
+
+    impl pallet_duniter_test_parameters::Config for Runtime {
+        type CertCount = u8;
+        type PeriodCount = Balance;
+    }
     impl pallet_sudo::Config for Runtime {
         type Event = Event;
         type Call = Call;
@@ -159,6 +184,9 @@ construct_runtime!(
         System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0,
         Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1,
 
+        // Test parameters
+        Parameters: pallet_duniter_test_parameters::{Pallet, Config<T>, Storage} = 2,
+
         Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5,
         TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32,
 
diff --git a/runtime/gdev/src/parameters.rs b/runtime/gdev/src/parameters.rs
index b47c41d07..19638d39d 100644
--- a/runtime/gdev/src/parameters.rs
+++ b/runtime/gdev/src/parameters.rs
@@ -46,46 +46,9 @@ frame_support::parameter_types! {
     pub const TransactionByteFee: Balance = 0;
 }
 
-// Wot
-parameter_types! {
-    pub MinCertForUdRight: u8 = 2;
-    pub MinCertForCertRight: u8 = 3;
-    pub MinCertForCreateIdtyRight: u8 = 3;
-}
-
-// Identity
-pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
-frame_support::parameter_types! {
-    pub const ConfirmPeriod: BlockNumber = 40;
-    pub const FirstIssuableOn: BlockNumber = 20;
-    pub const IdtyCreationPeriod: BlockNumber = 50;
-    pub const MaxNoRightPeriod: BlockNumber = 1_000;
-}
-
-// Membership
-parameter_types! {
-    pub const MembershipPeriod: BlockNumber = 1_000;
-    pub const PendingMembershipPeriod: BlockNumber = 500;
-    pub const RenewablePeriod: BlockNumber = 50;
-}
-
-// Certification
-pub const MIN_STRONG_CERT_FOR_UD: u32 = 2;
-pub const MIN_STRONG_CERT_FOR_STRONG_CERT: u32 = 3;
-parameter_types! {
-    pub const CertPeriod: BlockNumber = 15;
-    pub const MaxByIssuer: u8 = 100;
-    pub const StrongCertRenewablePeriod: BlockNumber = 50;//6 * MONTHS;
-    pub const ValidityPeriod: BlockNumber = 2_000;//2 * YEARS;
-}
-
 // Universal dividend
 parameter_types! {
     pub const SquareMoneyGrowthRate: Permill = Permill::one();
-    pub const UdCreationPeriod: BlockNumber = 10;
-    pub const UdFirstReeval: BlockNumber = 100;
-    pub const UdReevalPeriod: Balance = 10;
-    pub const UdReevalPeriodInBlocks: BlockNumber = 20 * 10;
 }
 
 // Multisig
diff --git a/runtime/gtest/src/parameters.rs b/runtime/gtest/src/parameters.rs
index 26eea171d..8dd514901 100644
--- a/runtime/gtest/src/parameters.rs
+++ b/runtime/gtest/src/parameters.rs
@@ -92,16 +92,16 @@ parameter_types! {
 /*******/
 
 parameter_types! {
-    pub MinCertForUdRight: u8 = 5;
-    pub MinCertForCertRight: u8 = 5;
-    pub MinCertForCreateIdtyRight: u8 = 5;
+    pub WotFirstCertIssuableOn: BlockNumber = DAYS;
+    pub WotMinCertForUdRight: u8 = 5;
+    pub WotMinCertForCertRight: u8 = 5;
+    pub WotMinCertForCreateIdtyRight: u8 = 5;
 }
 
 // Identity
 pub const IDTY_CREATE_PERIOD: BlockNumber = 100;
 frame_support::parameter_types! {
     pub const ConfirmPeriod: BlockNumber = 8 * HOURS;
-    pub const FirstIssuableOn: BlockNumber = DAYS;
     pub const IdtyCreationPeriod: BlockNumber = DAYS;
     pub const MaxNoRightPeriod: BlockNumber = 73 * DAYS;
 }
-- 
GitLab