mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 15:18:00 +00:00
Governance: Voters put money where mouth is (#1183)
* Referendums only gett enacted after a delay; successful voters must lock funds up until enactment. * Build fixes. * Configurable council enact delay, fix test builds. * Fix spelling * Remove TODO
This commit is contained in:
+311
-208
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
@@ -91,6 +91,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
launch_period: 5 * MINUTES, // 1 day per public referendum
|
||||
voting_period: 5 * MINUTES, // 3 days to discuss & vote on an active referendum
|
||||
minimum_deposit: 50 * DOLLARS, // 12000 as the minimum deposit for a referendum
|
||||
public_delay: 0,
|
||||
}),
|
||||
council_seats: Some(CouncilSeatsConfig {
|
||||
active_council: vec![],
|
||||
@@ -107,6 +108,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
council_voting: Some(CouncilVotingConfig {
|
||||
cooloff_period: 4 * DAYS,
|
||||
voting_period: 1 * DAYS,
|
||||
enact_delay_period: 0,
|
||||
}),
|
||||
timestamp: Some(TimestampConfig {
|
||||
period: SECS_PER_BLOCK,
|
||||
@@ -210,6 +212,7 @@ pub fn testnet_genesis(
|
||||
launch_period: 9,
|
||||
voting_period: 18,
|
||||
minimum_deposit: 10,
|
||||
public_delay: 0,
|
||||
}),
|
||||
council_seats: Some(CouncilSeatsConfig {
|
||||
active_council: endowed_accounts.iter()
|
||||
@@ -228,6 +231,7 @@ pub fn testnet_genesis(
|
||||
council_voting: Some(CouncilVotingConfig {
|
||||
cooloff_period: 75,
|
||||
voting_period: 20,
|
||||
enact_delay_period: 0,
|
||||
}),
|
||||
timestamp: Some(TimestampConfig {
|
||||
period: 5, // 5 second block time.
|
||||
|
||||
@@ -311,9 +311,9 @@ mod tests {
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
if support_changes_trie {
|
||||
hex!("df90128fe9ee27bd61d90308cc25ad262e518d4ba09e5077558be2389780d8e5").into()
|
||||
hex!("7c00d30974b6d709766e5b231295b6b5ff7ffd42ef1385853c0a29859723d147").into()
|
||||
} else {
|
||||
hex!("3cb0654b6c47c6532108695327fc68e22f2e67a4b20029c3c9d05a285f9e80a2").into()
|
||||
hex!("e96a29fe7f7aba0e4a06837d4a5a4201f60bf613b9947ce5772559ef525f4268").into()
|
||||
},
|
||||
if support_changes_trie {
|
||||
vec![changes_trie_log(
|
||||
@@ -339,7 +339,7 @@ mod tests {
|
||||
construct_block(
|
||||
2,
|
||||
block1(false).1,
|
||||
hex!("612d3e3c542b4ce62105f2f1fbc4fef1652d5ba38401795115042bee56a50752").into(),
|
||||
hex!("80e77e443da5f81fab7265acae6cbdfff79e02eaa90306d9dd14dabddad5f99d").into(),
|
||||
vec![ // session changes here, so we add a grandpa change signal log.
|
||||
Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![
|
||||
(Keyring::One.to_raw_public().into(), 1),
|
||||
@@ -368,7 +368,7 @@ mod tests {
|
||||
construct_block(
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
hex!("17df8f360a4a1bd8d5dc23f05b044f5b14ece43555f97d2058ded47d5e7fb64d").into(),
|
||||
hex!("337c94adf2041fa953d5afaf8919032e3b88ee440c88c48a231856306991dca1").into(),
|
||||
vec![],
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
@@ -658,7 +658,7 @@ mod tests {
|
||||
let b = construct_block(
|
||||
1,
|
||||
GENESIS_HASH.into(),
|
||||
hex!("81f45b36d1c8f667ac948bc48f8fb61d12aae87d841b6303ab0320ca906d01d2").into(),
|
||||
hex!("10cb18e5a4e000690aaa3e2f0165c1cc563d38eb6736aa79c5a0ea4868042671").into(),
|
||||
vec![],
|
||||
vec![
|
||||
CheckedExtrinsic {
|
||||
|
||||
@@ -124,8 +124,8 @@ impl system::Trait for Runtime {
|
||||
impl balances::Trait for Runtime {
|
||||
type Balance = Balance;
|
||||
type AccountIndex = AccountIndex;
|
||||
type OnFreeBalanceZero = (Staking, Contract);
|
||||
type EnsureAccountLiquid = Staking;
|
||||
type OnFreeBalanceZero = ((Staking, Contract), Democracy);
|
||||
type EnsureAccountLiquid = (Staking, Democracy);
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
|
||||
Generated
+328
-225
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
@@ -101,7 +101,16 @@ pub trait EnsureAccountLiquid<AccountId> {
|
||||
/// with the reason why not otherwise.
|
||||
fn ensure_account_liquid(who: &AccountId) -> Result;
|
||||
}
|
||||
|
||||
impl<
|
||||
AccountId,
|
||||
X: EnsureAccountLiquid<AccountId>,
|
||||
Y: EnsureAccountLiquid<AccountId>,
|
||||
> EnsureAccountLiquid<AccountId> for (X, Y) {
|
||||
fn ensure_account_liquid(who: &AccountId) -> Result {
|
||||
X::ensure_account_liquid(who)?;
|
||||
Y::ensure_account_liquid(who)
|
||||
}
|
||||
}
|
||||
impl<AccountId> EnsureAccountLiquid<AccountId> for () {
|
||||
fn ensure_account_liquid(_who: &AccountId) -> Result { Ok(()) }
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ mod tests {
|
||||
launch_period: 1,
|
||||
voting_period: 3,
|
||||
minimum_deposit: 1,
|
||||
public_delay: 0,
|
||||
}.build_storage().unwrap().0);
|
||||
t.extend(seats::GenesisConfig::<Test> {
|
||||
candidacy_bond: 9,
|
||||
@@ -147,6 +148,7 @@ mod tests {
|
||||
t.extend(voting::GenesisConfig::<Test> {
|
||||
cooloff_period: 2,
|
||||
voting_period: 1,
|
||||
enact_delay_period: 0,
|
||||
}.build_storage().unwrap().0);
|
||||
runtime_io::TestExternalities::new(t)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use rstd::prelude::*;
|
||||
use rstd::borrow::Borrow;
|
||||
use codec::HasCompact;
|
||||
use primitives::traits::{Hash, As};
|
||||
use primitives::traits::{Hash, As, Zero};
|
||||
use runtime_io::print;
|
||||
use srml_support::dispatch::Result;
|
||||
use srml_support::{StorageValue, StorageMap, IsSubType};
|
||||
@@ -116,6 +116,8 @@ decl_storage! {
|
||||
trait Store for Module<T: Trait> as CouncilVoting {
|
||||
pub CooloffPeriod get(cooloff_period) config(): T::BlockNumber = T::BlockNumber::sa(1000);
|
||||
pub VotingPeriod get(voting_period) config(): T::BlockNumber = T::BlockNumber::sa(3);
|
||||
/// Number of blocks by which to delay enactment of successful, non-unanimous-council-instigated referendum proposals.
|
||||
pub EnactDelayPeriod get(enact_delay_period) config(): T::BlockNumber = T::BlockNumber::sa(0);
|
||||
pub Proposals get(proposals) build(|_| vec![0u8; 0]): Vec<(T::BlockNumber, T::Hash)>; // ordered by expiry.
|
||||
pub ProposalOf get(proposal_of): map T::Hash => Option<T::Proposal>;
|
||||
pub ProposalVoters get(proposal_voters): map T::Hash => Vec<T::AccountId>;
|
||||
@@ -209,10 +211,18 @@ impl<T: Trait> Module<T> {
|
||||
Self::deposit_event(RawEvent::TallyReferendum(proposal_hash.clone(), tally.0, tally.1, tally.2));
|
||||
if tally.0 > tally.1 + tally.2 {
|
||||
Self::kill_veto_of(&proposal_hash);
|
||||
match tally {
|
||||
(_, 0, 0) => <democracy::Module<T>>::internal_start_referendum(proposal, democracy::VoteThreshold::SuperMajorityAgainst).map(|_| ())?,
|
||||
_ => <democracy::Module<T>>::internal_start_referendum(proposal, democracy::VoteThreshold::SimpleMajority).map(|_| ())?,
|
||||
// If there were no nay-votes from the council, then it's weakly uncontroversial; we enact immediately.
|
||||
let period = match tally.1 {
|
||||
0 => Zero::zero(),
|
||||
_ => Self::enact_delay_period(),
|
||||
};
|
||||
// If all council members voted yes, then it's strongly uncontroversial; we require a negative
|
||||
// super-majority at referendum in order to defeat it.
|
||||
let threshold = match tally {
|
||||
(_, 0, 0) => democracy::VoteThreshold::SuperMajorityAgainst,
|
||||
_ => democracy::VoteThreshold::SimpleMajority,
|
||||
};
|
||||
<democracy::Module<T>>::internal_start_referendum(proposal, threshold, period).map(|_| ())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,8 +271,8 @@ mod tests {
|
||||
with_externalities(&mut new_test_ext(true), || {
|
||||
System::set_block_number(1);
|
||||
let proposal = set_balance_proposal(42);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove), 0);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove, 0), 0);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove, 0)]);
|
||||
|
||||
let cancellation = cancel_referendum_proposal(0);
|
||||
let hash = cancellation.blake2_256().into();
|
||||
@@ -284,7 +294,7 @@ mod tests {
|
||||
with_externalities(&mut new_test_ext(true), || {
|
||||
System::set_block_number(1);
|
||||
let proposal = set_balance_proposal(42);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove), 0);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove, 0), 0);
|
||||
|
||||
let cancellation = cancel_referendum_proposal(0);
|
||||
let hash = cancellation.blake2_256().into();
|
||||
@@ -295,7 +305,7 @@ mod tests {
|
||||
|
||||
System::set_block_number(2);
|
||||
assert_ok!(CouncilVoting::end_block(System::block_number()));
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove, 0)]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -304,7 +314,7 @@ mod tests {
|
||||
with_externalities(&mut new_test_ext(true), || {
|
||||
System::set_block_number(1);
|
||||
let proposal = set_balance_proposal(42);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove), 0);
|
||||
assert_ok!(Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove, 0), 0);
|
||||
|
||||
let cancellation = cancel_referendum_proposal(0);
|
||||
let hash = cancellation.blake2_256().into();
|
||||
@@ -314,7 +324,7 @@ mod tests {
|
||||
|
||||
System::set_block_number(2);
|
||||
assert_ok!(CouncilVoting::end_block(System::block_number()));
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove, 0)]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -378,7 +388,7 @@ mod tests {
|
||||
System::set_block_number(4);
|
||||
assert_ok!(CouncilVoting::end_block(System::block_number()));
|
||||
assert_eq!(CouncilVoting::proposals().len(), 0);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 7, set_balance_proposal(42), VoteThreshold::SimpleMajority)]);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 7, set_balance_proposal(42), VoteThreshold::SimpleMajority, 0)]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -443,7 +453,7 @@ mod tests {
|
||||
System::set_block_number(2);
|
||||
assert_ok!(CouncilVoting::end_block(System::block_number()));
|
||||
assert_eq!(CouncilVoting::proposals().len(), 0);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SuperMajorityAgainst)]);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SuperMajorityAgainst, 0)]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -461,7 +471,7 @@ mod tests {
|
||||
System::set_block_number(2);
|
||||
assert_ok!(CouncilVoting::end_block(System::block_number()));
|
||||
assert_eq!(CouncilVoting::proposals().len(), 0);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SimpleMajority)]);
|
||||
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SimpleMajority, 0)]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -109,11 +109,12 @@ decl_module! {
|
||||
}
|
||||
|
||||
/// Start a referendum.
|
||||
fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result {
|
||||
fn start_referendum(proposal: Box<T::Proposal>, threshold: VoteThreshold, delay: T::BlockNumber) -> Result {
|
||||
Self::inject_referendum(
|
||||
<system::Module<T>>::block_number() + Self::voting_period(),
|
||||
*proposal,
|
||||
vote_threshold
|
||||
threshold,
|
||||
delay,
|
||||
).map(|_| ())
|
||||
}
|
||||
|
||||
@@ -122,6 +123,13 @@ decl_module! {
|
||||
Self::clear_referendum(ref_index.into());
|
||||
}
|
||||
|
||||
/// Cancel a proposal queued for enactment.
|
||||
pub fn cancel_queued(when: T::BlockNumber, which: u32) -> Result {
|
||||
let which = which as usize;
|
||||
<DispatchQueue<T>>::mutate(when, |items| if items.len() > which { items[which] = None });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_finalise(n: T::BlockNumber) {
|
||||
if let Err(e) = Self::end_block(n) {
|
||||
runtime_io::print(e);
|
||||
@@ -130,6 +138,20 @@ decl_module! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Info regarding an ongoing referendum.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct ReferendumInfo<BlockNumber: Parameter, Proposal: Parameter> {
|
||||
/// When voting on this referendum will end.
|
||||
end: BlockNumber,
|
||||
/// The proposal being voted on.
|
||||
proposal: Proposal,
|
||||
/// The thresholding mechanism to determine whether it passed.
|
||||
threshold: VoteThreshold,
|
||||
/// The delay (in blocks) to wait after a successful referendum before deploying.
|
||||
delay: BlockNumber,
|
||||
}
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as Democracy {
|
||||
|
||||
@@ -143,6 +165,8 @@ decl_storage! {
|
||||
pub LaunchPeriod get(launch_period) config(): T::BlockNumber = T::BlockNumber::sa(1000);
|
||||
/// The minimum amount to be used as a deposit for a public referendum proposal.
|
||||
pub MinimumDeposit get(minimum_deposit) config(): T::Balance;
|
||||
/// The delay before enactment for all public referenda.
|
||||
pub PublicDelay get(public_delay) config(): T::BlockNumber;
|
||||
|
||||
/// How often (in blocks) to check for new votes.
|
||||
pub VotingPeriod get(voting_period) config(): T::BlockNumber = T::BlockNumber::sa(1000);
|
||||
@@ -152,7 +176,12 @@ decl_storage! {
|
||||
/// The next referendum index that should be tallied.
|
||||
pub NextTally get(next_tally) build(|_| 0 as ReferendumIndex): ReferendumIndex;
|
||||
/// Information concerning any given referendum.
|
||||
pub ReferendumInfoOf get(referendum_info): map ReferendumIndex => Option<(T::BlockNumber, T::Proposal, VoteThreshold)>;
|
||||
pub ReferendumInfoOf get(referendum_info): map ReferendumIndex => Option<(ReferendumInfo<T::BlockNumber, T::Proposal>)>;
|
||||
/// Queue of successful referenda to be dispatched.
|
||||
pub DispatchQueue get(dispatch_queue): map T::BlockNumber => Vec<Option<(T::Proposal, ReferendumIndex)>>;
|
||||
|
||||
/// The block at which the `who`'s funds become liquid.
|
||||
pub Bondage get(bondage): map T::AccountId => T::BlockNumber;
|
||||
|
||||
/// Get the voters for the current proposal.
|
||||
pub VotersFor get(voters_for): map ReferendumIndex => Vec<T::AccountId>;
|
||||
@@ -189,21 +218,21 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
|
||||
/// Get all referendums currently active.
|
||||
pub fn active_referendums() -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold)> {
|
||||
pub fn active_referendums() -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold, T::BlockNumber)> {
|
||||
let next = Self::next_tally();
|
||||
let last = Self::referendum_count();
|
||||
(next..last).into_iter()
|
||||
.filter_map(|i| Self::referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
|
||||
.filter_map(|i| Self::referendum_info(i).map(|ReferendumInfo{ end, proposal, threshold, delay }| (i, end, proposal, threshold, delay)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get all referendums ready for tally at block `n`.
|
||||
pub fn maturing_referendums_at(n: T::BlockNumber) -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold)> {
|
||||
pub fn maturing_referendums_at(n: T::BlockNumber) -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold, T::BlockNumber)> {
|
||||
let next = Self::next_tally();
|
||||
let last = Self::referendum_count();
|
||||
(next..last).into_iter()
|
||||
.filter_map(|i| Self::referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
|
||||
.take_while(|&(_, block_number, _, _)| block_number == n)
|
||||
.filter_map(|i| Self::referendum_info(i).map(|ReferendumInfo{ end, proposal, threshold, delay }| (i, end, proposal, threshold, delay)))
|
||||
.take_while(|&(_, block_number, _, _, _)| block_number == n)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -218,8 +247,8 @@ impl<T: Trait> Module<T> {
|
||||
// Exposed mutables.
|
||||
|
||||
/// Start a referendum. Can be called directly by the council.
|
||||
pub fn internal_start_referendum(proposal: T::Proposal, vote_threshold: VoteThreshold) -> result::Result<ReferendumIndex, &'static str> {
|
||||
<Module<T>>::inject_referendum(<system::Module<T>>::block_number() + <Module<T>>::voting_period(), proposal, vote_threshold)
|
||||
pub fn internal_start_referendum(proposal: T::Proposal, threshold: VoteThreshold, delay: T::BlockNumber) -> result::Result<ReferendumIndex, &'static str> {
|
||||
<Module<T>>::inject_referendum(<system::Module<T>>::block_number() + <Module<T>>::voting_period(), proposal, threshold, delay)
|
||||
}
|
||||
|
||||
/// Remove a referendum. Can be called directly by the council.
|
||||
@@ -234,16 +263,17 @@ impl<T: Trait> Module<T> {
|
||||
fn inject_referendum(
|
||||
end: T::BlockNumber,
|
||||
proposal: T::Proposal,
|
||||
vote_threshold: VoteThreshold
|
||||
threshold: VoteThreshold,
|
||||
delay: T::BlockNumber,
|
||||
) -> result::Result<ReferendumIndex, &'static str> {
|
||||
let ref_index = Self::referendum_count();
|
||||
if ref_index > 0 && Self::referendum_info(ref_index - 1).map(|i| i.0 > end).unwrap_or(false) {
|
||||
if ref_index > 0 && Self::referendum_info(ref_index - 1).map(|i| i.end > end).unwrap_or(false) {
|
||||
Err("Cannot inject a referendum that ends earlier than preceeding referendum")?
|
||||
}
|
||||
|
||||
<ReferendumCount<T>>::put(ref_index + 1);
|
||||
<ReferendumInfoOf<T>>::insert(ref_index, (end, proposal, vote_threshold));
|
||||
Self::deposit_event(RawEvent::Started(ref_index, vote_threshold));
|
||||
<ReferendumInfoOf<T>>::insert(ref_index, ReferendumInfo { end, proposal, threshold, delay });
|
||||
Self::deposit_event(RawEvent::Started(ref_index, threshold));
|
||||
Ok(ref_index)
|
||||
}
|
||||
|
||||
@@ -256,6 +286,12 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enact a proposal from a referendum.
|
||||
fn enact_proposal(proposal: T::Proposal, index: ReferendumIndex) {
|
||||
let ok = proposal.dispatch(system::RawOrigin::Root.into()).is_ok();
|
||||
Self::deposit_event(RawEvent::Executed(index, ok));
|
||||
}
|
||||
|
||||
/// Current era is ending; we should finish up any proposals.
|
||||
fn end_block(now: T::BlockNumber) -> Result {
|
||||
// pick out another public referendum if it's time.
|
||||
@@ -274,29 +310,58 @@ impl<T: Trait> Module<T> {
|
||||
<balances::Module<T>>::unreserve(d, deposit);
|
||||
}
|
||||
Self::deposit_event(RawEvent::Tabled(prop_index, deposit, depositors));
|
||||
Self::inject_referendum(now + Self::voting_period(), proposal, VoteThreshold::SuperMajorityApprove)?;
|
||||
Self::inject_referendum(now + Self::voting_period(), proposal, VoteThreshold::SuperMajorityApprove, Self::public_delay())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tally up votes for any expiring referenda.
|
||||
for (index, _, proposal, vote_threshold) in Self::maturing_referendums_at(now) {
|
||||
for (index, _, proposal, threshold, delay) in Self::maturing_referendums_at(now) {
|
||||
let (approve, against) = Self::tally(index);
|
||||
let total_issuance = <balances::Module<T>>::total_issuance();
|
||||
let approved = threshold.approved(approve, against, total_issuance);
|
||||
|
||||
Self::voters_for(index).into_iter()
|
||||
.filter(|a| (Self::vote_of((index, a.clone())).unwrap_or(false)/*defensive only: all items come from `voters`; for an item to be in `voters` there must be a vote registered; qed*/ == approved))
|
||||
.for_each(|a| <Bondage<T>>::mutate(a, |b| if *b < now + delay { *b = now + delay }));
|
||||
|
||||
Self::clear_referendum(index);
|
||||
if vote_threshold.approved(approve, against, total_issuance) {
|
||||
if approved {
|
||||
Self::deposit_event(RawEvent::Passed(index));
|
||||
let ok = proposal.dispatch(system::RawOrigin::Root.into()).is_ok();
|
||||
Self::deposit_event(RawEvent::Executed(index, ok));
|
||||
if delay.is_zero() {
|
||||
Self::enact_proposal(proposal, index);
|
||||
} else {
|
||||
<DispatchQueue<T>>::mutate(now + delay, |q| q.push(Some((proposal, index))));
|
||||
}
|
||||
} else {
|
||||
Self::deposit_event(RawEvent::NotPassed(index));
|
||||
}
|
||||
<NextTally<T>>::put(index + 1);
|
||||
}
|
||||
|
||||
for (proposal, index) in <DispatchQueue<T>>::take(now).into_iter().filter_map(|x| x) {
|
||||
Self::enact_proposal(proposal, index);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> balances::OnFreeBalanceZero<T::AccountId> for Module<T> {
|
||||
fn on_free_balance_zero(who: &T::AccountId) {
|
||||
<Bondage<T>>::remove(who);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> balances::EnsureAccountLiquid<T::AccountId> for Module<T> {
|
||||
fn ensure_account_liquid(who: &T::AccountId) -> Result {
|
||||
if Self::bondage(who) <= <system::Module<T>>::block_number() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("cannot transfer illiquid funds")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -359,6 +424,7 @@ mod tests {
|
||||
launch_period: 1,
|
||||
voting_period: 1,
|
||||
minimum_deposit: 1,
|
||||
public_delay: 0,
|
||||
}.build_storage().unwrap().0);
|
||||
runtime_io::TestExternalities::new(t)
|
||||
}
|
||||
@@ -507,7 +573,7 @@ mod tests {
|
||||
fn simple_passing_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(1), r.into(), true));
|
||||
|
||||
assert_eq!(Democracy::voters_for(r), vec![1]);
|
||||
@@ -524,7 +590,7 @@ mod tests {
|
||||
fn cancel_referendum_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(1), r.into(), true));
|
||||
assert_ok!(Democracy::cancel_referendum(r.into()));
|
||||
|
||||
@@ -538,7 +604,7 @@ mod tests {
|
||||
fn simple_failing_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(1), r.into(), false));
|
||||
|
||||
assert_eq!(Democracy::voters_for(r), vec![1]);
|
||||
@@ -555,7 +621,7 @@ mod tests {
|
||||
fn controversial_voting_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(1), r.into(), true));
|
||||
assert_ok!(Democracy::vote(Origin::signed(2), r.into(), false));
|
||||
assert_ok!(Democracy::vote(Origin::signed(3), r.into(), false));
|
||||
@@ -575,7 +641,7 @@ mod tests {
|
||||
fn controversial_low_turnout_voting_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(5), r.into(), false));
|
||||
assert_ok!(Democracy::vote(Origin::signed(6), r.into(), true));
|
||||
|
||||
@@ -594,7 +660,7 @@ mod tests {
|
||||
assert_eq!(Balances::total_issuance(), 210);
|
||||
|
||||
System::set_block_number(1);
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
|
||||
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0).unwrap();
|
||||
assert_ok!(Democracy::vote(Origin::signed(4), r.into(), true));
|
||||
assert_ok!(Democracy::vote(Origin::signed(5), r.into(), false));
|
||||
assert_ok!(Democracy::vote(Origin::signed(6), r.into(), true));
|
||||
|
||||
@@ -63,13 +63,8 @@ use runtime_support::storage::unhashed::StorageVec;
|
||||
use primitives::traits::{CurrentHeight, Convert};
|
||||
use substrate_primitives::AuthorityId;
|
||||
use system::ensure_signed;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::traits::MaybeSerializeDebug;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use primitives::traits::MaybeSerializeDebugButNotDeserialize;
|
||||
|
||||
mod mock;
|
||||
mod tests;
|
||||
|
||||
@@ -128,11 +123,6 @@ pub trait Trait: system::Trait {
|
||||
type Log: From<Log<Self>> + Into<system::DigestItemOf<Self>>;
|
||||
|
||||
/// The session key type used by authorities.
|
||||
#[cfg(not(feature = "std"))]
|
||||
type SessionKey: Parameter + Default + MaybeSerializeDebugButNotDeserialize;
|
||||
|
||||
/// The session key type used by authorities.
|
||||
#[cfg(feature = "std")]
|
||||
type SessionKey: Parameter + Default + MaybeSerializeDebug;
|
||||
|
||||
/// The event type of this module.
|
||||
|
||||
Reference in New Issue
Block a user