diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs index 82aecc8557..de0ef3a5d7 100644 --- a/substrate/frame/democracy/src/lib.rs +++ b/substrate/frame/democracy/src/lib.rs @@ -276,8 +276,9 @@ decl_storage! { /// The next free referendum index, aka the number of referenda started so far. pub ReferendumCount get(fn referendum_count) build(|_| 0 as ReferendumIndex): ReferendumIndex; - /// The next referendum index that should be tallied. - pub NextTally get(fn next_tally) build(|_| 0 as ReferendumIndex): ReferendumIndex; + /// The lowest referendum index representing an unbaked referendum. Equal to + /// `ReferendumCount` if there isn't a unbaked referendum. + pub LowestUnbaked get(fn lowest_unbaked) build(|_| 0 as ReferendumIndex): ReferendumIndex; /// Information concerning any given referendum. pub ReferendumInfoOf get(fn referendum_info): map ReferendumIndex => Option<(ReferendumInfo)>; @@ -541,7 +542,7 @@ decl_module! { let now = >::block_number(); // We don't consider it an error if `vote_period` is too low, like `emergency_propose`. let period = voting_period.max(T::EmergencyVotingPeriod::get()); - Self::inject_referendum(now + period, proposal_hash, threshold, delay).map(|_| ())?; + Self::inject_referendum(now + period, proposal_hash, threshold, delay); } /// Veto and blacklist the external proposal hash. @@ -763,7 +764,7 @@ impl Module { pub fn active_referenda() -> Vec<(ReferendumIndex, ReferendumInfo)> { - let next = Self::next_tally(); + let next = Self::lowest_unbaked(); let last = Self::referendum_count(); (next..last).into_iter() .filter_map(|i| Self::referendum_info(i).map(|info| (i, info))) @@ -774,11 +775,11 @@ impl Module { pub fn maturing_referenda_at( n: T::BlockNumber ) -> Vec<(ReferendumIndex, ReferendumInfo)> { - let next = Self::next_tally(); + let next = Self::lowest_unbaked(); let last = Self::referendum_count(); (next..last).into_iter() .filter_map(|i| Self::referendum_info(i).map(|info| (i, info))) - .take_while(|&(_, ref info)| info.end == n) + .filter(|&(_, ref info)| info.end == n) .collect() } @@ -867,7 +868,7 @@ impl Module { proposal_hash: T::Hash, threshold: VoteThreshold, delay: T::BlockNumber - ) -> result::Result { + ) -> ReferendumIndex { >::inject_referendum( >::block_number() + T::VotingPeriod::get(), proposal_hash, @@ -900,26 +901,26 @@ impl Module { proposal_hash: T::Hash, threshold: VoteThreshold, delay: T::BlockNumber, - ) -> result::Result { + ) -> ReferendumIndex { let ref_index = Self::referendum_count(); - if ref_index.checked_sub(1) - .and_then(Self::referendum_info) - .map(|i| i.end > end) - .unwrap_or(false) - { - Err("Cannot inject a referendum that ends earlier than preceeding referendum")? - } - ReferendumCount::put(ref_index + 1); let item = ReferendumInfo { end, proposal_hash, threshold, delay }; >::insert(ref_index, item); Self::deposit_event(RawEvent::Started(ref_index, threshold)); - Ok(ref_index) + ref_index } /// Remove all info on a referendum. fn clear_referendum(ref_index: ReferendumIndex) { >::remove(ref_index); + + LowestUnbaked::mutate(|i| if *i == ref_index { + *i += 1; + let end = ReferendumCount::get(); + while !Self::is_active_referendum(*i) && *i < end { + *i += 1; + } + }); >::remove(ref_index); for v in Self::voters_for(ref_index) { >::remove((ref_index, v)); @@ -967,7 +968,7 @@ impl Module { proposal, threshold, T::EnactmentPeriod::get(), - )?; + ); Ok(()) } else { Err("No external proposal waiting") @@ -996,7 +997,7 @@ impl Module { proposal, VoteThreshold::SuperMajorityApprove, T::EnactmentPeriod::get(), - )?; + ); } Ok(()) } else { @@ -1037,6 +1038,7 @@ impl Module { } Self::clear_referendum(index); + if approved { Self::deposit_event(RawEvent::Passed(index)); if info.delay.is_zero() { @@ -1050,7 +1052,6 @@ impl Module { } else { Self::deposit_event(RawEvent::NotPassed(index)); } - NextTally::put(index + 1); Ok(()) } @@ -1277,7 +1278,7 @@ mod tests { set_balance_proposal_hash(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); next_block(); @@ -1304,7 +1305,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); assert_eq!(Balances::reserved_balance(6), 12); @@ -1329,7 +1330,7 @@ mod tests { set_balance_proposal_hash(2), VoteThreshold::SuperMajorityApprove, 1 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); assert_noop!( @@ -1470,7 +1471,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 2 - ).unwrap(); + ); assert!(Democracy::referendum_info(r).is_some()); assert_noop!(Democracy::emergency_cancel(Origin::signed(3), r), "Invalid origin"); @@ -1484,7 +1485,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 2 - ).unwrap(); + ); assert!(Democracy::referendum_info(r).is_some()); assert_noop!(Democracy::emergency_cancel(Origin::signed(4), r), "cannot cancel the same proposal twice"); }); @@ -2013,6 +2014,41 @@ mod tests { }); } + #[test] + fn ooo_inject_referendums_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let r1 = Democracy::inject_referendum( + 3, + set_balance_proposal_hash_and_note(3), + VoteThreshold::SuperMajorityApprove, + 0 + ); + let r2 = Democracy::inject_referendum( + 2, + set_balance_proposal_hash_and_note(2), + VoteThreshold::SuperMajorityApprove, + 0 + ); + + assert_ok!(Democracy::vote(Origin::signed(1), r2, AYE)); + assert_eq!(Democracy::voters_for(r2), vec![1]); + assert_eq!(Democracy::vote_of((r2, 1)), AYE); + assert_eq!(Democracy::tally(r2), (1, 0, 1)); + + next_block(); + assert_eq!(Balances::free_balance(&42), 2); + + assert_ok!(Democracy::vote(Origin::signed(1), r1, AYE)); + assert_eq!(Democracy::voters_for(r1), vec![1]); + assert_eq!(Democracy::vote_of((r1, 1)), AYE); + assert_eq!(Democracy::tally(r1), (1, 0, 1)); + + next_block(); + assert_eq!(Balances::free_balance(&42), 3); + }); + } + #[test] fn simple_passing_should_work() { new_test_ext().execute_with(|| { @@ -2022,7 +2058,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); assert_eq!(Democracy::voters_for(r), vec![1]); @@ -2045,7 +2081,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); assert_ok!(Democracy::cancel_referendum(Origin::ROOT, r.into())); @@ -2065,7 +2101,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, NAY)); assert_eq!(Democracy::voters_for(r), vec![1]); @@ -2088,7 +2124,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, BIG_AYE)); assert_ok!(Democracy::vote(Origin::signed(2), r, BIG_NAY)); @@ -2115,7 +2151,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 1 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, AYE)); assert_ok!(Democracy::vote(Origin::signed(2), r, AYE)); assert_ok!(Democracy::vote(Origin::signed(3), r, AYE)); @@ -2143,7 +2179,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(5), r, BIG_NAY)); assert_ok!(Democracy::vote(Origin::signed(6), r, BIG_AYE)); @@ -2168,7 +2204,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(4), r, BIG_AYE)); assert_ok!(Democracy::vote(Origin::signed(5), r, BIG_NAY)); assert_ok!(Democracy::vote(Origin::signed(6), r, BIG_AYE)); @@ -2191,7 +2227,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, Vote { aye: false, conviction: Conviction::Locked5x @@ -2251,7 +2287,7 @@ mod tests { set_balance_proposal_hash_and_note(2), VoteThreshold::SuperMajorityApprove, 0 - ).unwrap(); + ); assert_ok!(Democracy::vote(Origin::signed(1), r, Vote { aye: false, conviction: Conviction::Locked5x