From 5d9b08f58419222e2084a55eedb94fcf348746cb Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Tue, 15 Feb 2022 23:49:43 +0100
Subject: [PATCH] chore: add gdev runtime integration tests

---
 Cargo.lock                              |   3 +
 pallets/identity/src/lib.rs             |   1 +
 runtime/gdev/Cargo.toml                 |   5 +
 runtime/gdev/tests/common/mod.rs        | 425 ++++++++++++++++++++++++
 runtime/gdev/tests/integration_tests.rs | 143 ++++++++
 5 files changed, 577 insertions(+)
 create mode 100644 runtime/gdev/tests/common/mod.rs
 create mode 100644 runtime/gdev/tests/integration_tests.rs

diff --git a/Cargo.lock b/Cargo.lock
index e847b8931..ce9d5ea77 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2038,8 +2038,11 @@ dependencies = [
  "sp-authority-discovery",
  "sp-block-builder",
  "sp-consensus-babe",
+ "sp-consensus-vrf",
  "sp-core",
+ "sp-finality-grandpa",
  "sp-inherents",
+ "sp-io",
  "sp-membership",
  "sp-offchain",
  "sp-runtime",
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index 9602885ba..76d59fd84 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -144,6 +144,7 @@ pub mod pallet {
                         (idty_index, idty.value.status),
                     )
                 }
+                // frame_system::Pallet::<T>::dec_providers(&account);
                 frame_system::Pallet::<T>::inc_sufficients(&idty.value.owner_key);
                 <Identities<T>>::insert(idty_index, idty.value.clone());
                 IdentitiesNames::<T>::insert(idty.name.clone(), ());
diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml
index f74d42564..fb66fe924 100644
--- a/runtime/gdev/Cargo.toml
+++ b/runtime/gdev/Cargo.toml
@@ -73,6 +73,11 @@ std = [
     'sp-version/std',
 ]
 
