Skip to content

Commit

Permalink
exchange member with a new account and same rank in the ranked collec… (
Browse files Browse the repository at this point in the history
#2587)

closes polkadot-fellows/help-center#1

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: command-bot <>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
  • Loading branch information
dharjeezy and ggwpez committed Jan 30, 2024
1 parent e5bb11b commit 5eb4773
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod tracks;
use super::*;
use crate::xcm_config::{FellowshipAdminBodyId, LocationToAccountId, WndAssetHub};
use frame_support::traits::{EitherOf, MapSuccess, TryMapSuccess};
use frame_system::EnsureRootWithSuccess;
pub use origins::pallet_origins as pallet_ambassador_origins;
use origins::pallet_origins::{
EnsureAmbassadorsVoice, EnsureAmbassadorsVoiceFrom, EnsureHeadAmbassadorsVoice, Origin,
Expand Down Expand Up @@ -99,11 +100,17 @@ pub type PromoteOrigin = EitherOf<
>,
>;

/// Exchange is by any of:
/// - Root can exchange arbitrarily.
/// - the Fellows origin
pub type ExchangeOrigin = EitherOf<EnsureRootWithSuccess<AccountId, ConstU16<65535>>, Fellows>;

impl pallet_ranked_collective::Config<AmbassadorCollectiveInstance> for Runtime {
type WeightInfo = weights::pallet_ranked_collective_ambassador_collective::WeightInfo<Runtime>;
type RuntimeEvent = RuntimeEvent;
type PromoteOrigin = PromoteOrigin;
type DemoteOrigin = DemoteOrigin;
type ExchangeOrigin = ExchangeOrigin;
type Polls = AmbassadorReferenda;
type MinRankOfClass = sp_runtime::traits::Identity;
type VoteWeight = pallet_ranked_collective::Linear;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ impl pallet_ranked_collective::Config<FellowshipCollectiveInstance> for Runtime
Replace<ConstU16<{ ranks::DAN_9 }>>,
>,
>;
// Exchange is by any of:
// - Root can exchange arbitrarily.
// - the Fellows origin
type ExchangeOrigin =
EitherOf<EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>, Fellows>;
type Polls = FellowshipReferenda;
type MinRankOfClass = tracks::MinRankOfClass;
type VoteWeight = pallet_ranked_collective::Geometric;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,7 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
.saturating_add(Weight::from_parts(0, 2550).saturating_mul(n.into()))
}
fn exchange_member() -> Weight {
todo!()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,7 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
.saturating_add(Weight::from_parts(0, 2550).saturating_mul(n.into()))
}
fn exchange_member() -> Weight {
todo!()
}
}
5 changes: 5 additions & 0 deletions polkadot/runtime/rococo/src/governance/fellowship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ impl pallet_ranked_collective::Config<FellowshipCollectiveInstance> for Runtime
TryMapSuccess<origins::EnsureFellowship, CheckedReduceBy<ConstU16<2>>>,
>,
>;
// Exchange is by any of:
// - Root can exchange arbitrarily.
// - the Fellows origin;
type ExchangeOrigin =
EitherOf<EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>, Fellows>;
type Polls = FellowshipReferenda;
type MinRankOfClass = sp_runtime::traits::Identity;
type VoteWeight = pallet_ranked_collective::Geometric;
Expand Down
91 changes: 54 additions & 37 deletions polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
//! Autogenerated weights for `pallet_ranked_collective`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2024-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024
//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024

// Executed Command:
// target/production/polkadot
Expand All @@ -29,14 +29,13 @@
// --steps=50
// --repeat=20
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --heap-pages=4096
// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json
// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
// --pallet=pallet_ranked_collective
// --chain=rococo-dev
// --header=./file_header.txt
// --output=./runtime/rococo/src/weights/
// --header=./polkadot/file_header.txt
// --output=./polkadot/runtime/rococo/src/weights/

#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
Expand All @@ -61,8 +60,8 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
// Proof Size summary in bytes:
// Measured: `42`
// Estimated: `3507`
// Minimum execution time: 17_632_000 picoseconds.
Weight::from_parts(18_252_000, 0)
// Minimum execution time: 13_480_000 picoseconds.
Weight::from_parts(13_786_000, 0)
.saturating_add(Weight::from_parts(0, 3507))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
Expand All @@ -71,24 +70,24 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
/// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::MemberCount` (r:11 w:11)
/// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IdToIndex` (r:11 w:11)
/// Storage: `FellowshipCollective::IdToIndex` (r:11 w:22)
/// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IndexToId` (r:11 w:11)
/// Storage: `FellowshipCollective::IndexToId` (r:11 w:22)
/// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 10]`.
fn remove_member(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `517 + r * (281 ±0)`
// Measured: `516 + r * (281 ±0)`
// Estimated: `3519 + r * (2529 ±0)`
// Minimum execution time: 27_960_000 picoseconds.
Weight::from_parts(30_632_408, 0)
// Minimum execution time: 28_771_000 picoseconds.
Weight::from_parts(29_256_825, 0)
.saturating_add(Weight::from_parts(0, 3519))
// Standard Error: 22_806
.saturating_add(Weight::from_parts(13_000_901, 0).saturating_mul(r.into()))
// Standard Error: 21_594
.saturating_add(Weight::from_parts(14_649_527, 0).saturating_mul(r.into()))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into())))
.saturating_add(T::DbWeight::get().writes(4))
.saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into())))
.saturating_add(T::DbWeight::get().writes(6))
.saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into())))
.saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into()))
}
/// Storage: `FellowshipCollective::Members` (r:1 w:1)
Expand All @@ -104,34 +103,34 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
// Proof Size summary in bytes:
// Measured: `214 + r * (17 ±0)`
// Estimated: `3507`
// Minimum execution time: 19_900_000 picoseconds.
Weight::from_parts(20_908_316, 0)
// Minimum execution time: 16_117_000 picoseconds.
Weight::from_parts(16_978_453, 0)
.saturating_add(Weight::from_parts(0, 3507))
// Standard Error: 4_878
.saturating_add(Weight::from_parts(330_385, 0).saturating_mul(r.into()))
// Standard Error: 4_511
.saturating_add(Weight::from_parts(324_261, 0).saturating_mul(r.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: `FellowshipCollective::Members` (r:1 w:1)
/// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::MemberCount` (r:1 w:1)
/// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IdToIndex` (r:1 w:1)
/// Storage: `FellowshipCollective::IdToIndex` (r:1 w:2)
/// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IndexToId` (r:1 w:1)
/// Storage: `FellowshipCollective::IndexToId` (r:1 w:2)
/// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// The range of component `r` is `[0, 10]`.
fn demote_member(r: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `532 + r * (72 ±0)`
// Estimated: `3519`
// Minimum execution time: 27_697_000 picoseconds.
Weight::from_parts(30_341_815, 0)
// Minimum execution time: 28_995_000 picoseconds.
Weight::from_parts(31_343_215, 0)
.saturating_add(Weight::from_parts(0, 3519))
// Standard Error: 17_010
.saturating_add(Weight::from_parts(642_213, 0).saturating_mul(r.into()))
// Standard Error: 16_438
.saturating_add(Weight::from_parts(637_462, 0).saturating_mul(r.into()))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(4))
.saturating_add(T::DbWeight::get().writes(6))
}
/// Storage: `FellowshipCollective::Members` (r:1 w:0)
/// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
Expand All @@ -143,10 +142,10 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
/// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`)
fn vote() -> Weight {
// Proof Size summary in bytes:
// Measured: `638`
// Measured: `603`
// Estimated: `83866`
// Minimum execution time: 48_275_000 picoseconds.
Weight::from_parts(49_326_000, 0)
// Minimum execution time: 38_820_000 picoseconds.
Weight::from_parts(40_240_000, 0)
.saturating_add(Weight::from_parts(0, 83866))
.saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(4))
Expand All @@ -160,16 +159,34 @@ impl<T: frame_system::Config> pallet_ranked_collective::WeightInfo for WeightInf
/// The range of component `n` is `[0, 100]`.
fn cleanup_poll(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `434 + n * (50 ±0)`
// Measured: `400 + n * (50 ±0)`
// Estimated: `4365 + n * (2540 ±0)`
// Minimum execution time: 15_506_000 picoseconds.
Weight::from_parts(17_634_029, 0)
// Minimum execution time: 12_972_000 picoseconds.
Weight::from_parts(15_829_333, 0)
.saturating_add(Weight::from_parts(0, 4365))
// Standard Error: 2_117
.saturating_add(Weight::from_parts(1_126_879, 0).saturating_mul(n.into()))
// Standard Error: 1_754
.saturating_add(Weight::from_parts(1_116_520, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into())))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
.saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into()))
}
/// Storage: `FellowshipCollective::Members` (r:2 w:2)
/// Proof: `FellowshipCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::MemberCount` (r:2 w:2)
/// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IdToIndex` (r:2 w:4)
/// Proof: `FellowshipCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `FellowshipCollective::IndexToId` (r:0 w:2)
/// Proof: `FellowshipCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
fn exchange_member() -> Weight {
// Proof Size summary in bytes:
// Measured: `337`
// Estimated: `6048`
// Minimum execution time: 44_601_000 picoseconds.
Weight::from_parts(45_714_000, 0)
.saturating_add(Weight::from_parts(0, 6048))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(10))
}
}
9 changes: 9 additions & 0 deletions prdoc/pr_2587.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
title: Allow fellowship members to swap their AccountIds.

