diff --git a/Cargo.lock b/Cargo.lock index 485a1b9e8dffb..11b0c7ebc66b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1634,18 +1634,18 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "a8672257d642ffdd235f6e9c723c2326ac1253c8f3c022e7cfd2e57da55b1131" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "33526f770a27828ce7c2792fdb7cb240220237e0ff12933ed6c23957fc5dd7cf" dependencies = [ "proc-macro2", "quote", @@ -4579,6 +4579,7 @@ dependencies = [ "hex-literal", "log 0.4.14", "node-primitives", + "pallet-alliance", "pallet-assets", "pallet-authority-discovery", "pallet-authorship", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index dafd9db8bab96..6ac6595e42ade 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -51,6 +51,7 @@ frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, p frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/rpc/runtime-api/" } frame-try-runtime = { version = "0.10.0-dev", default-features = false, path = "../../../frame/try-runtime", optional = true } +pallet-alliance = { version = "4.0.0-dev", default-features = false, path = "../../../frame/alliance" } pallet-assets = { version = "4.0.0-dev", default-features = false, path = "../../../frame/assets" } pallet-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authority-discovery" } pallet-authorship = { version = "4.0.0-dev", default-features = false, path = "../../../frame/authorship" } @@ -169,7 +170,8 @@ std = [ "log/std", "frame-try-runtime/std", "sp-npos-elections/std", - "sp-io/std" + "sp-io/std", + "pallet-alliance/std", ] runtime-benchmarks = [ "frame-benchmarking", @@ -177,6 +179,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "pallet-alliance/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -214,6 +217,7 @@ try-runtime = [ "frame-executive/try-runtime", "frame-try-runtime", "frame-system/try-runtime", + "pallet-alliance/try-runtime", "pallet-assets/try-runtime", "pallet-authority-discovery/try-runtime", "pallet-authorship/try-runtime", diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index e315a45e698ce..6f43a3a27d362 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -17,8 +17,15 @@ //! Some configurable implementations as associated type for the substrate runtime. -use crate::{Authorship, Balances, NegativeImbalance}; -use frame_support::traits::{Currency, OnUnbalanced}; +use crate::{AllianceMotion, Authorship, Balances, Call, Identity, NegativeImbalance}; +use frame_support::{ + dispatch::{DispatchError, DispatchResultWithPostInfo}, + traits::{Currency, OnUnbalanced}, + weights::Weight, +}; +use node_primitives::{AccountId, Hash}; +use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider}; +use pallet_identity::Judgement; pub struct Author; impl OnUnbalanced for Author { @@ -27,6 +34,67 @@ impl OnUnbalanced for Author { } } +pub struct AllianceIdentityVerifier; +impl IdentityVerifier for AllianceIdentityVerifier { + fn super_account_id(who: &AccountId) -> Option { + Identity::super_of(who).map(|parent| parent.0) + } + + fn has_identity(who: &AccountId, fields: u64) -> bool { + Identity::has_identity(who, fields) + } + + fn has_good_judgement(who: &AccountId) -> bool { + if let Some(judgements) = + Identity::identity(who).map(|registration| registration.judgements) + { + judgements + .iter() + .filter(|(_, j)| Judgement::KnownGood == *j || Judgement::Reasonable == *j) + .count() > 0 + } else { + false + } + } +} + +pub struct AllianceProposalProvider; +impl ProposalProvider for AllianceProposalProvider { + fn propose_proposal( + who: AccountId, + threshold: u32, + proposal: Call, + ) -> Result { + AllianceMotion::do_propose(who, threshold, proposal) + } + + fn vote_proposal( + who: AccountId, + proposal: Hash, + index: ProposalIndex, + approve: bool, + ) -> Result { + AllianceMotion::do_vote(who, proposal, index, approve) + } + + fn veto_proposal(proposal_hash: Hash) -> u32 { + AllianceMotion::do_disapprove_proposal(proposal_hash) + } + + fn close_proposal( + proposal_hash: Hash, + proposal_index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) + } + + fn proposal_of(proposal_hash: Hash) -> Option { + AllianceMotion::proposal_of(proposal_hash) + } +} + #[cfg(test)] mod multiplier_tests { use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 7c6475bd18d6a..4561d8ed36f2b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub use sp_runtime::BuildStorage; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::Author; +use impls::{AllianceIdentityVerifier, AllianceProposalProvider, Author}; /// Constant values used within the runtime. pub mod constants; @@ -1208,6 +1208,46 @@ impl pallet_transaction_storage::Config for Runtime { type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; } +parameter_types! { + pub const AllianceMotionDuration: BlockNumber = 5 * DAYS; + pub const AllianceMaxProposals: u32 = 100; + pub const AllianceMaxMembers: u32 = 100; +} + +type AllianceCollective = pallet_collective::Instance3; +impl pallet_collective::Config for Runtime { + type Origin = Origin; + type Proposal = Call; + type Event = Event; + type MotionDuration = AllianceMotionDuration; + type MaxProposals = AllianceMaxProposals; + type MaxMembers = AllianceMaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; +} + +parameter_types! { + pub const MaxBlacklistCount: u32 = 100; +} + +impl pallet_alliance::Config for Runtime { + type Event = Event; + type Proposal = Call; + type SuperMajorityOrigin = EnsureOneOf< + AccountId, + EnsureRoot, + pallet_collective::EnsureProportionMoreThan<_2, _3, AccountId, AllianceCollective>, + >; + type Currency = Balances; + type InitializeMembers = AllianceMotion; + type MembershipChanged = AllianceMotion; + type Slashed = Treasury; + type IdentityVerifier = AllianceIdentityVerifier; + type ProposalProvider = AllianceProposalProvider; + type MaxBlacklistCount = MaxBlacklistCount; + type CandidateDeposit = CandidateDeposit; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -1254,6 +1294,8 @@ construct_runtime!( Gilt: pallet_gilt::{Pallet, Call, Storage, Event, Config}, Uniques: pallet_uniques::{Pallet, Call, Storage, Event}, TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Config, Event}, + AllianceMotion: pallet_collective::::{Pallet, Storage, Origin, Event}, + Alliance: pallet_alliance::{Pallet, Call, Storage, Event}, } ); @@ -1683,6 +1725,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_uniques, Uniques); add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_vesting, Vesting); + add_benchmark!(params, batches, pallet_alliance, Alliance); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 60529836bdc52..ad58d2895d7e3 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -135,16 +135,12 @@ type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -const IDENTITY_FIELD_DISPLAY: u64 = - 0b0000000000000000000000000000000000000000000000000000000000000001; -const IDENTITY_FIELD_WEB: u64 = 0b0000000000000000000000000000000000000000000000000000000000000100; - pub trait IdentityVerifier { - fn super_account_id(who: &AccountId) -> Option; + fn has_identity(who: &AccountId, fields: u64) -> bool; - fn verify_identity(who: &AccountId, fields: u64) -> bool; + fn has_good_judgement(who: &AccountId) -> bool; - fn verify_judgement(who: &AccountId) -> bool; + fn super_account_id(who: &AccountId) -> Option; } pub trait ProposalProvider { @@ -276,12 +272,10 @@ pub mod pallet { KickingMember, /// Balance is insufficient to be a candidate. InsufficientCandidateFunds, - /// The account's identity has not been judged. - WithoutVerifiedIdentity, - /// The account's identity has not display field. - WithoutIdentityDisplay, - /// The account' identity has not website field. - WithoutIdentityWebsite, + /// The account's identity has not display field and website field. + WithoutIdentityDisplayAndWebsite, + /// The account's identity has no good judgement. + WithoutGoodIdentityJudgement, /// The proposal hash is not found. MissingProposalHash, /// The proposal is not vetoable. @@ -934,18 +928,19 @@ impl, I: 'static> Pallet { } fn has_identity(who: &T::AccountId) -> DispatchResult { - let judgement = |w: &T::AccountId| -> DispatchResult { - ensure!( - T::IdentityVerifier::verify_identity(w, IDENTITY_FIELD_DISPLAY), - Error::::WithoutIdentityDisplay - ); + const IDENTITY_FIELD_DISPLAY: u64 = + 0b0000000000000000000000000000000000000000000000000000000000000001; + const IDENTITY_FIELD_WEB: u64 = + 0b0000000000000000000000000000000000000000000000000000000000000100; + + let judgement = |who: &T::AccountId| -> DispatchResult { ensure!( - T::IdentityVerifier::verify_judgement(w), - Error::::WithoutVerifiedIdentity + T::IdentityVerifier::has_identity(who, IDENTITY_FIELD_DISPLAY | IDENTITY_FIELD_WEB), + Error::::WithoutIdentityDisplayAndWebsite ); ensure!( - T::IdentityVerifier::verify_identity(w, IDENTITY_FIELD_WEB), - Error::::WithoutIdentityWebsite + T::IdentityVerifier::has_good_judgement(who), + Error::::WithoutGoodIdentityJudgement ); Ok(()) }; diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 49844ddd2dcba..ef9d1da0435f4 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -97,16 +97,16 @@ impl pallet_collective::Config for Test { pub struct AllianceIdentityVerifier; impl IdentityVerifier for AllianceIdentityVerifier { - fn super_account_id(_who: &u64) -> Option { - None + fn has_identity(_who: &u64, _fields: u64) -> bool { + true } - fn verify_identity(_who: &u64, _field: u64) -> bool { + fn has_good_judgement(_who: &u64) -> bool { true } - fn verify_judgement(_who: &u64) -> bool { - true + fn super_account_id(_who: &u64) -> Option { + None } } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 598be25c5ef38..ad43b46148c9c 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -enumflags2 = { version = "0.6.2" } +enumflags2 = { version = "0.7.1" } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index a91381f1edd8b..fcbee59415238 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -81,13 +81,13 @@ pub mod weights; use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency}; use sp_runtime::traits::{AppendZerosInput, Saturating, StaticLookup, Zero}; use sp_std::{convert::TryInto, prelude::*}; -pub use weights::WeightInfo; pub use pallet::*; pub use types::{ Data, IdentityField, IdentityFields, IdentityInfo, Judgement, RegistrarIndex, RegistrarInfo, Registration, }; +pub use weights::WeightInfo; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -160,7 +160,7 @@ pub mod pallet { /// TWOX-NOTE: OK ― `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn identity)] - pub(super) type IdentityOf = StorageMap< + pub type IdentityOf = StorageMap< _, Twox64Concat, T::AccountId, @@ -172,7 +172,7 @@ pub mod pallet { /// context. If the account is not some other account's sub-identity, then just `None`. #[pallet::storage] #[pallet::getter(fn super_of)] - pub(super) type SuperOf = + pub type SuperOf = StorageMap<_, Blake2_128Concat, T::AccountId, (T::AccountId, Data), OptionQuery>; /// Alternative "sub" identities of this account. @@ -182,7 +182,7 @@ pub mod pallet { /// TWOX-NOTE: OK ― `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn subs_of)] - pub(super) type SubsOf = StorageMap< + pub type SubsOf = StorageMap< _, Twox64Concat, T::AccountId, @@ -196,7 +196,7 @@ pub mod pallet { /// The index into this can be cast to `RegistrarIndex` to get a valid value. #[pallet::storage] #[pallet::getter(fn registrars)] - pub(super) type Registrars = StorageValue< + pub type Registrars = StorageValue< _, BoundedVec, T::AccountId>>, T::MaxRegistrars>, ValueQuery, @@ -970,4 +970,13 @@ impl Pallet { .filter_map(|a| SuperOf::::get(&a).map(|x| (a, x.1))) .collect() } + + /// Check if the account has corresponding identity information by the identity field. + pub fn has_identity(who: &T::AccountId, fields: u64) -> bool { + if let Some(info) = IdentityOf::::get(who).map(|registration| registration.info) { + (info.fields().0.bits() & fields) == 1 + } else { + false + } + } } diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index ed6aeb18e96a1..127c4367862f6 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -17,7 +17,7 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; -use enumflags2::BitFlags; +use enumflags2::{bitflags, BitFlags}; use frame_support::{ traits::{ConstU32, Get}, BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -230,8 +230,9 @@ impl> { pub twitter: Data, } +impl> IdentityInfo { + pub(crate) fn fields(&self) -> IdentityFields { + let mut res = >::empty(); + if self.display != Data::None { + res.insert(IdentityField::Display); + } + if self.legal != Data::None { + res.insert(IdentityField::Legal); + } + if self.web != Data::None { + res.insert(IdentityField::Web); + } + if self.riot != Data::None { + res.insert(IdentityField::Riot); + } + if self.email != Data::None { + res.insert(IdentityField::Email); + } + if self.pgp_fingerprint.is_some() { + res.insert(IdentityField::PgpFingerprint); + } + if self.image != Data::None { + res.insert(IdentityField::Image); + } + if self.twitter != Data::None { + res.insert(IdentityField::Twitter); + } + IdentityFields(res) + } +} + /// Information concerning the identity of the controller of an account. /// /// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a