diff --git a/Cargo.lock b/Cargo.lock index ce9d5ea77e7b5dc2f05b8efdd16af31c27bec619..ef4a5bba74d60a1f2abf137c799fb09f807fff20 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 c85139721b48f6ec92bd59cb4e9aaba662b02e1c..2e0e830ce5e92f1230c4b11b419b14b46494a2f9 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 62d63d952614379dae307526704f4227765b033f..1176adc1ed52b577817e614f6a7cf6148c18bf21 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 cb0d6dbbb5461d6ddd7ad5254236e250a98b887c..f4e5707bcff836733f306b70ca8592f066043a01 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 6f499362f4b051b1c73b0e3df82be42c1c1117a6..0d1ae96c8af1dd2f6ff5e22a62bf45c7bd80e50f 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 1d6b055557a8ffc96d854b25005147afa59f13e4..1cfb55dcfb3fd05139fbc9b14690f6dba317549c 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 0000000000000000000000000000000000000000..c4f48360f0b1c5ac9e5c3fd6e26e24c3b13f966b --- /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 0000000000000000000000000000000000000000..85991c6ed94b88633dbdf710f6a44a0d60088510 --- /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 0000000000000000000000000000000000000000..92d5494db7b057e93bb81e0301fbafbf4de6f43b --- /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 161ce0b5ee6bf6afbafa0f1545a39ad8d882a228..90689c4c4d4d9872aa48a2290e81e41db434e7b7 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 da821daa430f73d5e2654e4fd426b49af88956b1..123dbf7dec10d7c944b49ed9809dad00ebf0e301 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 e9f6f4c6383a046a210fa8dca9794ea5e297d4b8..42f255fa8bdbd844c792f69a0eedf8d3de6ea4e3 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 76d59fd84c0ab4f12b34aa5986842ce708f4d4b3..00f0ed190114e2e59d9bed5a4868fa2bd4fdcd81 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 3d5103e1d828fa15f1225d72041a0408deb6b7f8..7a19d32d3cc8849aa5b5795261c3c898f6fe12c5 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 462c437ae0e9aebb61b8e654994669aca8d88847..885b1cd009f5d805d18585c3628467d6d528cbd4 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 629a81ce65b06581c6ed8d62b3618642d6d1e7eb..d6991ce60acdfd98e60a775c278804cf9f2bfd0c 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 0000000000000000000000000000000000000000..f7d8a9f84edb07a690ccb869bfe1781c5f06836b --- /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 0000000000000000000000000000000000000000..10907697032a690e72bcb4c56cc05cc5f32629b4 --- /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 0000000000000000000000000000000000000000..cb6c3d2a63f2715cacf9544c95fe4bbb806c8983 --- /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 Binary files a/resources/metadata.scale and b/resources/metadata.scale differ diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index d664f6723d08da0ba20a3cff9c7503b56b98d11a..7a5eeb50b6a6610c0e932aa52b5b6705bc3dcf40 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 f601b2dc5bcffae9265aa42a1ead14e7783fc4b6..5e35e81701e6d0b4ad0dd71dc2f2f9900022f03d 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 4a9ae041799d4cd606266001e9ed4f8acaaa006b..1dae66af8ed3fd1e73a644035ef15999dd431f3a 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 ce2dac1538260a29d7a37826e11d28bbda2462bb..1f08a0648284599b0bdbc5db71f2967ff9fad30f 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 6528e2864bee0ca430be73597b1dfc9d20badc52..ed5a4d9cfce917a41fc865260fba6967279bc2a0 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 fb66fe92443260a19ed0ccfc36e06f8a68ab944a..9a325078a4a2b47a410d663d1e8359247e994cdf 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 09583583bc502e382746955820ecd73b2dc5bb0b..c8fb20374958e8f49c5cf6cfc2f678d43f4ffc85 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 655f6186bd1fd96a2dde70772debfcc039b2f2b0..215b1152a51f1d850f173cd7f511b828c7b5c011 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 5eb92d06504cd8cada91e7b3ac3576aaea18e1dc..af482793005974d16eda5bd51aa63ccc723cab14 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 211925aa81f3bbb10902ec6cbf123f87bdf1f4d2..49444c2dc1a288cd30e35f51bc4a0362ea6e6767 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, } );