doc:
- audience: Runtime User
description: |
Add a `exchange_member` extrinsic to the `ranked-collective` pallet that allows to vote on
swapping the AccountId of a member. This can be used to recover lost access to a collective.

crates: [ ]
1 change: 1 addition & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,7 @@ impl pallet_ranked_collective::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type PromoteOrigin = EnsureRootWithSuccess<AccountId, ConstU16<65535>>;
type DemoteOrigin = EnsureRootWithSuccess<AccountId, ConstU16<65535>>;
type ExchangeOrigin = EnsureRootWithSuccess<AccountId, ConstU16<65535>>;
type Polls = RankedPolls;
type MinRankOfClass = traits::Identity;
type VoteWeight = pallet_ranked_collective::Geometric;
Expand Down
15 changes: 15 additions & 0 deletions substrate/frame/ranked-collective/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,20 @@ benchmarks_instance_pallet! {
assert_eq!(Voting::<T, I>::iter().count(), 0);
}

exchange_member {
let who = make_member::<T, I>(1);
let who_lookup = T::Lookup::unlookup(who.clone());
let new_who = account::<T::AccountId>("new-member", 0, SEED);
let new_who_lookup = T::Lookup::unlookup(new_who.clone());
let origin =
T::ExchangeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
let call = Call::<T, I>::exchange_member { who: who_lookup, new_who:new_who_lookup};
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_eq!(Members::<T, I>::get(&new_who).unwrap().rank, 1);
assert_eq!(Members::<T, I>::get(&who), None);
assert_last_event::<T, I>(Event::MemberExchanged { who, new_who }.into());
}

impl_benchmark_test_suite!(RankedCollective, crate::tests::new_test_ext(), crate::tests::Test);
}
Loading

0 comments on commit 5eb4773

Please sign in to comment.