diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index e884f81ce487314dcb81f4c351740209b4085d48..e402e8d8c16fe114e659746cde05916586ae80f2 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -62,6 +62,16 @@ //! These skeptics are expected to vote on the current candidates. If they do not vote, //! their skeptic status is treated as a rejection vote, the member is deemed //! "lazy", and are given a strike per missing vote. +//! +//! #### Membership Challenges +//! +//! Every challenge rotation period, an existing member will be randomly selected +//! to defend their membership into society. Then, other members can vote whether +//! this defender should stay in society. A simple majority wins vote will determine +//! the outcome of the user. Ties are treated as a failure of the challenge, but +//! assuming no one else votes, the defender always get a free vote on their +//! own challenge keeping them in the society. The Head member is exempt from the +//! negative outcome of a membership challenge. //! //! #### Society Treasury //! @@ -193,6 +203,7 @@ //! There is a challenge period in parallel to the rotation period. During a challenge period, //! a random member is selected to defend their membership to the society. Other members //! make a traditional majority-wins vote to determine if the member should stay in the society. +//! Ties are treated as a failure of the challenge. //! //! If a member accumulates too many strikes or fails their membership challenge, //! they will become suspended. While a member is suspended, they are unable to @@ -1431,7 +1442,7 @@ impl<T: Trait<I>, I: Instance> Module<T, I> { } }); - if approval_count < rejection_count { + if approval_count <= rejection_count { // User has failed the challenge Self::suspend_member(&defender); *members = Self::members(); diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 930fbdf927a3ac8fc969e613e998725d774e87ca..61bb1fd232cc0cd84123300d7078bbdda2ce94a8 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -102,6 +102,7 @@ fn bidding_works() { assert_eq!(Balances::free_balance(Society::account_id()), 8_800); // No more candidates satisfy the requirements assert_eq!(Society::candidates(), vec![]); + assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around // Next period run_to_block(16); // Same members @@ -480,6 +481,7 @@ fn head_cannot_be_removed() { assert_ok!(Society::bid(Origin::signed(50), 0)); run_to_block(28); assert_ok!(Society::vote(Origin::signed(10), 50, true)); + assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around run_to_block(32); assert_eq!(Society::members(), vec![10, 50]); assert_eq!(Society::head(), Some(50)); @@ -509,25 +511,27 @@ fn challenges_work() { // 20 will be challenged during the challenge rotation run_to_block(8); assert_eq!(Society::defender(), Some(20)); - // If no one votes, nothing happens + // They can always free vote for themselves + assert_ok!(Society::defender_vote(Origin::signed(20), true)); + // If no one else votes, nothing happens run_to_block(16); assert_eq!(Society::members(), vec![10, 20, 30, 40]); // New challenge period assert_eq!(Society::defender(), Some(20)); // Non-member cannot challenge assert_noop!(Society::defender_vote(Origin::signed(1), true), Error::<Test, _>::NotMember); - // 2 people say accept, 2 reject + // 3 people say accept, 1 reject assert_ok!(Society::defender_vote(Origin::signed(10), true)); assert_ok!(Society::defender_vote(Origin::signed(20), true)); - assert_ok!(Society::defender_vote(Origin::signed(30), false)); + assert_ok!(Society::defender_vote(Origin::signed(30), true)); assert_ok!(Society::defender_vote(Origin::signed(40), false)); run_to_block(24); // 20 survives assert_eq!(Society::members(), vec![10, 20, 30, 40]); // One more time assert_eq!(Society::defender(), Some(20)); - // 3 people reject - assert_ok!(Society::defender_vote(Origin::signed(10), false)); + // 2 people say accept, 2 reject + assert_ok!(Society::defender_vote(Origin::signed(10), true)); assert_ok!(Society::defender_vote(Origin::signed(20), true)); assert_ok!(Society::defender_vote(Origin::signed(30), false)); assert_ok!(Society::defender_vote(Origin::signed(40), false));