From f562a95bbaca1902fba2731428079e8783256bf4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Moreau?= <cem.moreau@gmail.com>
Date: Fri, 2 Feb 2024 22:09:24 +0100
Subject: [PATCH] Resolve #152 "remove random_id mechanism which is heavy and
 that we do not use" (nodes/rust/duniter-v2s!235)

* remove unnecessary currency associated type

* WIP: rebase

* WIP: update docs

* WIP: clippy

* WIP: test pass

* WIP: // TODO: decrement consumers?
---
 Cargo.lock                                    |   1 -
 docs/api/runtime-events.md                    |  19 +----
 live-tests/tests/sanity_gdev.rs               |   6 +-
 node/src/chain_spec/gen_genesis_data.rs       |   7 +-
 pallets/README.md                             |   2 +-
 pallets/duniter-account/Cargo.toml            |   4 -
 pallets/duniter-account/README.md             |   8 +-
 pallets/duniter-account/src/benchmarking.rs   |  20 -----
 pallets/duniter-account/src/lib.rs            |  73 ++----------------
 pallets/duniter-account/src/types.rs          |   6 --
 pallets/duniter-account/src/weights.rs        |  29 -------
 resources/metadata.scale                      | Bin 112080 -> 111870 bytes
 runtime/common/src/pallets_config.rs          |   3 +-
 .../src/weights/pallet_duniter_account.rs     |  47 -----------
 runtime/gdev/tests/common/mod.rs              |   2 -
 runtime/gdev/tests/integration_tests.rs       |  59 ++++----------
 16 files changed, 32 insertions(+), 254 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 026013d64..45eec7591 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6603,7 +6603,6 @@ dependencies = [
  "maplit",
  "pallet-balances",
  "pallet-identity",
- "pallet-provide-randomness",
  "pallet-quota",
  "pallet-transaction-payment",
  "pallet-treasury",
diff --git a/docs/api/runtime-events.md b/docs/api/runtime-events.md
index 71abd3323..0787b7f5f 100644
--- a/docs/api/runtime-events.md
+++ b/docs/api/runtime-events.md
@@ -1,6 +1,6 @@
 # Runtime events
 
-There are **129** events from **35** pallets.
+There are **128** events from **35** pallets.
 
 <ul>
 <li>System - 0
@@ -112,20 +112,7 @@ balance: T::Balance
 <li>
 <details>
 <summary>
-<code>RandomIdAssigned(who, random_id)</code> - 1</summary>
-A random ID has been assigned to the account.
-
-```rust
-who: T::AccountId
-random_id: H256
-```
-
-</details>
-</li>
-<li>
-<details>
-<summary>
-<code>AccountLinked(who, identity)</code> - 2</summary>
+<code>AccountLinked(who, identity)</code> - 1</summary>
 account linked to identity
 
 ```rust
@@ -138,7 +125,7 @@ identity: IdtyIdOf<T>
 <li>
 <details>
 <summary>
-<code>AccountUnlinked()</code> - 3</summary>
+<code>AccountUnlinked()</code> - 2</summary>
 The account was unlinked from its identity.
 
 ```rust
diff --git a/live-tests/tests/sanity_gdev.rs b/live-tests/tests/sanity_gdev.rs
index 814af0786..86cec2524 100644
--- a/live-tests/tests/sanity_gdev.rs
+++ b/live-tests/tests/sanity_gdev.rs
@@ -235,10 +235,10 @@ mod verifier {
 
                 if account_id.as_slice() != TREASURY_ACCOUNT_ID {
                     // Rule 4: If the account is not a "special account",
-                    // it should have a random id or a consumer
+                    // it should have a consumer
                     self.assert(
-                        account_info.data.random_id.is_some() || account_info.consumers > 0,
-                        format!("Account {} has no random_id nor consumer.", account_id),
+                        account_info.consumers > 0,
+                        format!("Account {} has no consumer.", account_id),
                     );
                 }
             }
diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs
index ba2609e03..b6ce08e5f 100644
--- a/node/src/chain_spec/gen_genesis_data.rs
+++ b/node/src/chain_spec/gen_genesis_data.rs
@@ -25,7 +25,7 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_consensus_babe::AuthorityId as BabeId;
 use sp_consensus_grandpa::AuthorityId as GrandpaId;
 use sp_core::crypto::AccountId32;
-use sp_core::{blake2_256, ed25519, sr25519, Decode, Encode, H256};
+use sp_core::{ed25519, sr25519, Decode, Encode};
 use sp_runtime::traits::{IdentifyAccount, Verify};
 use sp_runtime::{MultiSignature, Perbill};
 use std::collections::{BTreeMap, HashMap};
@@ -1162,7 +1162,6 @@ fn v1_wallets_to_v2_accounts(
             accounts.insert(
                 owner_key.clone(),
                 GenesisAccountData {
-                    random_id: H256(blake2_256(&(balance, &owner_key).encode())),
                     balance,
                     idty_id: None,
                 },
@@ -1425,7 +1424,6 @@ fn feed_identities(
         accounts.insert(
             identity.owner_key.clone(),
             GenesisAccountData {
-                random_id: H256(blake2_256(&(identity.index, &identity.owner_key).encode())),
                 balance: identity.balance,
                 idty_id: Some(identity.index),
             },
@@ -1747,9 +1745,6 @@ where
             (
                 owner_key.clone(),
                 GenesisAccountData {
-                    random_id: H256(blake2_256(
-                        &(i as u32 + idty_index_start, owner_key).encode(),
-                    )),
                     // Should be sufficient for the overhead benchmark
                     balance: initial_idty_balance,
                     idty_id: Some(i as u32 + idty_index_start),
diff --git a/pallets/README.md b/pallets/README.md
index 4e229119e..e25c7907f 100644
--- a/pallets/README.md
+++ b/pallets/README.md
@@ -8,7 +8,7 @@ These pallets are at the core of Duniter/Ğ1 currency
 
 - **`authority-members`** Duniter authorities are not selected with staking but through a smith web of trust.
 - **`certification`** Certifications are the "edges" of Duniter's dynamic directed graph. They mean the acceptation of a Licence.
-- **`duniter-account`** Duniter customized the `AccountData` defined in the `Balances` pallet to introduce a `RandomId`.
+- **`duniter-account`** Duniter customized the `AccountData` defined in the `Balances` pallet to introduce a `linked_idty`.
 - **`duniter-wot`** Merges identities, membership, certifications and distance pallets to implement Duniter Web of Trust.
 - **`distance`** Publishes median of distance computation results provided by inherents coming from `distance-oracle` workers.
 - **`identity`** Identities are the "nodes" of Duniter's dynamic directed graph. They are one-to-one mapping to human being.
diff --git a/pallets/duniter-account/Cargo.toml b/pallets/duniter-account/Cargo.toml
index 8e1dca7dc..304f5f331 100644
--- a/pallets/duniter-account/Cargo.toml
+++ b/pallets/duniter-account/Cargo.toml
@@ -17,7 +17,6 @@ runtime-benchmarks = [
     'frame-system/runtime-benchmarks',
     'sp-runtime/runtime-benchmarks',
     'pallet-identity/runtime-benchmarks',
-    'pallet-provide-randomness/runtime-benchmarks',
     'pallet-treasury/runtime-benchmarks',
     'pallet-quota/runtime-benchmarks',
     'pallet-balances/runtime-benchmarks',
@@ -30,7 +29,6 @@ std = [
     'pallet-balances/std',
     'pallet-transaction-payment/std',
     'pallet-identity/std',
-    'pallet-provide-randomness/std',
     'pallet-treasury/std',
     'pallet-quota/std',
     'serde/std',
@@ -46,7 +44,6 @@ try-runtime = [
     'frame-system/try-runtime',
     'sp-runtime/try-runtime',
     'pallet-identity/try-runtime',
-    'pallet-provide-randomness/try-runtime',
     'pallet-treasury/try-runtime',
     'pallet-quota/try-runtime',
     'pallet-balances/try-runtime',
@@ -57,7 +54,6 @@ try-runtime = [
 # local
 pallet-quota = { path = "../quota", default-features = false }
 pallet-identity = { path = "../identity", default-features = false }
-pallet-provide-randomness = { path = "../provide-randomness", default-features = false }
 
 # crates.io
 codec = { package = 'parity-scale-codec', version = "3.6.9", default-features = false, features = ["derive"] }
diff --git a/pallets/duniter-account/README.md b/pallets/duniter-account/README.md
index 5d9e73b14..185e37ce5 100644
--- a/pallets/duniter-account/README.md
+++ b/pallets/duniter-account/README.md
@@ -1,12 +1,6 @@
 # Duniter account pallet
 
-Duniter customizes the `AccountData` of the `Balances` Substrate pallet. In particular, it adds the fields `random_id` and `linked_idty`. 
-
-## RandomID
-
-The RandomId field was added with the idea to provide a unique id that can not be controlled by user to serve as a basis for robust identification. The discussion is available on the forum.
-
-https://forum.duniter.org/t/la-solution-pour-des-identicones-securisees-le-random-id/9126
+Duniter customizes the `AccountData` of the `Balances` Substrate pallet. In particular, it adds the field `linked_idty`. 
 
 ## Account creation fee
 
diff --git a/pallets/duniter-account/src/benchmarking.rs b/pallets/duniter-account/src/benchmarking.rs
index 27a839e1a..b5594e7d2 100644
--- a/pallets/duniter-account/src/benchmarking.rs
+++ b/pallets/duniter-account/src/benchmarking.rs
@@ -21,14 +21,9 @@ use super::*;
 use frame_benchmarking::{account, benchmarks, whitelisted_caller};
 use frame_support::sp_runtime::{traits::One, Saturating};
 use frame_support::traits::{Currency, Get};
-use pallet_provide_randomness::OnFilledRandomness;
 
 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());
-}
-
 fn create_pending_accounts<T: Config>(
     i: u32,
     is_balance: bool,
@@ -72,19 +67,4 @@ benchmarks! {
     on_initialize_no_balance {
         let i in 0 .. T::MaxNewAccountsPerBlock::get() => create_pending_accounts::<T>(i, false, false)?;
     }: { Pallet::<T>::on_initialize(BlockNumberFor::<T>::one()); }
-    on_filled_randomness_pending {
-        let caller: T::AccountId = whitelisted_caller();
-        let randomness = H256(T::AccountIdToSalt::convert(caller.clone()));
-        let request_id = pallet_provide_randomness::Pallet::<T>::force_request(pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo, randomness);
-        PendingRandomIdAssignments::<T>::insert(request_id, caller.clone());
-    }: { Pallet::<T>::on_filled_randomness(request_id,  randomness); }
-    verify {
-        assert_has_event::<T>(Event::<T>::RandomIdAssigned { who: caller, random_id: randomness }.into());
-    }
-    on_filled_randomness_no_pending {
-        let caller: T::AccountId = whitelisted_caller();
-        let randomness = H256(T::AccountIdToSalt::convert(caller.clone()));
-        let request_id = pallet_provide_randomness::Pallet::<T>::force_request(pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo, randomness);
-        assert!(!PendingRandomIdAssignments::<T>::contains_key(request_id));
-    }: { Pallet::<T>::on_filled_randomness(request_id,  randomness); }
 }
diff --git a/pallets/duniter-account/src/lib.rs b/pallets/duniter-account/src/lib.rs
index 05f0c69e3..596554ec7 100644
--- a/pallets/duniter-account/src/lib.rs
+++ b/pallets/duniter-account/src/lib.rs
@@ -32,10 +32,8 @@ use frame_support::pallet_prelude::*;
 use frame_support::traits::{Currency, ExistenceRequirement, StorageVersion};
 use frame_support::traits::{OnUnbalanced, StoredMap};
 use frame_system::pallet_prelude::*;
-use pallet_provide_randomness::RequestId;
 use pallet_quota::traits::RefundFee;
 use pallet_transaction_payment::OnChargeTransaction;
-use sp_core::H256;
 use sp_runtime::traits::{Convert, DispatchInfoOf, PostDispatchInfoOf, Saturating};
 use sp_std::fmt::Debug;
 
@@ -61,7 +59,6 @@ pub mod pallet {
     pub trait Config:
         frame_system::Config<AccountData = AccountData<Self::Balance, IdtyIdOf<Self>>>
         + pallet_balances::Config
-        + pallet_provide_randomness::Config<Currency = pallet_balances::Pallet<Self>>
         + pallet_transaction_payment::Config
         + pallet_treasury::Config<Currency = pallet_balances::Pallet<Self>>
         + pallet_quota::Config
@@ -75,6 +72,8 @@ pub mod pallet {
         type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
         /// Type representing the weight of this pallet
         type WeightInfo: WeightInfo;
+        /// Handler for the unbalanced reduction when the requestor pays fees.
+        type OnUnbalanced: OnUnbalanced<pallet_balances::NegativeImbalance<Self>>;
         /// wrapped type
         type InnerOnChargeTransaction: OnChargeTransaction<Self>;
         /// type implementing refund behavior
@@ -83,11 +82,6 @@ pub mod pallet {
 
     // STORAGE //
 
-    #[pallet::storage]
-    #[pallet::getter(fn pending_random_id_assignments)]
-    pub type PendingRandomIdAssignments<T: Config> =
-        StorageMap<_, Twox64Concat, RequestId, T::AccountId, OptionQuery>;
-
     #[pallet::storage]
     #[pallet::getter(fn pending_new_accounts)]
     pub type PendingNewAccounts<T: Config> =
@@ -120,7 +114,6 @@ pub mod pallet {
             frame_system::Account::<T>::mutate(
                 pallet_treasury::Pallet::<T>::account_id(),
                 |account| {
-                    account.data.random_id = None;
                     account.data.free = self.treasury_balance;
                     account.providers = 1;
                 },
@@ -139,20 +132,11 @@ pub mod pallet {
             );
 
             // Classic accounts
-            for (
-                account_id,
-                GenesisAccountData {
-                    random_id,
-                    balance,
-                    idty_id,
-                },
-            ) in &self.accounts
-            {
+            for (account_id, GenesisAccountData { balance, idty_id }) in &self.accounts {
                 // if the balance is below existential deposit, the account must be an identity
                 assert!(balance >= &T::ExistentialDeposit::get() || idty_id.is_some());
                 // mutate account
                 frame_system::Account::<T>::mutate(account_id, |account| {
-                    account.data.random_id = Some(*random_id);
                     account.data.free = *balance;
                     if idty_id.is_some() {
                         account.data.linked_idty = *idty_id;
@@ -179,8 +163,6 @@ pub mod pallet {
             who: T::AccountId,
             balance: T::Balance,
         },
-        /// A random ID has been assigned to the account.
-        RandomIdAssigned { who: T::AccountId, random_id: H256 },
         /// account linked to identity
         AccountLinked {
             who: T::AccountId,
@@ -243,11 +225,6 @@ pub mod pallet {
             {
                 if frame_system::Pallet::<T>::sufficients(&account_id) > 0 {
                     // If the account is self-sufficient, it is exempt from account creation fees
-                    let request_id = pallet_provide_randomness::Pallet::<T>::force_request(
-                        pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo,
-                        H256(T::AccountIdToSalt::convert(account_id.clone())),
-                    );
-                    PendingRandomIdAssignments::<T>::insert(request_id, account_id);
                     total_weight += <T as pallet::Config>::WeightInfo::on_initialize_sufficient(
                         T::MaxNewAccountsPerBlock::get(),
                     );
@@ -258,11 +235,7 @@ pub mod pallet {
                     if account_data.free >= T::ExistentialDeposit::get() + price {
                         // The account can pay the new account price, we should:
                         // 1. Withdraw the "new account price" amount
-                        // 2. Increment consumers to prevent the destruction of the account before
-                        // the random id is assigned
-                        // 3. Manage the funds collected
-                        // 4. Submit random id generation request
-                        // 5. Save the id of the random generation request.
+                        // 2. Manage the funds collected
                         let res = <pallet_balances::Pallet<T> as Currency<T::AccountId>>::withdraw(
                             &account_id,
                             price,
@@ -274,18 +247,7 @@ pub mod pallet {
                             "Cannot fail because we checked that the free balance was sufficient"
                         );
                         if let Ok(imbalance) = res {
-                            let res =
-                                frame_system::Pallet::<T>::inc_consumers_without_limit(&account_id);
-                            debug_assert!(
-                                res.is_ok(),
-                                "Cannot fail because any account with funds should have providers"
-                            );
                             T::OnUnbalanced::on_unbalanced(imbalance);
-                            let request_id = pallet_provide_randomness::Pallet::<T>::force_request(
-                                pallet_provide_randomness::RandomnessType::RandomnessFromTwoEpochsAgo,
-                                H256(T::AccountIdToSalt::convert(account_id.clone())),
-                            );
-                            PendingRandomIdAssignments::<T>::insert(request_id, account_id);
                             total_weight +=
                                 <T as pallet::Config>::WeightInfo::on_initialize_with_balance(
                                     T::MaxNewAccountsPerBlock::get(),
@@ -332,28 +294,6 @@ where
     }
 }
 
-// implement on filled randomness
-impl<T> pallet_provide_randomness::OnFilledRandomness for Pallet<T>
-where
-    T: Config,
-{
-    fn on_filled_randomness(request_id: RequestId, randomness: H256) -> Weight {
-        if let Some(account_id) = PendingRandomIdAssignments::<T>::take(request_id) {
-            frame_system::Account::<T>::mutate(&account_id, |account| {
-                account.consumers = account.consumers.saturating_sub(1);
-                account.data.random_id = Some(randomness);
-            });
-            Self::deposit_event(Event::RandomIdAssigned {
-                who: account_id,
-                random_id: randomness,
-            });
-            <T as pallet::Config>::WeightInfo::on_filled_randomness_pending()
-        } else {
-            <T as pallet::Config>::WeightInfo::on_filled_randomness_no_pending()
-        }
-    }
-}
-
 // implement accountdata storedmap
 impl<T, AccountId, Balance>
     frame_support::traits::StoredMap<AccountId, pallet_balances::AccountData<Balance>> for Pallet<T>
@@ -378,8 +318,7 @@ where
         + scale_info::TypeInfo,
     T: Config
         + frame_system::Config<AccountId = AccountId, AccountData = AccountData<Balance, IdtyIdOf<T>>>
-        + pallet_balances::Config<Balance = Balance>
-        + pallet_provide_randomness::Config,
+        + pallet_balances::Config<Balance = Balance>,
 {
     fn get(k: &AccountId) -> pallet_balances::AccountData<Balance> {
         frame_system::Account::<T>::get(k).data.into()
@@ -399,7 +338,7 @@ where
         let result = f(&mut some_data)?;
         let is_providing = some_data.is_some();
         match (was_providing, is_providing) {
-            // the account has just been created, increment its provider and request a random_id
+            // the account has just been created, increment its provider
             (false, true) => {
                 frame_system::Pallet::<T>::inc_providers(account_id);
                 PendingNewAccounts::<T>::insert(account_id, ());
diff --git a/pallets/duniter-account/src/types.rs b/pallets/duniter-account/src/types.rs
index 77553c4db..c44cb0873 100644
--- a/pallets/duniter-account/src/types.rs
+++ b/pallets/duniter-account/src/types.rs
@@ -17,15 +17,11 @@
 use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::pallet_prelude::*;
 use scale_info::TypeInfo;
-use sp_core::H256;
 use sp_runtime::traits::Zero;
 
 // see `struct AccountData` for details in substrate code
 #[derive(Clone, Decode, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] // Default,
 pub struct AccountData<Balance, IdtyId> {
-    /// A random identifier that can not be chosen by the user
-    // this intends to be used as a robust identification system
-    pub(super) random_id: Option<H256>,
     // see Substrate AccountData
     pub(super) free: Balance,
     // see Substrate AccountData
@@ -43,7 +39,6 @@ impl<Balance: Zero, IdtyId> Default for AccountData<Balance, IdtyId> {
     fn default() -> Self {
         Self {
             linked_idty: None,
-            random_id: None,
             free: Balance::zero(),
             reserved: Balance::zero(),
             fee_frozen: Balance::zero(),
@@ -89,7 +84,6 @@ impl<Balance: Zero, IdtyId> From<AccountData<Balance, IdtyId>>
 )]
 #[serde(deny_unknown_fields)]
 pub struct GenesisAccountData<Balance, IdtyId> {
-    pub random_id: H256,
     pub balance: Balance,
     pub idty_id: Option<IdtyId>,
 }
diff --git a/pallets/duniter-account/src/weights.rs b/pallets/duniter-account/src/weights.rs
index d8ccf6bb5..f4bbe1588 100644
--- a/pallets/duniter-account/src/weights.rs
+++ b/pallets/duniter-account/src/weights.rs
@@ -23,8 +23,6 @@ pub trait WeightInfo {
     fn on_initialize_sufficient(i: u32) -> Weight;
     fn on_initialize_with_balance(i: u32) -> Weight;
     fn on_initialize_no_balance(i: u32) -> Weight;
-    fn on_filled_randomness_pending() -> Weight;
-    fn on_filled_randomness_no_pending() -> Weight;
     fn unlink_identity() -> Weight;
 }
 
@@ -43,13 +41,7 @@ impl WeightInfo for () {
     }
 
     // Storage: Account PendingNewAccounts (r:1 w:0)
-    // Storage: ProvideRandomness RequestIdProvider (r:1 w:1)
-    // Storage: ProvideRandomness RequestsIds (r:1 w:1)
-    // Storage: ProvideRandomness CounterForRequestsIds (r:1 w:1)
     // Storage: Babe EpochIndex (r:1 w:0)
-    // Storage: ProvideRandomness NexEpochHookIn (r:1 w:0)
-    // Storage: ProvideRandomness RequestsReadyAtEpoch (r:1 w:1)
-    // Storage: Account PendingRandomIdAssignments (r:0 w:1)
     /// The range of component `i` is `[0, 1]`.
     fn on_initialize_sufficient(i: u32) -> Weight {
         // Minimum execution time: 12_958 nanoseconds.
@@ -62,13 +54,7 @@ impl WeightInfo for () {
     }
 
     // Storage: Account PendingNewAccounts (r:1 w:0)
-    // Storage: ProvideRandomness RequestIdProvider (r:1 w:1)
-    // Storage: ProvideRandomness RequestsIds (r:1 w:1)
-    // Storage: ProvideRandomness CounterForRequestsIds (r:1 w:1)
     // Storage: Babe EpochIndex (r:1 w:0)
-    // Storage: ProvideRandomness NexEpochHookIn (r:1 w:0)
-    // Storage: ProvideRandomness RequestsReadyAtEpoch (r:1 w:1)
-    // Storage: Account PendingRandomIdAssignments (r:0 w:1)
     /// The range of component `i` is `[0, 1]`.
     fn on_initialize_with_balance(i: u32) -> Weight {
         // Minimum execution time: 12_965 nanoseconds.
@@ -90,19 +76,4 @@ impl WeightInfo for () {
             .saturating_add(RocksDbWeight::get().reads(1 as u64))
             .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(i as u64)))
     }
-
-    // Storage: Account PendingRandomIdAssignments (r:1 w:1)
-    fn on_filled_randomness_pending() -> Weight {
-        // Minimum execution time: 66_963 nanoseconds.
-        Weight::from_parts(69_757_000 as u64, 0)
-            .saturating_add(RocksDbWeight::get().reads(1 as u64))
-            .saturating_add(RocksDbWeight::get().writes(1 as u64))
-    }
-
-    // Storage: Account PendingRandomIdAssignments (r:1 w:0)
-    fn on_filled_randomness_no_pending() -> Weight {
-        // Minimum execution time: 16_088 nanoseconds.
-        Weight::from_parts(27_963_000 as u64, 0)
-            .saturating_add(RocksDbWeight::get().reads(1 as u64))
-    }
 }
diff --git a/resources/metadata.scale b/resources/metadata.scale
index f963c977883e0d240b34d87f1b77b461ffcdee71..26b30e4664d0ced1c6e5a8bb586ccfd1ace71403 100644
GIT binary patch
delta 11514
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

delta 11613
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

diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index d1893985c..a2262503e 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -108,6 +108,7 @@ type RuntimeTask = ();
             // does currency adapter in any case, but adds "refund with quota" feature
             type InnerOnChargeTransaction = CurrencyAdapter<Balances, HandleFees>;
             type Refund = Quota;
+            type OnUnbalanced = Treasury;
         }
 
         // QUOTA //
@@ -347,7 +348,7 @@ type RuntimeFreezeReason = ();
             type GetCurrentEpochIndex = GetCurrentEpochIndex<Self>;
             type MaxRequests = frame_support::traits::ConstU32<100>;
             type RequestPrice = frame_support::traits::ConstU64<2_000>;
-            type OnFilledRandomness = Account;
+            type OnFilledRandomness = ();
             type OnUnbalanced = Treasury;
             type ParentBlockRandomness = pallet_babe::ParentBlockRandomness<Self>;
             type RandomnessFromOneEpochAgo = pallet_babe::RandomnessFromOneEpochAgo<Self>;
diff --git a/runtime/common/src/weights/pallet_duniter_account.rs b/runtime/common/src/weights/pallet_duniter_account.rs
index 797603e66..3dcee20a0 100644
--- a/runtime/common/src/weights/pallet_duniter_account.rs
+++ b/runtime/common/src/weights/pallet_duniter_account.rs
@@ -61,20 +61,8 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 	}
 	/// Storage: `Account::PendingNewAccounts` (r:1 w:1)
 	/// Proof: `Account::PendingNewAccounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::RequestIdProvider` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestIdProvider` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::RequestsIds` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestsIds` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::CounterForRequestsIds` (r:1 w:1)
-	/// Proof: `ProvideRandomness::CounterForRequestsIds` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Babe::EpochIndex` (r:1 w:0)
 	/// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
-	/// Storage: `ProvideRandomness::NexEpochHookIn` (r:1 w:0)
-	/// Proof: `ProvideRandomness::NexEpochHookIn` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::RequestsReadyAtEpoch` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestsReadyAtEpoch` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Account::PendingRandomIdAssignments` (r:0 w:1)
-	/// Proof: `Account::PendingRandomIdAssignments` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// The range of component `i` is `[0, 1]`.
 	fn on_initialize_sufficient(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
@@ -94,20 +82,8 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 	/// Proof: `Account::PendingNewAccounts` (`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: `ProvideRandomness::RequestIdProvider` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestIdProvider` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::RequestsIds` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestsIds` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::CounterForRequestsIds` (r:1 w:1)
-	/// Proof: `ProvideRandomness::CounterForRequestsIds` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
 	/// Storage: `Babe::EpochIndex` (r:1 w:0)
 	/// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
-	/// Storage: `ProvideRandomness::NexEpochHookIn` (r:1 w:0)
-	/// Proof: `ProvideRandomness::NexEpochHookIn` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
-	/// Storage: `ProvideRandomness::RequestsReadyAtEpoch` (r:1 w:1)
-	/// Proof: `ProvideRandomness::RequestsReadyAtEpoch` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `Account::PendingRandomIdAssignments` (r:0 w:1)
-	/// Proof: `Account::PendingRandomIdAssignments` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// The range of component `i` is `[0, 1]`.
 	fn on_initialize_with_balance(i: u32, ) -> Weight {
 		// Proof Size summary in bytes:
@@ -139,27 +115,4 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 			.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
 			.saturating_add(Weight::from_parts(0, 74).saturating_mul(i.into()))
 	}
-	/// Storage: `Account::PendingRandomIdAssignments` (r:1 w:1)
-	/// Proof: `Account::PendingRandomIdAssignments` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	fn on_filled_randomness_pending() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `116`
-		//  Estimated: `3581`
-		// Minimum execution time: 20_089_000 picoseconds.
-		Weight::from_parts(21_261_000, 0)
-			.saturating_add(Weight::from_parts(0, 3581))
-			.saturating_add(T::DbWeight::get().reads(1))
-			.saturating_add(T::DbWeight::get().writes(1))
-	}
-	/// Storage: `Account::PendingRandomIdAssignments` (r:1 w:0)
-	/// Proof: `Account::PendingRandomIdAssignments` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	fn on_filled_randomness_no_pending() -> Weight {
-		// Proof Size summary in bytes:
-		//  Measured:  `42`
-		//  Estimated: `3507`
-		// Minimum execution time: 4_511_000 picoseconds.
-		Weight::from_parts(4_829_000, 0)
-			.saturating_add(Weight::from_parts(0, 3507))
-			.saturating_add(T::DbWeight::get().reads(1))
-	}
 }
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index 249653ec2..95933e525 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -73,7 +73,6 @@ impl ExtBuilder {
                     get_account_id_from_seed::<sr25519::Public>(NAMES[i]),
                     GenesisAccountData {
                         balance: 0,
-                        random_id: H256([i as u8; 32]),
                         idty_id: Some(i as u32 + 1),
                     },
                 )
@@ -123,7 +122,6 @@ impl ExtBuilder {
             self.initial_accounts
                 .entry(account_id.clone())
                 .or_insert(GenesisAccountData {
-                    random_id: H256(account_id.into()),
                     ..Default::default()
                 })
                 .balance = balance;
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index 4624094d4..bd6332369 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -1056,42 +1056,25 @@ fn test_create_new_account() {
             // 100 initial + 300 deposit
             assert_eq!(Balances::free_balance(Treasury::account_id()), 400);
 
-            // A random id request should be registered
-            assert_eq!(
-                Account::pending_random_id_assignments(0),
-                Some(AccountKeyring::Eve.to_account_id())
-            );
-
-            // We can't remove the account until the random id is assigned
             run_to_block(4);
-            // can not remove using transfer
-            assert_noop!(
-                Balances::transfer_allow_death(
-                    frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
-                    MultiAddress::Id(AccountKeyring::Alice.to_account_id()),
-                    200
-                ),
-                sp_runtime::DispatchError::ConsumerRemaining,
-            );
+            // can remove an account using transfer
+            assert_ok!(Balances::transfer_allow_death(
+                frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
+                MultiAddress::Id(AccountKeyring::Alice.to_account_id()),
+                200
+            ));
+            // Account reaped
             assert_eq!(
                 Balances::free_balance(AccountKeyring::Eve.to_account_id()),
-                200
-            );
-            // can not remove using transfer_all either
-            assert_noop!(
-                Balances::transfer_all(
-                    frame_system::RawOrigin::Signed(AccountKeyring::Eve.to_account_id()).into(),
-                    MultiAddress::Id(AccountKeyring::Alice.to_account_id()),
-                    false
-                ),
-                sp_runtime::DispatchError::ConsumerRemaining,
+                0
             );
-            // Transfer failed, so free_balance remains the same
             assert_eq!(
-                Balances::free_balance(AccountKeyring::Eve.to_account_id()),
-                200
+                frame_system::Pallet::<Runtime>::get(&AccountKeyring::Eve.to_account_id()),
+                pallet_duniter_account::AccountData::default()
             );
-            // TODO detail account removal
+            System::assert_has_event(RuntimeEvent::System(frame_system::Event::KilledAccount {
+                account: AccountKeyring::Eve.to_account_id(),
+            }));
         });
 }
 
@@ -1118,12 +1101,6 @@ fn test_create_new_idty() {
             run_to_block(3);
             let events = System::events();
             assert_eq!(events.len(), 0);
-
-            // A random id request should be registered
-            assert_eq!(
-                Account::pending_random_id_assignments(0),
-                Some(AccountKeyring::Eve.to_account_id())
-            );
         });
 }
 
@@ -1156,25 +1133,19 @@ fn test_create_new_idty_without_founds() {
             let events = System::events();
             assert_eq!(events.len(), 0);
 
-            // Deposit some founds on the identity account,
-            // this should trigger the random id assignemt
+            // Deposit some founds on the identity account
             assert_ok!(Balances::transfer_allow_death(
                 frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
                 MultiAddress::Id(AccountKeyring::Eve.to_account_id()),
                 200
             ));
 
-            // At next block, nothing should be preleved,
-            // and a random id request should be registered
+            // At next block, nothing should be preleved
             run_to_block(4);
             assert_eq!(
                 Balances::free_balance(AccountKeyring::Eve.to_account_id()),
                 200
             );
-            assert_eq!(
-                Account::pending_random_id_assignments(0),
-                Some(AccountKeyring::Eve.to_account_id())
-            );
         });
 }
 
-- 
GitLab