+[dev-dependencies]
+sp-consensus-vrf = { git = 'https://github.com/librelois/substrate.git', branch = 'duniter-monthly-2022-02' }
+sp-finality-grandpa = { git = 'https://github.com/librelois/substrate.git', branch = 'duniter-monthly-2022-02' }
+sp-io = { git = 'https://github.com/librelois/substrate.git', branch = 'duniter-monthly-2022-02' }
+
 [dependencies]
 common-runtime = { path = "../common", default-features = false }
 pallet-authority-members = { path = '../../pallets/authority-members', default-features = false }
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
new file mode 100644
index 000000000..8cb21971d
--- /dev/null
+++ b/runtime/gdev/tests/common/mod.rs
@@ -0,0 +1,425 @@
+// 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/>.
+
+#![allow(dead_code, unused_imports)] // TODO remove this line when we will have more tests
+
+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 sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
+use sp_consensus_babe::{AuthorityId as BabeId, Slot};
+use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
+use sp_core::crypto::IsWrappedBy;
+use sp_core::sr25519;
+use sp_core::{Encode, Pair, Public};
+use sp_finality_grandpa::AuthorityId as GrandpaId;
+use sp_membership::MembershipData;
+use sp_runtime::testing::{Digest, DigestItem};
+use sp_runtime::traits::{IdentifyAccount, Verify};
+use std::collections::BTreeMap;
+
+pub type AccountPublic = <Signature as Verify>::Signer;
+
+pub type AuthorityKeys = (
+    AccountId,
+    BabeId,
+    GrandpaId,
+    ImOnlineId,
+    AuthorityDiscoveryId,
+);
+
+pub const NAMES: [&str; 6] = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Ferdie"];
+
+//pub const CHARLIE: &str = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y";
+pub const DAVE: &str = "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy";
+
+pub struct ExtBuilder {
+    // endowed accounts with balances
+    initial_authorities_len: usize,
+    initial_balances: Vec<(AccountId, Balance)>,
+    initial_identities: BTreeMap<IdtyName, AccountId>,
+    initial_smiths: Vec<AuthorityKeys>,
+    parameters: GenesisParameters<u32, u32, Balance>,
+}
+
+impl ExtBuilder {
+    pub fn new(
+        initial_authorities_len: usize,
+        initial_smiths_len: usize,
+        initial_identities_len: usize,
+    ) -> Self {
+        assert!(initial_identities_len <= 6);
+        assert!(initial_smiths_len <= initial_identities_len);
+        assert!(initial_authorities_len <= initial_smiths_len);
+
+        let initial_smiths = (0..initial_smiths_len)
+            .map(|i| get_authority_keys_from_seed(NAMES[i]))
+            .collect::<Vec<AuthorityKeys>>();
+        let initial_identities = (0..initial_identities_len)
+            .map(|i| {
+                (
+                    IdtyName::from(NAMES[i]),
+                    get_account_id_from_seed::<sr25519::Public>(NAMES[i]),
+                )
+            })
+            .collect::<BTreeMap<IdtyName, AccountId>>();
+
+        Self {
+            initial_authorities_len,
+            initial_balances: vec![],
+            initial_identities,
+            initial_smiths,
+            parameters: GenesisParameters {
+                babe_epoch_duration: 25,
+                cert_period: 15,
+                cert_max_by_issuer: 10,
+                cert_min_received_cert_to_issue_cert: 2,
+                cert_renewable_period: 50,
+                cert_validity_period: 10_000,
+                idty_confirm_period: 40,
+                idty_creation_period: 50,
+                idty_max_disabled_period: 1_000,
+                membership_period: 1_000,
+                membership_renewable_period: 5,
+                pending_membership_period: 500,
+                ud_creation_period: 10,
+                ud_first_reeval: 100,
+                ud_reeval_period: 20,
+                ud_reeval_period_in_blocks: 10 * 20,
+                smith_cert_period: 15,
+                smith_cert_max_by_issuer: 8,
+                smith_cert_min_received_cert_to_issue_cert: 2,
+                smith_cert_renewable_period: 50,
+                smith_cert_validity_period: 1_000,
+                smith_membership_period: 1_000,
+                smith_membership_renewable_period: 50,
+                smith_pending_membership_period: 500,
+                smiths_wot_first_cert_issuable_on: 20,
+                smiths_wot_min_cert_for_membership: 2,
+                wot_first_cert_issuable_on: 20,
+                wot_min_cert_for_create_idty_right: 2,
+                wot_min_cert_for_membership: 2,
+            },
+        }
+    }
+
+    /*pub fn with_initial_balances(mut self, initial_balances: Vec<(AccountId, Balance)>) -> Self {
+        self.initial_balances = initial_balances;
+        self
+    }
+
+    pub fn with_parameters(mut self, parameters: GenesisParameters<u32, u32, Balance>) -> Self {
+        self.parameters = parameters;
+        self
+    }*/
+
+    pub fn build(self) -> sp_io::TestExternalities {
+        let Self {
+            initial_authorities_len,
+            initial_balances,
+            initial_identities,
+            initial_smiths,
+            parameters,
+        } = self;
+
+        let mut t = frame_system::GenesisConfig::default()
+            .build_storage::<Runtime>()
+            .unwrap();
+
+        pallet_authority_members::GenesisConfig::<Runtime> {
+            initial_authorities: initial_smiths
+                .iter()
+                .enumerate()
+                .map(|(i, keys)| (i as u32 + 1, (keys.0.clone(), i < initial_authorities_len)))
+                .collect(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        /*pallet_babe::GenesisConfig {
+            authorities: Vec::with_capacity(0),
+            epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();*/
+
+        pallet_balances::GenesisConfig::<Runtime> {
+            balances: initial_balances,
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_duniter_test_parameters::GenesisConfig::<Runtime> { parameters }
+            .assimilate_storage(&mut t)
+            .unwrap();
+
+        pallet_session::GenesisConfig::<Runtime> {
+            keys: initial_smiths
+                .iter()
+                .map(|x| {
+                    (
+                        x.0.clone(),
+                        x.0.clone(),
+                        session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone()),
+                    )
+                })
+                .collect::<Vec<_>>(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_identity::GenesisConfig::<Runtime> {
+            identities: initial_identities
+                .iter()
+                .enumerate()
+                .map(|(i, (name, owner_key))| GenesisIdty {
+                    index: i as u32 + 1,
+                    name: name.clone(),
+                    value: IdtyValue {
+                        next_creatable_identity_on: Default::default(),
+                        owner_key: owner_key.clone(),
+                        removable_on: 0,
+                        status: IdtyStatus::Validated,
+                    },
+                })
+                .collect(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_membership::GenesisConfig::<Runtime, Instance1> {
+            memberships: (1..=initial_identities.len())
+                .map(|i| {
+                    (
+                        i as u32,
+                        MembershipData {
+                            expire_on: parameters.membership_period,
+                            renewable_on: parameters.membership_renewable_period,
+                        },
+                    )
+                })
+                .collect(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_certification::GenesisConfig::<Runtime, Instance1> {
+            apply_cert_period_at_genesis: false,
+            certs_by_issuer: clique_wot(initial_identities.len(), parameters.cert_validity_period),
+        }
+        .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,
+                            renewable_on: parameters.smith_membership_renewable_period,
+                        },
+                    )
+                })
+                .collect(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_certification::GenesisConfig::<Runtime, Instance2> {
+            apply_cert_period_at_genesis: false,
+            certs_by_issuer: clique_wot(
+                initial_smiths.len(),
+                parameters.smith_cert_validity_period,
+            ),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_ud_accounts_storage::GenesisConfig::<Runtime> {
+            ud_accounts: initial_identities
+                .values()
+                .cloned()
+                .enumerate()
+                .map(|(i, account)| (account, (i + 1) as u32))
+                .collect(),
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        pallet_universal_dividend::GenesisConfig::<Runtime> {
+            first_ud: 1_000,
+            initial_monetary_mass: 0,
+        }
+        .assimilate_storage(&mut t)
+        .unwrap();
+
+        let mut ext = sp_io::TestExternalities::new(t);
+
+        ext.execute_with(|| {
+            System::set_block_number(1);
+        });
+
+        ext
+    }
+}
+
+/// Generate a crypto pair from seed.
+pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
+    TPublic::Pair::from_string(&format!("//{}", seed), None)
+        .expect("static values are valid; qed")
+        .public()
+}
+
+/// Generate an account ID from seed.
+pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
+where
+    AccountPublic: From<<TPublic::Pair as Pair>::Public>,
+{
+    AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
+}
+
+/// Generate an authority keys.
+pub fn get_authority_keys_from_seed(s: &str) -> AuthorityKeys {
+    (
+        get_account_id_from_seed::<sr25519::Public>(s),
+        get_from_seed::<BabeId>(s),
+        get_from_seed::<GrandpaId>(s),
+        get_from_seed::<ImOnlineId>(s),
+        get_from_seed::<AuthorityDiscoveryId>(s),
+    )
+}
+
+pub fn run_to_block(n: u32) {
+    while System::block_number() < n {
+        // Finalize the previous block
+        //Babe::on_finalize(System::block_number());
+        //Timestamp::on_finalize(System::block_number());
+        TransactionPayment::on_finalize(System::block_number());
+        Authorship::on_finalize(System::block_number());
+        Grandpa::on_finalize(System::block_number());
+
+        // Set the new block number and author
+        System::reset_events();
+        System::set_block_number(System::block_number() + 1);
+
+        // Initialize the new block
+        Scheduler::on_initialize(System::block_number());
+        //Babe::on_initialize(System::block_number());
+        Authorship::on_initialize(System::block_number());
+        Session::on_initialize(System::block_number());
+
+        UniversalDividend::on_initialize(System::block_number());
+        Wot::on_initialize(System::block_number());
+        Identity::on_initialize(System::block_number());
+        Membership::on_initialize(System::block_number());
+        Cert::on_initialize(System::block_number());
+        SmithsSubWot::on_initialize(System::block_number());
+        SmithsMembership::on_initialize(System::block_number());
+        SmithsCert::on_initialize(System::block_number());
+    }
+}
+
+/*pub fn make_primary_pre_digest(
+    authority_index: sp_consensus_babe::AuthorityIndex,
+    slot: sp_consensus_babe::Slot,
+    vrf_output: VRFOutput,
+    vrf_proof: VRFProof,
+) -> Digest {
+    let digest_data = sp_consensus_babe::digests::PreDigest::Primary(
+        sp_consensus_babe::digests::PrimaryPreDigest {
+            authority_index,
+            slot,
+            vrf_output,
+            vrf_proof,
+        },
+    );
+    let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode());
+    Digest { logs: vec![log] }
+}
+
+pub fn make_vrf_output(
+    slot: Slot,
+    pair: &sp_consensus_babe::AuthorityPair,
+) -> (VRFOutput, VRFProof, [u8; 32]) {
+    let pair = sp_core::sr25519::Pair::from_ref(pair).as_ref();
+    let transcript = sp_consensus_babe::make_transcript(&Babe::randomness(), slot, 0);
+    let vrf_inout = pair.vrf_sign(transcript);
+    let vrf_randomness: sp_consensus_vrf::schnorrkel::Randomness = vrf_inout
+        .0
+        .make_bytes::<[u8; 32]>(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT);
+    let vrf_output = VRFOutput(vrf_inout.0.to_output());
+    let vrf_proof = VRFProof(vrf_inout.1);
+
+    (vrf_output, vrf_proof, vrf_randomness)
+}
+
+pub fn make_secondary_vrf_pre_digest(
+    authority_index: sp_consensus_babe::AuthorityIndex,
+    slot: sp_consensus_babe::Slot,
+    vrf_output: VRFOutput,
+    vrf_proof: VRFProof,
+) -> Digest {
+    let digest_data = sp_consensus_babe::digests::PreDigest::SecondaryVRF(
+        sp_consensus_babe::digests::SecondaryVRFPreDigest {
+            authority_index,
+            slot,
+            vrf_output,
+            vrf_proof,
+        },
+    );
+    let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode());
+    Digest { logs: vec![log] }
+}*/
+
+fn clique_wot(
+    initial_identities_len: usize,
+    cert_validity_period: common_runtime::BlockNumber,
+) -> BTreeMap<IdtyIndex, BTreeMap<IdtyIndex, common_runtime::BlockNumber>> {
+    let mut certs_by_issuer = BTreeMap::new();
+    for i in 1..=initial_identities_len {
+        certs_by_issuer.insert(
+            i as IdtyIndex,
+            (1..=initial_identities_len)
+                .filter_map(|j| {
+                    if i != j {
+                        Some((j as IdtyIndex, cert_validity_period))
+                    } else {
+                        None
+                    }
+                })
+                .collect(),
+        );
+    }
+    certs_by_issuer
+}
+
+fn session_keys(
+    babe: BabeId,
+    grandpa: GrandpaId,
+    im_online: ImOnlineId,
+    authority_discovery: AuthorityDiscoveryId,
+) -> SessionKeys {
+    SessionKeys {
+        babe,
+        grandpa,
+        im_online,
+        authority_discovery,
+    }
+}
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
new file mode 100644
index 000000000..655f6186b
--- /dev/null
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -0,0 +1,143 @@
+// 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/>.
+
+mod common;
+
+use common::*;
+use frame_support::traits::{PalletInfo, StorageInfo, StorageInfoTrait};
+//use frame_support::{assert_err, assert_ok};
+use frame_support::assert_ok;
+use frame_support::{StorageHasher, Twox128};
+use gdev_runtime::*;
+use sp_core::crypto::Ss58Codec;
+
+#[test]
+fn verify_pallet_prefixes() {
+    let prefix = |pallet_name, storage_name| {
+        let mut res = [0u8; 32];
+        res[0..16].copy_from_slice(&Twox128::hash(pallet_name));
+        res[16..32].copy_from_slice(&Twox128::hash(storage_name));
+        res.to_vec()
+    };
+    assert_eq!(
+        <Timestamp as StorageInfoTrait>::storage_info(),
+        vec![
+            StorageInfo {
+                pallet_name: b"Timestamp".to_vec(),
+                storage_name: b"Now".to_vec(),
+                prefix: prefix(b"Timestamp", b"Now"),
+                max_values: Some(1),
+                max_size: Some(8),
+            },
+            StorageInfo {
+                pallet_name: b"Timestamp".to_vec(),
+                storage_name: b"DidUpdate".to_vec(),
+                prefix: prefix(b"Timestamp", b"DidUpdate"),
+                max_values: Some(1),
+                max_size: Some(1),
+            }
+        ]
+    );
+}
+
+#[test]
+fn verify_pallet_indices() {
+    fn is_pallet_index<P: 'static>(index: usize) {
+        assert_eq!(
+            <Runtime as frame_system::Config>::PalletInfo::index::<P>(),
+            Some(index)
+        );
+    }
+    is_pallet_index::<System>(0);
+}
+
+#[test]
+fn verify_proxy_type_indices() {
+    assert_eq!(ProxyType::Any as u8, 0);
+}
+
+#[test]
+fn test_genesis_build() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(2);
+    });
+}
+
+#[test]
+fn test_remove_identity() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(2);
+
+        assert_ok!(Identity::remove_identity(
+            frame_system::RawOrigin::Root.into(),
+            4,
+            None
+        ));
+        let events = System::events();
+        assert_eq!(events.len(), 3);
+        assert_eq!(
+            System::events()[0].event,
+            Event::Membership(pallet_membership::Event::MembershipRevoked(4))
+        );
+        /*println!(
+            "{}",
+            get_account_id_from_seed::<sp_core::sr25519::Public>("Charlie")
+        );*/
+        assert_eq!(
+            System::events()[1].event,
+            Event::System(frame_system::Event::KilledAccount {
+                account: AccountId::from_ss58check(DAVE).unwrap()
+            })
+        );
+        assert_eq!(
+            System::events()[2].event,
+            Event::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 4 })
+        );
+        //println!("{:#?}", events);
+    });
+}
+
+#[test]
+fn test_remove_smith_identity() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(2);
+
+        assert_ok!(Identity::remove_identity(
+            frame_system::RawOrigin::Root.into(),
+            3,
+            None
+        ));
+        let events = System::events();
+        assert_eq!(events.len(), 4);
+        assert_eq!(
+            System::events()[0].event,
+            Event::AuthorityMembers(pallet_authority_members::Event::MemberRemoved(3))
+        );
+        assert_eq!(
+            System::events()[1].event,
+            Event::SmithsMembership(pallet_membership::Event::MembershipRevoked(3))
+        );
+        assert_eq!(
+            System::events()[2].event,
+            Event::Membership(pallet_membership::Event::MembershipRevoked(3))
+        );
+        assert_eq!(
+            System::events()[3].event,
+            Event::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 3 })
+        );
+        //println!("{:#?}", events);
+    });
+}
-- 
GitLab