Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mainnet): add gov: collective, membership, motion #448

Merged
merged 39 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
45ae67b
feat(pallets): add pallet-motion
peterwht Jan 23, 2025
8d0d7ad
build(mainnet): add gov pallets: collective, membership, motion
peterwht Jan 23, 2025
e777676
feat(mainnet): add gov configs: collective, membership, motion
peterwht Jan 23, 2025
33e16e9
feat(node): add councillors at genesis
peterwht Jan 23, 2025
f8606e3
TEMPORARY COMMIT: Sets mainnet chain-spec to Development
peterwht Jan 23, 2025
5a8a374
refactor(governance): apply feedback configuration changes
al3mart Feb 5, 2025
b5d76fa
test(governance): add council, membership & motion tests
al3mart Feb 5, 2025
c283432
refactor(governance): change mainnet ChainType to Live
al3mart Feb 5, 2025
8049245
Update runtime/mainnet/src/config/governance.rs
al3mart Feb 6, 2025
6196d22
refactor(governance): SuperMajorityOrigin is at least 3/4
al3mart Feb 6, 2025
1325b57
docs(governance): update comments.
al3mart Feb 6, 2025
6d87835
fix(governance): remove duplicated code
al3mart Feb 6, 2025
7207135
style(mainnet): simplify syntax in Runtime struct
al3mart Feb 6, 2025
31a9f52
style(mainnet): order dependencies
al3mart Feb 6, 2025
508e3aa
fix(governance): amend motion origin tests
al3mart Feb 6, 2025
f9a573b
refactor(motion): feature gate simple majority
al3mart Feb 6, 2025
1d1304b
docs(motion): include Config docs
al3mart Feb 6, 2025
85242e8
docs(motion): credit source
al3mart Feb 6, 2025
3c02141
add simple-majority feature to mainnet runtime & node
al3mart Feb 6, 2025
99a4f24
refactor(motion): remove sp-std
al3mart Feb 6, 2025
c0cc278
fix(ci): temporary disabling zepter format feautures
al3mart Feb 6, 2025
91cca9f
refactor(motion): revert simple-majority feature
al3mart Feb 6, 2025
f8e92a1
refactor(ci): reenable zepter
al3mart Feb 6, 2025
5cdced0
refactor(governance): use MoreThanMajorityThenPrimeDefaultVote as Def…
al3mart Feb 7, 2025
aebe152
test(governance): runtime upgrade doesn't saturare weight limit
al3mart Feb 7, 2025
880fb24
fix(motion): remve sp-std dependendency
al3mart Feb 7, 2025
5d1d49e
style(governance): use change variable name
al3mart Feb 7, 2025
d86f49f
test(governance): remove irrelevant tests
al3mart Feb 7, 2025
3c57991
docs(motion): add documentation to public elements
al3mart Feb 7, 2025
01efc94
chore(governance): apply feedback
al3mart Feb 7, 2025
604bb64
refactor(governance): AllMembersButOne as RemoveOrigin
al3mart Feb 7, 2025
0e07b3c
chore(motion): update pallet author
al3mart Feb 7, 2025
5319e04
docs(motion): sort documentation
al3mart Feb 7, 2025
d245359
chore(motion): fmt
al3mart Feb 7, 2025
8790017
Update runtime/mainnet/src/config/governance.rs
al3mart Feb 7, 2025
a76aa2e
revert 604bb64
al3mart Feb 7, 2025
fd99104
chore(gov): remove CouncilMembership from the runtime
al3mart Feb 13, 2025
15711ea
chore(motion): remove extra weight from docs
al3mart Feb 14, 2025
8ba715f
chore(deps): remove pallet-membership from manifests"
peterwht Feb 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,319 changes: 1,119 additions & 1,200 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", b

# Local
pallet-api = { path = "pallets/api", default-features = false }
pallet-motion = { path = "pallets/motion", default-features = false }
pallet-nfts = { path = "pallets/nfts", default-features = false }
pop-chain-extension = { path = "./extension", default-features = false }
pop-primitives = { path = "./primitives", default-features = false }
Expand All @@ -90,7 +91,9 @@ pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk", branch = "
pallet-aura = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-authorship = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-collective = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
pallet-nft-fractionalization = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2412", default-features = false }
Expand Down
9 changes: 9 additions & 0 deletions networks/mainnet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ balances = [
["5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", 10000000000000000],
]

[parachains.genesis_overrides.councilMembership]
members = [
al3mart marked this conversation as resolved.
Show resolved Hide resolved
# Dev accounts
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
"5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy",
]

