From 37ed154535598cc59bc02bb1a14174ca50193eb5 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 5 Dec 2019 16:57:25 +0100 Subject: [PATCH] Allow members of groups to change their key (#4300) --- substrate/frame/membership/src/lib.rs | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index d18c107d66..acecd456ee 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -28,7 +28,7 @@ use support::{ traits::{ChangeMembers, InitializeMembers}, weights::SimpleDispatchInfo, }; -use system::ensure_root; +use system::{ensure_root, ensure_signed}; use sp_runtime::traits::EnsureOrigin; pub trait Trait: system::Trait { @@ -86,6 +86,8 @@ decl_event!( MembersSwapped, /// The membership was reset; see the transaction for who the new set is. MembersReset, + /// One of the members' keys changed. + KeyChanged, /// Phantom member, never used. Dummy(rstd::marker::PhantomData<(AccountId, Event)>), } @@ -186,6 +188,31 @@ decl_module! { Self::deposit_event(RawEvent::MembersReset); } + + /// Swap out the sending member for some other key `new`. + /// + /// May only be called from `Signed` origin of a current member. + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn change_key(origin, new: T::AccountId) { + let remove = ensure_signed(origin)?; + + if remove != new { + let mut members = >::get(); + let location = members.binary_search(&remove).ok().ok_or("not a member")?; + members[location] = new.clone(); + let _location = members.binary_search(&new).err().ok_or("already a member")?; + members.sort(); + >::put(&members); + + T::MembershipChanged::change_members_sorted( + &[new], + &[remove], + &members[..], + ); + } + + Self::deposit_event(RawEvent::KeyChanged); + } } } @@ -333,6 +360,17 @@ mod tests { }); } + #[test] + fn change_key_works() { + new_test_ext().execute_with(|| { + assert_noop!(Membership::change_key(Origin::signed(3), 25), "not a member"); + assert_noop!(Membership::change_key(Origin::signed(10), 20), "already a member"); + assert_ok!(Membership::change_key(Origin::signed(10), 40)); + assert_eq!(Membership::members(), vec![20, 30, 40]); + assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members()); + }); + } + #[test] fn reset_members_works() { new_test_ext().execute_with(|| {