From 168228a51a33414e6db24bb3e9ca763afeafd7d7 Mon Sep 17 00:00:00 2001 From: librelois <c@elo.tf> Date: Sun, 20 Feb 2022 02:34:38 +0100 Subject: [PATCH] feat(runtimes): add account random id & provide randomness calls --- Cargo.lock | 42 ++++ node/src/chain_spec/gdev.rs | 16 +- node/src/chain_spec/gen_genesis_data.rs | 9 +- pallets/authority-members/src/lib.rs | 8 +- pallets/authority-members/src/mock.rs | 1 + pallets/authority-members/src/traits.rs | 11 + pallets/duniter-account/Cargo.toml | 104 +++++++++ pallets/duniter-account/src/lib.rs | 253 +++++++++++++++++++++ pallets/duniter-account/src/types.rs | 48 ++++ pallets/duniter-wot/src/lib.rs | 8 +- pallets/duniter-wot/src/mock.rs | 87 ++++--- pallets/duniter-wot/src/tests.rs | 22 +- pallets/identity/src/lib.rs | 8 +- pallets/identity/src/mock.rs | 23 +- pallets/identity/src/tests.rs | 12 +- pallets/identity/src/types.rs | 2 +- pallets/provide-randomness/Cargo.toml | 75 ++++++ pallets/provide-randomness/src/lib.rs | 290 ++++++++++++++++++++++++ pallets/provide-randomness/src/types.rs | 36 +++ resources/metadata.scale | Bin 99619 -> 112264 bytes runtime/common/Cargo.toml | 4 + runtime/common/src/handlers.rs | 27 +-- runtime/common/src/pallets_config.rs | 27 ++- runtime/g1/Cargo.toml | 7 +- runtime/g1/src/lib.rs | 19 +- runtime/gdev/Cargo.toml | 4 + runtime/gdev/src/lib.rs | 18 +- runtime/gdev/tests/integration_tests.rs | 4 +- runtime/gtest/Cargo.toml | 7 +- runtime/gtest/src/lib.rs | 16 +- 30 files changed, 1057 insertions(+), 131 deletions(-) create mode 100644 pallets/duniter-account/Cargo.toml create mode 100644 pallets/duniter-account/src/lib.rs create mode 100644 pallets/duniter-account/src/types.rs create mode 100644 pallets/provide-randomness/Cargo.toml create mode 100644 pallets/provide-randomness/src/lib.rs create mode 100644 pallets/provide-randomness/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index ce9d5ea77..ef4a5bba7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -833,9 +833,11 @@ dependencies = [ "pallet-authority-members", "pallet-balances", "pallet-certification", + "pallet-duniter-account", "pallet-duniter-wot", "pallet-identity", "pallet-membership", + "pallet-provide-randomness", "pallet-session", "pallet-ud-accounts-storage", "parity-scale-codec", @@ -1953,6 +1955,7 @@ dependencies = [ "pallet-balances", "pallet-certification", "pallet-collective", + "pallet-duniter-account", "pallet-duniter-wot", "pallet-grandpa", "pallet-identity", @@ -1960,6 +1963,7 @@ dependencies = [ "pallet-membership", "pallet-multisig", "pallet-offences", + "pallet-provide-randomness", "pallet-proxy", "pallet-scheduler", "pallet-session", @@ -2011,6 +2015,7 @@ dependencies = [ "pallet-balances", "pallet-certification", "pallet-collective", + "pallet-duniter-account", "pallet-duniter-test-parameters", "pallet-duniter-wot", "pallet-grandpa", @@ -2019,6 +2024,7 @@ dependencies = [ "pallet-membership", "pallet-multisig", "pallet-offences", + "pallet-provide-randomness", "pallet-proxy", "pallet-scheduler", "pallet-session", @@ -2212,6 +2218,7 @@ dependencies = [ "pallet-balances", "pallet-certification", "pallet-collective", + "pallet-duniter-account", "pallet-duniter-wot", "pallet-grandpa", "pallet-identity", @@ -2219,6 +2226,7 @@ dependencies = [ "pallet-membership", "pallet-multisig", "pallet-offences", + "pallet-provide-randomness", "pallet-proxy", "pallet-scheduler", "pallet-session", @@ -4418,6 +4426,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-duniter-account" +version = "3.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "maplit", + "pallet-balances", + "pallet-provide-randomness", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-duniter-test-parameters" version = "3.0.0" @@ -4571,6 +4598,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-provide-randomness" +version = "3.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-proxy" version = "4.0.0-dev" diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs index c85139721..2e0e830ce 100644 --- a/node/src/chain_spec/gdev.rs +++ b/node/src/chain_spec/gdev.rs @@ -18,10 +18,10 @@ use super::*; use common_runtime::constants::*; use common_runtime::*; use gdev_runtime::{ - opaque::SessionKeys, AccountId, AuthorityMembersConfig, BabeConfig, BalancesConfig, CertConfig, - GenesisConfig, IdentityConfig, ImOnlineId, MembershipConfig, ParametersConfig, SessionConfig, - SmithsCertConfig, SmithsMembershipConfig, SudoConfig, SystemConfig, UdAccountsStorageConfig, - UniversalDividendConfig, WASM_BINARY, + opaque::SessionKeys, AccountConfig, AccountId, AuthorityMembersConfig, BabeConfig, + BalancesConfig, CertConfig, GenesisConfig, IdentityConfig, ImOnlineId, MembershipConfig, + ParametersConfig, SessionConfig, SmithsCertConfig, SmithsMembershipConfig, SudoConfig, + SystemConfig, UdAccountsStorageConfig, UniversalDividendConfig, WASM_BINARY, }; use sc_service::ChainType; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; @@ -239,6 +239,12 @@ fn gen_genesis_conf( // Add Wasm runtime to storage. code: wasm_binary.to_vec(), }, + account: AccountConfig { + accounts: initial_identities + .iter() + .map(|(_, owner_key)| owner_key.clone()) + .collect(), + }, parameters: ParametersConfig { parameters: GenesisParameters { babe_epoch_duration, @@ -396,6 +402,7 @@ fn genesis_data_to_gdev_genesis_conf( wasm_binary: &[u8], ) -> gdev_runtime::GenesisConfig { let super::gen_genesis_data::GenesisData { + accounts, balances, certs_by_issuer, first_ud, @@ -416,6 +423,7 @@ fn genesis_data_to_gdev_genesis_conf( // Add Wasm runtime to storage. code: wasm_binary.to_vec(), }, + account: AccountConfig { accounts }, parameters: ParametersConfig { parameters }, authority_discovery: Default::default(), authority_members: AuthorityMembersConfig { diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs index 62d63d952..1176adc1e 100644 --- a/node/src/chain_spec/gen_genesis_data.rs +++ b/node/src/chain_spec/gen_genesis_data.rs @@ -17,12 +17,13 @@ use common_runtime::*; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_core::Decode; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; type MembershipData = sp_membership::MembershipData<u32>; #[derive(Clone)] pub struct GenesisData<Parameters: DeserializeOwned, SessionKeys: Decode> { + pub accounts: BTreeSet<AccountId>, pub balances: Vec<(AccountId, u64)>, pub certs_by_issuer: BTreeMap<u32, BTreeMap<u32, u32>>, pub first_ud: u64, @@ -137,6 +138,7 @@ where // MONEY AND WOT // + let mut accounts = BTreeSet::new(); let mut balances = Vec::new(); let mut identities_ = Vec::with_capacity(identities.len()); let mut idty_index: u32 = 1; @@ -152,6 +154,10 @@ where // Money if identity.balance >= 100 { balances.push((identity.pubkey.clone(), identity.balance)); + } else { + // If an identity has no currency in genesis, its account will not be created, + // so it must be created explicitly + accounts.insert(identity.pubkey.clone()); } // We must count the money under the existential deposit because what we count is // the monetary mass created (for the revaluation of the DU) @@ -241,6 +247,7 @@ where } let genesis_data = GenesisData { + accounts, balances, certs_by_issuer, first_ud, diff --git a/pallets/authority-members/src/lib.rs b/pallets/authority-members/src/lib.rs index cb0d6dbbb..f4e5707bc 100644 --- a/pallets/authority-members/src/lib.rs +++ b/pallets/authority-members/src/lib.rs @@ -32,6 +32,7 @@ mod benchmarking;*/ pub use pallet::*; pub use types::*; +use self::traits::*; use frame_support::traits::Get; use sp_runtime::traits::Convert; use sp_staking::SessionIndex; @@ -40,7 +41,6 @@ use sp_std::prelude::*; #[frame_support::pallet] pub mod pallet { use super::*; - use crate::traits::OnRemovedMember; use frame_support::pallet_prelude::*; use frame_support::traits::ValidatorRegistration; use frame_support::traits::{StorageVersion, UnfilteredDispatchable}; @@ -66,6 +66,7 @@ pub mod pallet { type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; type KeysWrapper: Parameter + Into<Self::Keys>; type IsMember: IsMember<Self::MemberId>; + type OnNewSession: OnNewSession; type OnRemovedMember: OnRemovedMember<Self::MemberId>; /// Max number of authorities allowed #[pallet::constant] @@ -335,10 +336,6 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::RemoveMemberOrigin::ensure_origin(origin)?; - if !T::IsMember::is_member(&member_id) { - return Err(Error::<T>::NotMember.into()); - } - let member_data = Members::<T>::get(member_id).ok_or(Error::<T>::NotMember)?; Self::do_remove_member(member_id, member_data.owner_key); @@ -572,6 +569,7 @@ impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> { /// The session start to be used for validation. fn start_session(start_index: SessionIndex) { Self::expire_memberships(start_index); + T::OnNewSession::on_new_session(start_index); } } diff --git a/pallets/authority-members/src/mock.rs b/pallets/authority-members/src/mock.rs index 6f499362f..0d1ae96c8 100644 --- a/pallets/authority-members/src/mock.rs +++ b/pallets/authority-members/src/mock.rs @@ -156,6 +156,7 @@ impl pallet_authority_members::Config for Test { type MaxOfflineSessions = ConstU32<2>; type MemberId = u64; type MemberIdOf = ConvertInto; + type OnNewSession = (); type OnRemovedMember = (); type RemoveMemberOrigin = system::EnsureRoot<u64>; } diff --git a/pallets/authority-members/src/traits.rs b/pallets/authority-members/src/traits.rs index 1d6b05555..1cfb55dcf 100644 --- a/pallets/authority-members/src/traits.rs +++ b/pallets/authority-members/src/traits.rs @@ -14,8 +14,19 @@ // 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/>. +use super::SessionIndex; use frame_support::pallet_prelude::Weight; +pub trait OnNewSession { + fn on_new_session(index: SessionIndex) -> Weight; +} + +impl OnNewSession for () { + fn on_new_session(_: SessionIndex) -> Weight { + 0 + } +} + pub trait OnRemovedMember<MemberId> { fn on_removed_member(member_id: MemberId) -> Weight; } diff --git a/pallets/duniter-account/Cargo.toml b/pallets/duniter-account/Cargo.toml new file mode 100644 index 000000000..c4f48360f --- /dev/null +++ b/pallets/duniter-account/Cargo.toml @@ -0,0 +1,104 @@ +[package] +authors = ['librelois <c@elo.tf>'] +description = 'FRAME pallet duniter account.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'AGPL-3.0' +name = 'pallet-duniter-account' +readme = 'README.md' +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', + 'pallet-balances/std', + 'pallet-provide-randomness/std', + 'serde', + 'sp-core/std', + 'sp-io/std', + 'sp-runtime/std', + 'sp-std/std', +] +try-runtime = ['frame-support/try-runtime'] + +[dependencies] +# local +pallet-provide-randomness = { path = "../provide-randomness", default-features = false } + +# crates.io +codec = { package = 'parity-scale-codec', version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +# substrate +[dependencies.frame-benchmarking] +default-features = false +git = 'https://github.com/librelois/substrate.git' +optional = true +branch = 'duniter-monthly-2022-02' + +[dependencies.frame-support] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.frame-system] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.pallet-balances] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.serde] +version = "1.0.101" +optional = true +features = ["derive"] + +[dependencies.sp-core] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-io] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-runtime] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-std] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +### DOC ### + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +### DEV ### + +[dev-dependencies.pallet-balances] +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dev-dependencies.maplit] +version = '1.0.2' + +[dev-dependencies.serde] +version = '1.0.119' + +[dev-dependencies.sp-io] +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' diff --git a/pallets/duniter-account/src/lib.rs b/pallets/duniter-account/src/lib.rs new file mode 100644 index 000000000..85991c6ed --- /dev/null +++ b/pallets/duniter-account/src/lib.rs @@ -0,0 +1,253 @@ +// 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)] + +mod types; + +pub use pallet::*; +pub use types::*; + +use frame_support::pallet_prelude::*; +use frame_support::traits::{OnUnbalanced, StoredMap}; +use frame_system::pallet_prelude::*; +use pallet_provide_randomness::RequestId; +use sp_core::H256; +use sp_runtime::traits::{Convert, Saturating, Zero}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::traits::{Currency, ExistenceRequirement, 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)] + #[pallet::without_storage_info] + pub struct Pallet<T>(_); + + // CONFIG // + + #[pallet::config] + pub trait Config: + frame_system::Config<AccountData = AccountData<Self::Balance>> + + pallet_balances::Config + + pallet_provide_randomness::Config<Currency = pallet_balances::Pallet<Self>> + { + type AccountIdToSalt: Convert<Self::AccountId, [u8; 32]>; + /// The overarching event type. + type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; + type MaxNewAccountsPerBlock: Get<u32>; + type NewAccountPrice: Get<Self::Balance>; + } + + // 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> = + StorageMap<_, Blake2_128Concat, T::AccountId, (), OptionQuery>; + + // GENESIS STUFF // + + #[pallet::genesis_config] + pub struct GenesisConfig<T: Config> { + pub accounts: sp_std::collections::btree_set::BTreeSet<T::AccountId>, + } + + #[cfg(feature = "std")] + impl<T: Config> Default for GenesisConfig<T> { + fn default() -> Self { + Self { + accounts: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl<T: Config> GenesisBuild<T> for GenesisConfig<T> { + fn build(&self) { + for account_id in &self.accounts { + PendingNewAccounts::<T>::insert(account_id.clone(), ()); + } + } + } + + // EVENTS // + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event<T: Config> { + /// Random id assigned + /// [account_id, random_id] + RandomIdAssigned { + account_id: T::AccountId, + random_id: H256, + }, + } + + // HOOKS // + #[pallet::hooks] + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { + fn on_initialize(_: T::BlockNumber) -> Weight { + let mut total_weight = 0; + for account_id in PendingNewAccounts::<T>::iter_keys() + .drain() + .take(T::MaxNewAccountsPerBlock::get() as usize) + { + 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 += 100_000; + } else { + // If the account is not self-sufficient, it must pay the account creation fees + frame_system::Pallet::<T>::inc_providers(&account_id); + let res = T::Currency::withdraw( + &account_id, + T::NewAccountPrice::get(), + frame_support::traits::WithdrawReasons::FEE, + ExistenceRequirement::KeepAlive, + ); + if let Ok(imbalance) = res { + // The fees have been collected, we handle the collected amount and we + // request the random id + 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 += 200_000; + } else { + // The charges could not be deducted, we slash the account + let account_data = frame_system::Pallet::<T>::get(&account_id); + let (imbalance, rest) = pallet_balances::Pallet::<T>::slash( + &account_id, + account_data.free.saturating_add(account_data.reserved), + ); + debug_assert!(rest.is_zero()); + T::OnUnbalanced::on_unbalanced(imbalance); + total_weight += 300_000; + } + } + } + total_weight + } + } +} + +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) { + // Can only fail if the account has been deleted in the meantime, + // but this case does not require any processing + let res = frame_system::Pallet::<T>::mutate_exists(&account_id, |maybe_account_data| { + if let Some(ref mut account_data) = maybe_account_data { + account_data.random_id = Some(randomness); + } + }); + if res.is_ok() { + Self::deposit_event(Event::RandomIdAssigned { + account_id, + random_id: randomness, + }); + } + 200_000 + } else { + 100_000 + } + } +} + +impl<T, AccountId, Balance> + frame_support::traits::StoredMap<AccountId, pallet_balances::AccountData<Balance>> for Pallet<T> +where + AccountId: Parameter + + Member + + MaybeSerializeDeserialize + + core::fmt::Debug + + sp_runtime::traits::MaybeDisplay + + Ord + + Into<[u8; 32]> + + codec::MaxEncodedLen, + Balance: Parameter + + Member + + sp_runtime::traits::AtLeast32BitUnsigned + + codec::Codec + + Default + + Copy + + MaybeSerializeDeserialize + + core::fmt::Debug + + codec::MaxEncodedLen + + scale_info::TypeInfo, + T: Config + + frame_system::Config<AccountId = AccountId, AccountData = AccountData<Balance>> + + pallet_balances::Config<Balance = Balance> + + pallet_provide_randomness::Config, +{ + fn get(k: &AccountId) -> pallet_balances::AccountData<Balance> { + frame_system::Account::<T>::get(k).data.into() + } + + fn try_mutate_exists<R, E: From<sp_runtime::DispatchError>>( + account_id: &AccountId, + f: impl FnOnce(&mut Option<pallet_balances::AccountData<Balance>>) -> Result<R, E>, + ) -> Result<R, E> { + let account = frame_system::Account::<T>::get(account_id); + let was_providing = account.data != Default::default(); + let mut some_data = if was_providing { + Some(account.data.into()) + } else { + None + }; + let result = f(&mut some_data)?; + let is_providing = some_data.is_some(); + if !was_providing && is_providing { + // If the account does not exist, we should program its creation + if !frame_system::Pallet::<T>::account_exists(account_id) { + PendingNewAccounts::<T>::insert(account_id, ()); + } + } else if was_providing && !is_providing { + match frame_system::Pallet::<T>::dec_providers(account_id)? { + frame_system::DecRefStatus::Reaped => return Ok(result), + frame_system::DecRefStatus::Exists => { + // Update value as normal... + } + } + } else if !was_providing && !is_providing { + return Ok(result); + } + frame_system::Account::<T>::mutate(account_id, |a| { + a.data.set_balances(some_data.unwrap_or_default()) + }); + Ok(result) + } +} diff --git a/pallets/duniter-account/src/types.rs b/pallets/duniter-account/src/types.rs new file mode 100644 index 000000000..92d5494db --- /dev/null +++ b/pallets/duniter-account/src/types.rs @@ -0,0 +1,48 @@ +// 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/>. + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::pallet_prelude::*; +use scale_info::TypeInfo; +use sp_core::H256; +use sp_runtime::traits::Zero; + +#[derive(Clone, Decode, Default, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct AccountData<Balance> { + pub(super) random_id: Option<H256>, + pub(super) free: Balance, + pub(super) reserved: Balance, + fee_frozen: Balance, +} + +impl<Balance: Zero> AccountData<Balance> { + pub fn set_balances(&mut self, new_balances: pallet_balances::AccountData<Balance>) { + self.free = new_balances.free; + self.reserved = new_balances.reserved; + self.fee_frozen = new_balances.fee_frozen; + } +} + +impl<Balance: Zero> From<AccountData<Balance>> for pallet_balances::AccountData<Balance> { + fn from(account_data: AccountData<Balance>) -> Self { + Self { + free: account_data.free, + reserved: account_data.reserved, + misc_frozen: Zero::zero(), + fee_frozen: account_data.fee_frozen, + } + } +} diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs index 161ce0b5e..90689c4c4 100644 --- a/pallets/duniter-wot/src/lib.rs +++ b/pallets/duniter-wot/src/lib.rs @@ -115,7 +115,7 @@ pub mod pallet { if !T::IsSubWot::get() { if let Err(e) = idty_call.dispatch_bypass_filter(RawOrigin::Root.into()) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to dispatch idty call: {:?}", e) } return false; } @@ -269,7 +269,7 @@ impl<T: Config<I>, I: 'static> pallet_identity::traits::OnIdtyChange<T> for Pall true, ) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to force add cert: {:?}", e) } } } @@ -304,7 +304,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnNewcert<IdtyIndex Some(receiver), ) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to claim membership: {:?}", e) } } } else { @@ -344,7 +344,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::OnRemovedCert<IdtyI Some(receiver), ) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to revoke membership: {:?}", e) } } } diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs index da821daa4..123dbf7de 100644 --- a/pallets/duniter-wot/src/mock.rs +++ b/pallets/duniter-wot/src/mock.rs @@ -22,7 +22,6 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, }; use std::collections::BTreeMap; @@ -45,7 +44,7 @@ frame_support::construct_runtime!( } ); -// Sstem +// System parameter_types! { pub const BlockHashCount: u64 = 250; pub const SS58Prefix: u8 = 42; @@ -170,43 +169,57 @@ 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) -> sp_io::TestExternalities { - GenesisConfig { - system: SystemConfig::default(), - identity: IdentityConfig { - identities: (1..=initial_identities_len) - .map(|i| pallet_identity::GenesisIdty { - index: i as u32, - name: pallet_identity::IdtyName::from(NAMES[i - 1]), - value: pallet_identity::IdtyValue { - next_creatable_identity_on: 0, - owner_key: i as u64, - removable_on: 0, - status: pallet_identity::IdtyStatus::Validated, + let mut t = frame_system::GenesisConfig::default() + .build_storage::<Test>() + .unwrap(); + + pallet_identity::GenesisConfig::<Test> { + identities: (1..=initial_identities_len) + .map(|i| pallet_identity::GenesisIdty { + index: i as u32, + name: pallet_identity::IdtyName::from(NAMES[i - 1]), + value: pallet_identity::IdtyValue { + next_creatable_identity_on: 0, + owner_key: i as u64, + removable_on: 0, + status: pallet_identity::IdtyStatus::Validated, + }, + }) + .collect(), + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_membership::GenesisConfig::<Test, Instance1> { + memberships: (1..=initial_identities_len) + .map(|i| { + ( + i as u32, + sp_membership::MembershipData { + expire_on: MembershipPeriod::get(), + renewable_on: RenewablePeriod::get(), }, - }) - .collect(), - }, - membership: MembershipConfig { - memberships: (1..=initial_identities_len) - .map(|i| { - ( - i as u32, - sp_membership::MembershipData { - expire_on: MembershipPeriod::get(), - renewable_on: RenewablePeriod::get(), - }, - ) - }) - .collect(), - }, - cert: CertConfig { - certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()), - apply_cert_period_at_genesis: true, - }, + ) + }) + .collect(), + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_certification::GenesisConfig::<Test, Instance1> { + certs_by_issuer: clique_wot(initial_identities_len, ValidityPeriod::get()), + apply_cert_period_at_genesis: true, } - .build_storage() - .unwrap() - .into() + .assimilate_storage(&mut t) + .unwrap(); + + frame_support::BasicExternalities::execute_with_storage(&mut t, || { + // Some dedicated test account + frame_system::Pallet::<Test>::inc_providers(&(initial_identities_len as u64)); + frame_system::Pallet::<Test>::inc_providers(&(initial_identities_len as u64 + 1)); + }); + + sp_io::TestExternalities::new(t) } pub fn run_to_block(n: u64) { diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs index e9f6f4c63..42f255fa8 100644 --- a/pallets/duniter-wot/src/tests.rs +++ b/pallets/duniter-wot/src/tests.rs @@ -60,17 +60,9 @@ fn test_create_idty_ok() { assert_ok!(Identity::create_identity(Origin::signed(1), 6)); // 2 events should have occurred: IdtyCreated and NewCert let events = System::events(); - assert_eq!(events.len(), 3); + assert_eq!(events.len(), 2); assert_eq!( events[0], - EventRecord { - phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: 6 }), - topics: vec![], - } - ); - assert_eq!( - events[1], EventRecord { phase: Phase::Initialization, event: Event::Identity(pallet_identity::Event::IdtyCreated { @@ -81,7 +73,7 @@ fn test_create_idty_ok() { } ); assert_eq!( - events[2], + events[1], EventRecord { phase: Phase::Initialization, event: Event::Cert(pallet_certification::Event::NewCert { @@ -222,7 +214,7 @@ fn test_idty_membership_expire_them_requested() { run_to_block(5); assert!(Membership::membership(3).is_none()); let events = System::events(); - assert_eq!(events.len(), 3); + assert_eq!(events.len(), 2); assert_eq!( events[0], EventRecord { @@ -233,14 +225,6 @@ fn test_idty_membership_expire_them_requested() { ); assert_eq!( events[1], - EventRecord { - phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { account: 3 }), - topics: vec![], - } - ); - assert_eq!( - events[2], EventRecord { phase: Phase::Initialization, event: Event::Identity(pallet_identity::Event::IdtyRemoved { idty_index: 3 }), diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs index 76d59fd84..00f0ed190 100644 --- a/pallets/identity/src/lib.rs +++ b/pallets/identity/src/lib.rs @@ -144,7 +144,6 @@ 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(), ()); @@ -244,6 +243,11 @@ pub mod pallet { let creator_idty_val = Identities::<T>::try_get(&creator).map_err(|_| Error::<T>::IdtyNotFound)?; + ensure!( + frame_system::Pallet::<T>::account_exists(&owner_key), + Error::<T>::OwnerAccountNotExist + ); + if IdentityIndexOf::<T>::contains_key(&owner_key) { return Err(Error::<T>::IdtyAlreadyCreated.into()); } @@ -453,6 +457,8 @@ pub mod pallet { RightNotExist, /// Not respect IdtyCreationPeriod NotRespectIdtyCreationPeriod, + /// Owner account not exist + OwnerAccountNotExist, } // PUBLIC FUNCTIONS // diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs index 3d5103e1d..7a19d32d3 100644 --- a/pallets/identity/src/mock.rs +++ b/pallets/identity/src/mock.rs @@ -18,14 +18,13 @@ use super::*; use crate::{self as pallet_identity}; use frame_support::{ parameter_types, - traits::{Everything, OnFinalize, OnInitialize}, + traits::{Everything, GenesisBuild, OnFinalize, OnInitialize}, }; use frame_system as system; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup, IsMember}, - BuildStorage, }; type AccountId = u64; @@ -115,13 +114,19 @@ impl pallet_identity::Config for Test { // Build genesis storage according to the mock runtime. pub fn new_test_ext(gen_conf: pallet_identity::GenesisConfig<Test>) -> sp_io::TestExternalities { - GenesisConfig { - system: SystemConfig::default(), - identity: gen_conf, - } - .build_storage() - .unwrap() - .into() + let mut t = frame_system::GenesisConfig::default() + .build_storage::<Test>() + .unwrap(); + + gen_conf.assimilate_storage(&mut t).unwrap(); + + frame_support::BasicExternalities::execute_with_storage(&mut t, || { + // Some dedicated test account + frame_system::Pallet::<Test>::inc_providers(&2); + frame_system::Pallet::<Test>::inc_providers(&3); + }); + + sp_io::TestExternalities::new(t) } pub fn run_to_block(n: u64) { diff --git a/pallets/identity/src/tests.rs b/pallets/identity/src/tests.rs index 462c437ae..885b1cd00 100644 --- a/pallets/identity/src/tests.rs +++ b/pallets/identity/src/tests.rs @@ -57,9 +57,9 @@ fn test_create_identity_ok() { // Alice should be able te create an identity assert_ok!(Identity::create_identity(Origin::signed(1), 2)); let events = System::events(); - assert_eq!(events.len(), 2); + assert_eq!(events.len(), 1); assert_eq!( - events[1], + events[0], EventRecord { phase: Phase::Initialization, event: Event::Identity(crate::Event::IdtyCreated { @@ -84,9 +84,9 @@ fn test_idty_creation_period() { // Alice should be able te create an identity assert_ok!(Identity::create_identity(Origin::signed(1), 2)); let events = System::events(); - assert_eq!(events.len(), 2); + assert_eq!(events.len(), 1); assert_eq!( - events[1], + events[0], EventRecord { phase: Phase::Initialization, event: Event::Identity(crate::Event::IdtyCreated { @@ -109,9 +109,9 @@ fn test_idty_creation_period() { run_to_block(4); assert_ok!(Identity::create_identity(Origin::signed(1), 3)); let events = System::events(); - assert_eq!(events.len(), 2); + assert_eq!(events.len(), 1); assert_eq!( - events[1], + events[0], EventRecord { phase: Phase::Initialization, event: Event::Identity(crate::Event::IdtyCreated { diff --git a/pallets/identity/src/types.rs b/pallets/identity/src/types.rs index 629a81ce6..d6991ce60 100644 --- a/pallets/identity/src/types.rs +++ b/pallets/identity/src/types.rs @@ -14,7 +14,7 @@ // 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/>. -//! Various basic types for use in the certification pallet. +//! Various basic types for use in the identity pallet. use codec::{Decode, Encode}; use frame_support::pallet_prelude::*; diff --git a/pallets/provide-randomness/Cargo.toml b/pallets/provide-randomness/Cargo.toml new file mode 100644 index 000000000..f7d8a9f84 --- /dev/null +++ b/pallets/provide-randomness/Cargo.toml @@ -0,0 +1,75 @@ +[package] +authors = ['librelois <c@elo.tf>'] +description = 'FRAME pallet to provide randomness to users.' +edition = '2018' +homepage = 'https://substrate.dev' +license = 'AGPL-3.0' +name = 'pallet-provide-randomness' +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', + "sp-core/std", + "sp-io/std", + "sp-std/std", +] +try-runtime = ['frame-support/try-runtime'] + +[dependencies] + +# 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-02' + +[dependencies.frame-support] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.frame-system] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-core] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-io] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-std] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +[dependencies.sp-runtime] +default-features = false +git = 'https://github.com/librelois/substrate.git' +branch = 'duniter-monthly-2022-02' + +### DOC ### + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] diff --git a/pallets/provide-randomness/src/lib.rs b/pallets/provide-randomness/src/lib.rs new file mode 100644 index 000000000..109076970 --- /dev/null +++ b/pallets/provide-randomness/src/lib.rs @@ -0,0 +1,290 @@ +// 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)] +#![allow(clippy::boxed_local)] + +mod types; + +use frame_support::pallet_prelude::Weight; +use sp_core::H256; +use sp_std::prelude::*; + +pub use pallet::*; +pub use types::*; + +pub type RequestId = u64; + +pub trait OnFilledRandomness { + fn on_filled_randomness(request_id: RequestId, randomness: H256) -> Weight; +} +impl OnFilledRandomness for () { + fn on_filled_randomness(_: RequestId, _: H256) -> Weight { + 0 + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_support::traits::{ + Currency, ExistenceRequirement, OnUnbalanced, Randomness, StorageVersion, WithdrawReasons, + }; + use frame_system::pallet_prelude::*; + use sp_core::H256; + + pub type BalanceOf<T> = + <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance; + pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency< + <T as frame_system::Config>::AccountId, + >>::NegativeImbalance; + + /// 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)] + #[pallet::without_storage_info] + pub struct Pallet<T>(_); + + /// Configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config<Hash = H256> { + // The currency + type Currency: Currency<Self::AccountId>; + /// The overarching event type. + type Event: From<Event> + IsType<<Self as frame_system::Config>::Event>; + /// Maximum number of not yet filled requests + #[pallet::constant] + type MaxRequests: Get<u32>; + /// The price of a request + #[pallet::constant] + type RequestPrice: Get<BalanceOf<Self>>; + /// On filled randomness + type OnFilledRandomness: OnFilledRandomness; + /// Handler for the unbalanced reduction when the requestor pays fees. + type OnUnbalanced: OnUnbalanced<NegativeImbalanceOf<Self>>; + /// A safe source of randomness from the current block + type CurrentBlockRandomness: Randomness<Option<H256>, Self::BlockNumber>; + /// A safe source of randomness from one epoch ago + type RandomnessFromOneEpochAgo: Randomness<H256, Self::BlockNumber>; + } + + // STORAGE // + + #[pallet::storage] + pub(super) type NewEpoch<T: Config> = StorageValue<_, bool, ValueQuery>; + + #[pallet::storage] + pub(super) type RequestIdProvider<T: Config> = StorageValue<_, RequestId, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn requests_ready_at_next_block)] + pub type RequestsReadyAtNextBlock<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn requests_ready_at_next_epoch)] + pub type RequestsReadyAtNextEpoch<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn requests_ready_in_two_epochs)] + pub type RequestsReadyInTwoEpochs<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn requests_ready_in_three_epochs)] + pub type RequestsReadyInThreeEpochs<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn pending_requests)] + pub type PendingRequests<T: Config> = StorageValue<_, Vec<Request>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn requests_ids)] + pub type RequestsIds<T: Config> = + CountedStorageMap<_, Twox64Concat, RequestId, (), OptionQuery>; + + // EVENTS // + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Filled randomness + FilledRandomness { + request_id: RequestId, + randomness: H256, + }, + /// Requested randomness + RequestedRandomness { + request_id: RequestId, + salt: H256, + r#type: RandomnessType, + }, + } + + // ERRORS // + + #[pallet::error] + pub enum Error<T> { + /// The queue is full, pleasy retry later + FullQueue, + } + + // CALLS // + + #[pallet::call] + impl<T: Config> Pallet<T> { + /// Request a randomness + #[pallet::weight(100_000_000)] + pub fn request( + origin: OriginFor<T>, + randomness_type: RandomnessType, + salt: H256, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let request_id = Self::do_request(&who, randomness_type, salt)?; + + Self::deposit_event(Event::RequestedRandomness { + request_id, + salt, + r#type: randomness_type, + }); + + Ok(()) + } + } + + // HOOKS // + + #[pallet::hooks] + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { + fn on_initialize(_: T::BlockNumber) -> Weight { + let mut total_weight = 0; + + total_weight += 100_000; + for Request { request_id, salt } in RequestsReadyAtNextBlock::<T>::take() { + let randomness = T::CurrentBlockRandomness::random(salt.as_ref()) + .0 + .unwrap_or_default(); + total_weight += T::OnFilledRandomness::on_filled_randomness(request_id, randomness); + Self::deposit_event(Event::FilledRandomness { + request_id, + randomness, + }); + total_weight += 100_000; + } + + if NewEpoch::<T>::get() { + NewEpoch::<T>::put(false); + total_weight += 100_000; + for Request { request_id, salt } in RequestsReadyAtNextEpoch::<T>::take() { + let randomness = T::RandomnessFromOneEpochAgo::random(salt.as_ref()).0; + total_weight += + T::OnFilledRandomness::on_filled_randomness(request_id, randomness); + Self::deposit_event(Event::FilledRandomness { + request_id, + randomness, + }); + total_weight += 100_000; + } + + total_weight += 200_000; + let requests_ready_at_next_epoch = RequestsReadyInTwoEpochs::<T>::take(); + RequestsReadyAtNextEpoch::<T>::put(requests_ready_at_next_epoch); + + total_weight += 200_000; + let requests_ready_in_two_epochs = RequestsReadyInThreeEpochs::<T>::take(); + RequestsReadyInTwoEpochs::<T>::put(requests_ready_in_two_epochs); + + total_weight += 200_000; + let requests_ready_in_three_epochs = PendingRequests::<T>::take(); + RequestsReadyInThreeEpochs::<T>::put(requests_ready_in_three_epochs); + } + + total_weight + } + } + + // PUBLIC FUNCTIONS // + + impl<T: Config> Pallet<T> { + pub fn do_request( + requestor: &T::AccountId, + randomness_type: RandomnessType, + salt: H256, + ) -> Result<RequestId, DispatchError> { + // Verify phase + ensure!( + RequestsIds::<T>::count() < T::MaxRequests::get(), + Error::<T>::FullQueue + ); + + Self::pay_request(requestor)?; + + // Apply phase + Ok(Self::apply_request(randomness_type, salt)) + } + pub fn force_request(randomness_type: RandomnessType, salt: H256) -> RequestId { + Self::apply_request(randomness_type, salt) + } + pub fn on_new_epoch() { + NewEpoch::<T>::put(true); + } + } + + // INTERNAL FUNCTIONS // + + impl<T: Config> Pallet<T> { + fn pay_request(requestor: &T::AccountId) -> DispatchResult { + let imbalance = T::Currency::withdraw( + requestor, + T::RequestPrice::get(), + WithdrawReasons::FEE, + ExistenceRequirement::KeepAlive, + )?; + T::OnUnbalanced::on_unbalanced(imbalance); + Ok(()) + } + fn apply_request(randomness_type: RandomnessType, salt: H256) -> RequestId { + let request_id = RequestIdProvider::<T>::mutate(|next_request_id| { + core::mem::replace(next_request_id, next_request_id.saturating_add(1)) + }); + RequestsIds::<T>::insert(request_id, ()); + match randomness_type { + RandomnessType::RandomnessFromPreviousBlock => { + RequestsReadyAtNextBlock::<T>::append(Request { request_id, salt }); + } + RandomnessType::RandomnessFromOneEpochAgo => { + if NewEpoch::<T>::get() { + RequestsReadyInThreeEpochs::<T>::append(Request { request_id, salt }); + } else { + RequestsReadyInTwoEpochs::<T>::append(Request { request_id, salt }); + } + } + RandomnessType::RandomnessFromTwoEpochsAgo => { + if NewEpoch::<T>::get() { + PendingRequests::<T>::append(Request { request_id, salt }); + } else { + RequestsReadyInThreeEpochs::<T>::append(Request { request_id, salt }); + } + } + } + request_id + } + } +} diff --git a/pallets/provide-randomness/src/types.rs b/pallets/provide-randomness/src/types.rs new file mode 100644 index 000000000..cb6c3d2a6 --- /dev/null +++ b/pallets/provide-randomness/src/types.rs @@ -0,0 +1,36 @@ +// 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/>. + +//! Various basic types for use in pallet provide randomness + +use super::RequestId; +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::*; +use scale_info::TypeInfo; +use sp_core::H256; + +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub enum RandomnessType { + RandomnessFromPreviousBlock, + RandomnessFromOneEpochAgo, + RandomnessFromTwoEpochsAgo, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Request { + pub request_id: RequestId, + pub salt: H256, +} diff --git a/resources/metadata.scale b/resources/metadata.scale index e7cb5e913808755149ae30d7d23c9f3f2befccd8..aaae5189c6cf33378f92a82f949f3f23a0c2ee3c 100644 GIT binary patch delta 19588 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 MWMg$@sqkb00B$3?9RL6T delta 8471 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 diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index d664f6723..7a5eeb50b 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -25,9 +25,11 @@ std = [ 'pallet-authority-members/std', 'pallet-balances/std', 'pallet-certification/std', + 'pallet-duniter-account/std', 'pallet-duniter-wot/std', 'pallet-identity/std', 'pallet-membership/std', + 'pallet-provide-randomness/std', 'pallet-ud-accounts-storage/std', 'serde', 'sp-arithmetic/std', @@ -40,9 +42,11 @@ std = [ [dependencies] pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } +pallet-duniter-account = { path = '../../pallets/duniter-account', 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 } +pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false } pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false } sp-membership = { path = '../../primitives/membership', default-features = false } diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs index f601b2dc5..5e35e8170 100644 --- a/runtime/common/src/handlers.rs +++ b/runtime/common/src/handlers.rs @@ -22,6 +22,17 @@ use frame_support::pallet_prelude::Weight; use frame_support::Parameter; use sp_runtime::traits::IsMember; +pub struct OnNewSessionHandler<Runtime>(core::marker::PhantomData<Runtime>); +impl<Runtime> pallet_authority_members::traits::OnNewSession for OnNewSessionHandler<Runtime> +where + Runtime: pallet_provide_randomness::Config, +{ + fn on_new_session(_index: sp_staking::SessionIndex) -> Weight { + pallet_provide_randomness::Pallet::<Runtime>::on_new_epoch(); + 0 + } +} + pub struct OnMembershipEventHandler<Inner, Runtime>(core::marker::PhantomData<(Inner, Runtime)>); type MembershipMetaData = pallet_duniter_wot::MembershipMetaData<AccountId>; @@ -92,7 +103,7 @@ impl< frame_system::Origin::<Runtime>::Signed(owner_key.clone()).into(), ) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to set session keys: {:?}", e) } } 0 @@ -105,7 +116,7 @@ impl< call.dispatch_bypass_filter(frame_system::Origin::<Runtime>::Root.into()) { sp_std::if_std! { - println!("{:?}", e) + println!("faid to remove member: {:?}", e) } } 0 @@ -127,7 +138,7 @@ where Some(idty_index), ) { sp_std::if_std! { - println!("{:?}", e) + println!("fail to revoke membership: {:?}", e) } } 0 @@ -146,16 +157,6 @@ where fn remove_idty_consumers(idty_index: IdtyIndex) -> Weight { // Remove smith member if pallet_membership::Pallet::<Runtime, Instance2>::is_member(&idty_index) { - if let Err(e) = pallet_authority_members::Pallet::<Runtime>::remove_member( - frame_system::RawOrigin::Root.into(), - idty_index, - ) { - log::error!( - target: "runtime::common", - "Logic error: fail to remove authority member in remove_idty_consumers(): {:?}", - e - ); - } if let Err(e) = pallet_membership::Pallet::<Runtime, Instance2>::revoke_membership( frame_system::RawOrigin::Root.into(), Some(idty_index), diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs index 4a9ae0417..1dae66af8 100644 --- a/runtime/common/src/pallets_config.rs +++ b/runtime/common/src/pallets_config.rs @@ -67,7 +67,7 @@ macro_rules! pallets_config { /// What to do if an account is fully reaped from the system. type OnKilledAccount = (); /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData<Balance>; + type AccountData = pallet_duniter_account::AccountData<Balance>; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = (); /// This is used as an identifier of the chain. 42 is the generic substrate prefix. @@ -109,6 +109,15 @@ macro_rules! pallets_config { type NoPreimagePostponement = (); } + // ACCOUNT // + + impl pallet_duniter_account::Config for Runtime { + type AccountIdToSalt = sp_runtime::traits::ConvertInto; + type Event = Event; + type MaxNewAccountsPerBlock = frame_support::pallet_prelude::ConstU32<100>; + type NewAccountPrice = frame_support::traits::ConstU64<200>; + } + // BLOCK CREATION // impl pallet_babe::Config for Runtime { @@ -151,7 +160,7 @@ macro_rules! pallets_config { impl pallet_balances::Config for Runtime { type MaxLocks = MaxLocks; - type MaxReserves = (); + type MaxReserves = frame_support::pallet_prelude::ConstU32<5>; type ReserveIdentifier = [u8; 8]; /// The type for recording an account's balance. type Balance = Balance; @@ -159,7 +168,7 @@ macro_rules! pallets_config { type Event = Event; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; + type AccountStore = Account; type WeightInfo = common_runtime::weights::pallet_balances::WeightInfo<Runtime>; } @@ -191,6 +200,7 @@ macro_rules! pallets_config { type Event = Event; type KeysWrapper = opaque::SessionKeysWrapper; type IsMember = SmithsMembership; + type OnNewSession = OnNewSessionHandler<Runtime>; type OnRemovedMember = OnRemovedAuthorityMemberHandler<Runtime>; type MemberId = IdtyIndex; type MemberIdOf = Identity; @@ -266,6 +276,17 @@ macro_rules! pallets_config { type ProofLimit = frame_support::traits::ConstU32<255>; } + impl pallet_provide_randomness::Config for Runtime { + type Currency = Balances; + type Event = Event; + type MaxRequests = frame_support::traits::ConstU32<1_000>; + type RequestPrice = frame_support::traits::ConstU64<200>; + type OnFilledRandomness = Account; + type OnUnbalanced = (); + type CurrentBlockRandomness = pallet_babe::CurrentBlockRandomness<Self>; + type RandomnessFromOneEpochAgo = pallet_babe::RandomnessFromOneEpochAgo<Self>; + } + parameter_types! { // One storage item; key size 32, value size 8; . pub const ProxyDepositBase: Balance = deposit(1, 8); diff --git a/runtime/g1/Cargo.toml b/runtime/g1/Cargo.toml index ce2dac153..1f08a0648 100644 --- a/runtime/g1/Cargo.toml +++ b/runtime/g1/Cargo.toml @@ -39,13 +39,15 @@ std = [ 'pallet-balances/std', 'pallet-certification/std', 'pallet-collective/std', + 'pallet-duniter-account/std', 'pallet-duniter-wot/std', 'pallet-grandpa/std', 'pallet-identity/std', 'pallet-im-online/std', 'pallet-membership/std', - 'pallet-proxy/std', 'pallet-multisig/std', + 'pallet-provide-randomness/std', + 'pallet-proxy/std', 'pallet-session/std', 'pallet-sudo/std', 'pallet-universal-dividend/std', @@ -71,12 +73,15 @@ std = [ ] [dependencies] +# local common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } +pallet-duniter-account = { path = '../../pallets/duniter-account', 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 } +pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false } pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false } pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false } sp-membership = { path = '../../primitives/membership', default-features = false } diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs index 6528e2864..ed5a4d9cf 100644 --- a/runtime/g1/src/lib.rs +++ b/runtime/g1/src/lib.rs @@ -194,15 +194,15 @@ construct_runtime!( { // Basic stuff System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1, + Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2, - // Babe must be before session. - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2, - - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + // Block creation + Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4, // Money management - Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5, + Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6, TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32, // Consensus support. @@ -236,9 +236,10 @@ construct_runtime!( // Utilities AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62, - Utility: pallet_utility::{Pallet, Call, Event} = 63, + 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, } ); diff --git a/runtime/gdev/Cargo.toml b/runtime/gdev/Cargo.toml index fb66fe924..9a325078a 100644 --- a/runtime/gdev/Cargo.toml +++ b/runtime/gdev/Cargo.toml @@ -41,10 +41,12 @@ std = [ 'pallet-certification/std', 'pallet-collective/std', 'pallet-duniter-test-parameters/std', + 'pallet-duniter-account/std', 'pallet-duniter-wot/std', 'pallet-grandpa/std', 'pallet-identity/std', 'pallet-membership/std', + 'pallet-provide-randomness/std', 'pallet-im-online/std', 'pallet-multisig/std', 'pallet-proxy/std', @@ -83,9 +85,11 @@ common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', 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-account = { path = '../../pallets/duniter-account', 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 } +pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false } pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false } pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false } pallet-upgrade-origin = { path = '../../pallets/upgrade-origin', default-features = false } diff --git a/runtime/gdev/src/lib.rs b/runtime/gdev/src/lib.rs index 09583583b..c8fb20374 100644 --- a/runtime/gdev/src/lib.rs +++ b/runtime/gdev/src/lib.rs @@ -247,17 +247,18 @@ construct_runtime!( { // Basic stuff System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1, + Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2, // Block creation - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4, // Test parameters - Parameters: pallet_duniter_test_parameters::{Pallet, Config<T>, Storage} = 4, + Parameters: pallet_duniter_test_parameters::{Pallet, Config<T>, Storage} = 5, // Money management - Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5, + Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6, TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32, // Consensus support @@ -292,9 +293,10 @@ construct_runtime!( // Utilities AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62, - Utility: pallet_utility::{Pallet, Call, Event} = 63, + 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, } ); diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs index 655f6186b..215b1152a 100644 --- a/runtime/gdev/tests/integration_tests.rs +++ b/runtime/gdev/tests/integration_tests.rs @@ -124,11 +124,11 @@ fn test_remove_smith_identity() { assert_eq!(events.len(), 4); assert_eq!( System::events()[0].event, - Event::AuthorityMembers(pallet_authority_members::Event::MemberRemoved(3)) + Event::SmithsMembership(pallet_membership::Event::MembershipRevoked(3)) ); assert_eq!( System::events()[1].event, - Event::SmithsMembership(pallet_membership::Event::MembershipRevoked(3)) + Event::AuthorityMembers(pallet_authority_members::Event::MemberRemoved(3)) ); assert_eq!( System::events()[2].event, diff --git a/runtime/gtest/Cargo.toml b/runtime/gtest/Cargo.toml index 5eb92d065..af4827930 100644 --- a/runtime/gtest/Cargo.toml +++ b/runtime/gtest/Cargo.toml @@ -39,11 +39,13 @@ std = [ 'pallet-balances/std', 'pallet-certification/std', 'pallet-collective/std', + 'pallet-duniter-account/std', 'pallet-duniter-wot/std', 'pallet-grandpa/std', 'pallet-identity/std', - 'pallet-membership/std', 'pallet-im-online/std', + 'pallet-membership/std', + 'pallet-provide-randomness/std', 'pallet-proxy/std', 'pallet-multisig/std', 'pallet-session/std', @@ -71,12 +73,15 @@ std = [ ] [dependencies] +# local common-runtime = { path = "../common", default-features = false } pallet-authority-members = { path = '../../pallets/authority-members', default-features = false } pallet-certification = { path = '../../pallets/certification', default-features = false } +pallet-duniter-account = { path = '../../pallets/duniter-account', 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 } +pallet-provide-randomness = { path = '../../pallets/provide-randomness', default-features = false } pallet-ud-accounts-storage = { path = '../../pallets/ud-accounts-storage', default-features = false } pallet-universal-dividend = { path = '../../pallets/universal-dividend', default-features = false } sp-membership = { path = '../../primitives/membership', default-features = false } diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs index 211925aa8..49444c2dc 100644 --- a/runtime/gtest/src/lib.rs +++ b/runtime/gtest/src/lib.rs @@ -195,14 +195,15 @@ construct_runtime!( { // Basic stuff System: frame_system::{Pallet, Call, Config, Storage, Event<T>} = 0, - Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1, + Account: pallet_duniter_account::{Pallet, Storage, Config<T>, Event<T>} = 1, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 2, // Block creation - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 3, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 4, // Money management - Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5, + Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 6, TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 32, // Consensus support. @@ -236,9 +237,10 @@ construct_runtime!( // Utilities AtomicSwap: pallet_atomic_swap::{Pallet, Call, Storage, Event<T>} = 60, - Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 61, - Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 62, - Utility: pallet_utility::{Pallet, Call, Event} = 63, + 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, } ); -- GitLab