[[parachains.collators]]
name = "pop"
rpc_port = 9944
Expand Down
8 changes: 7 additions & 1 deletion node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ pub fn mainnet_chain_spec(relay: Relay) -> MainnetChainSpec {
],
sudo_account_id,
para_id.into(),
// councillors
vec![],
))
.with_protocol_id("pop")
.with_properties(properties)
Expand All @@ -208,6 +210,7 @@ fn mainnet_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
root: AccountId,
id: ParaId,
councillors: Vec<AccountId>,
) -> serde_json::Value {
use pop_runtime_mainnet::EXISTENTIAL_DEPOSIT;

Expand Down Expand Up @@ -238,7 +241,10 @@ fn mainnet_genesis(
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
"sudo": { "key": Some(root) }
"sudo": { "key": Some(root) },
al3mart marked this conversation as resolved.
Show resolved Hide resolved
"councilMembership": {
"members": councillors,
}
})
}

Expand Down
51 changes: 51 additions & 0 deletions pallets/motion/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[package]
authors = [ "Parity Technologies <admin@parity.io>", "R0GUE <go@r0gue.io>" ]
description = "FRAME pallet to wrap council calls providing root origin to the council."
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
name = "pallet-motion"
publish = false
repository = { workspace = true }
version = "4.0.0-dev"

[package.metadata.docs.rs]
targets = [ "x86_64-unknown-linux-gnu" ]

[dependencies]
codec = { workspace = true, default-features = false, features = [
"derive",
] }
frame-benchmarking = { workspace = true, default-features = false, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
log = { workspace = true, default-features = false }
pallet-collective = { workspace = true, default-features = false }
scale-info = { workspace = true, default-features = false, features = [
"derive",
] }
sp-runtime = { workspace = true, default-features = false }

[dev-dependencies]
pallet-balances = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-io = { workspace = true, default-features = false }

[features]
default = [ "std" ]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"pallet-collective/runtime-benchmarks",
]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"log/std",
"pallet-balances/std",
"pallet-collective/std",
"scale-info/std",
"sp-runtime/std",
]
try-runtime = [ "frame-support/try-runtime" ]
38 changes: 38 additions & 0 deletions pallets/motion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Motion Pallet
al3mart marked this conversation as resolved.
Show resolved Hide resolved

`pallet-motion` enables councils (`pallet-collective`) to make root-origin calls by providing three configurable origins:
- `SimpleMajority` (1/2)
- `SuperMajority` (2/3)
- `Unanimous` (1/1)

It is composed of three associated extrinsics, one for each origin:
- `simple_majority`
- Dispatches the call if and only if the number of votes is greater than `SimpleMajority`.
- `super_majority`
- Dispatches the call if and only if the number of votes is greater than or equal to `SuperMajority`.
- `unanimous`
- Dispatches the call if and only if all collective members have voted yes.


## Configuration

You can configure `pallet-motion` in combination with `pallet-collective` the following way:

```rust
type CouncilCollective = pallet_collective::Instance1;
impl pallet_motion::Config for Runtime {
// ---
type SimpleMajorityOrigin =
pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>;
type SuperMajorityOrigin =
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 2, 3>;
type UnanimousOrigin =
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 1>;
}
```

---

### Credit:

Original source at: https://github.com/Watr-Protocol/watr/tree/main/pallets/motion
55 changes: 55 additions & 0 deletions pallets/motion/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! Benchmarking setup for pallet-motion

use frame_benchmarking::v2::*;
use frame_support::traits::EnsureOrigin;

use super::*;
#[allow(unused)]
use crate::Pallet as Motion;

fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}

#[benchmarks(
where
<T as Config>::RuntimeCall: From<frame_system::Call<T>>,
)]
mod benchmarks {
use super::*;

#[benchmark]
fn simple_majority() {
let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
let origin = <T as Config>::SimpleMajorityOrigin::try_successful_origin().unwrap();

#[extrinsic_call]
al3mart marked this conversation as resolved.
Show resolved Hide resolved
_(origin as T::RuntimeOrigin, Box::new(call));

assert_last_event::<T>(Event::DispatchSimpleMajority { motion_result: Ok(()) }.into())
}

#[benchmark]
fn super_majority() {
let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
let origin = <T as Config>::SuperMajorityOrigin::try_successful_origin().unwrap();

#[extrinsic_call]
al3mart marked this conversation as resolved.
Show resolved Hide resolved
_(origin as T::RuntimeOrigin, Box::new(call));

assert_last_event::<T>(Event::DispatchSuperMajority { motion_result: Ok(()) }.into())
}

#[benchmark]
fn unanimous() {
let call: <T as Config>::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
let origin = <T as Config>::UnanimousOrigin::try_successful_origin().unwrap();

#[extrinsic_call]
al3mart marked this conversation as resolved.
Show resolved Hide resolved
_(origin as T::RuntimeOrigin, Box::new(call));

assert_last_event::<T>(Event::DispatchUnanimous { motion_result: Ok(()) }.into())
}

impl_benchmark_test_suite!(Motion, crate::mock::new_test_ext(), crate::mock::Test);
al3mart marked this conversation as resolved.
Show resolved Hide resolved
}
170 changes: 170 additions & 0 deletions pallets/motion/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

/// Dispatchable function benchmarks.
evilrobot-01 marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

/// Dispatchable function weights.
pub mod weights;
pub use pallet::*;
use sp_runtime::DispatchResult;
pub use weights::WeightInfo;

extern crate alloc;
use alloc::{boxed::Box, vec};

/// The motion pallet.
#[frame_support::pallet]
pub mod pallet {
use frame_support::{
dispatch::GetDispatchInfo, pallet_prelude::*, traits::UnfilteredDispatchable,
};
use frame_system::pallet_prelude::*;

use super::{DispatchResult, *};

#[pallet::pallet]
pub struct Pallet<T>(_);

/// Configure the pallet by specifying the parameters and types on which it depends.
#[pallet::config]
pub trait Config: frame_system::Config {
al3mart marked this conversation as resolved.
Show resolved Hide resolved
/// The runtime call type.
type RuntimeCall: Parameter
+ UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ GetDispatchInfo;
/// The runtime event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Origin that can act as `Root` origin if a collective has achieved a simple majority
/// consensus.
type SimpleMajorityOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Origin that can act as `Root` origin if a collective has achieved a super majority
/// consensus.
type SuperMajorityOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Origin that can act as `Root` origin if a collective has achieved a unanimous consensus.
type UnanimousOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Type representing the weight of this pallet
type WeightInfo: WeightInfo;
}

/// The events that can be emitted.
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// A [SimpleMajorityOrigin] motion was executed. [motion_result] contains the call result
DispatchSimpleMajority {
/// Result of dispatching the proposed call.
motion_result: DispatchResult,
},
/// A [SuperMajorityOrigin] motion was executed. [motion_result] contains the call result
DispatchSuperMajority {
/// Result of dispatching the proposed call.
motion_result: DispatchResult,
},
/// A [UnanimousOrigin] motion was executed. [motion_result] contains the call result
DispatchUnanimous {
/// Result of dispatching the proposed call.
motion_result: DispatchResult,
},
}

/// Errors inform users that something went wrong.
#[pallet::error]
pub enum Error<T> {}

/// The dispatchable functions available.
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Ensures the simple majority is met and dispatches a call with `Root` origin.
///
/// # <weight>
/// - O(1).
/// - Limited storage reads.
/// - One DB write (event).
/// - Weight of derivative `call` execution + 10,000.
al3mart marked this conversation as resolved.
Show resolved Hide resolved
peterwht marked this conversation as resolved.
Show resolved Hide resolved
/// # </weight>
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(T::WeightInfo::simple_majority().saturating_add(dispatch_info.call_weight), dispatch_info.class)
})]
#[pallet::call_index(1)]
pub fn simple_majority(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
peterwht marked this conversation as resolved.
Show resolved Hide resolved
) -> DispatchResultWithPostInfo {
T::SimpleMajorityOrigin::ensure_origin(origin)?;

let motion_result = Self::do_dispatch(*call);
Self::deposit_event(Event::DispatchSimpleMajority { motion_result });

Ok(Pays::No.into())
}

/// Ensures the super majority is met and dispatches a call with `Root` origin.
///
/// # <weight>
/// - O(1).
/// - Limited storage reads.
/// - One DB write (event).
/// - Weight of derivative `call` execution + 10,000.
peterwht marked this conversation as resolved.
Show resolved Hide resolved
/// # </weight>
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(T::WeightInfo::super_majority().saturating_add(dispatch_info.call_weight), dispatch_info.class)
})]
#[pallet::call_index(2)]
pub fn super_majority(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
T::SuperMajorityOrigin::ensure_origin(origin)?;

let motion_result = Self::do_dispatch(*call);
Self::deposit_event(Event::DispatchSuperMajority { motion_result });

Ok(Pays::No.into())
}

/// Ensures unanimous voting is met and dispatches a call with `Root` origin.
///
/// # <weight>
/// - O(1).
/// - Limited storage reads.
/// - One DB write (event).
/// - Weight of derivative `call` execution + 10,000.
peterwht marked this conversation as resolved.
Show resolved Hide resolved
/// # </weight>
#[pallet::weight({
let dispatch_info = call.get_dispatch_info();
(T::WeightInfo::unanimous().saturating_add(dispatch_info.call_weight), dispatch_info.class)
})]
#[pallet::call_index(3)]
pub fn unanimous(
origin: OriginFor<T>,
call: Box<<T as Config>::RuntimeCall>,
) -> DispatchResultWithPostInfo {
T::UnanimousOrigin::ensure_origin(origin)?;

let motion_result = Self::do_dispatch(*call);
Self::deposit_event(Event::DispatchUnanimous { motion_result });

Ok(Pays::No.into())
}
}

impl<T: Config> Pallet<T> {
/// Helper to actually dispatch RuntimeCall.
///
/// Should only be called after the origin is ensured.
///
/// Returns the `DispatchResult` from the dispatched call.
fn do_dispatch(call: <T as Config>::RuntimeCall) -> DispatchResult {
let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into());
res.map(|_| ()).map_err(|e| e.error)
}
}
}
Loading
Loading