Skip to content

Commit

Permalink
Merge pull request #333 from liberland/BLOCKCHAIN-176-fees-for-propos…
Browse files Browse the repository at this point in the history
…ing-referenda

BLOCKCHAIN-176 Added proposal fee and updated tests
  • Loading branch information
DorianSternVukotic authored Nov 17, 2023
2 parents 71d4a16 + b2981df commit 760a27d
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 47 deletions.
4 changes: 4 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ parameter_types! {
pub const MinimumDeposit: Balance = 10 * GRAINS_IN_LLM;
pub const CooloffPeriod: BlockNumber = 7 * DAYS;
pub const MaxProposals: u32 = 100;
pub const ProposalFeeAmount: Balance = 100 * DOLLARS;
}

impl pallet_democracy::Config for Runtime {
Expand Down Expand Up @@ -870,6 +871,9 @@ impl pallet_democracy::Config for Runtime {
type MaxDeposits = ConstU32<100>;
type MaxBlacklisted = ConstU32<100>;
type DelegateeFilter = ContainsMember<Runtime, CouncilCollective>;

type ProposalFee = Treasury;
type ProposalFeeAmount = ProposalFeeAmount;
}

parameter_types! {
Expand Down
16 changes: 14 additions & 2 deletions frame/democracy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ use frame_support::{
schedule::{v3::Named as ScheduleNamed, DispatchTime},
Bounded, Currency, Get, Hash as PreimageHash, LockIdentifier, LockableCurrency, QueryPreimage,
ReservableCurrency, StorePreimage,
Contains,
Contains, OnUnbalanced, tokens::{ExistenceRequirement, WithdrawReasons}
},
pallet_prelude::{MaxEncodedLen, TypeInfo},
BoundedVec,
Expand Down Expand Up @@ -322,6 +322,9 @@ pub mod pallet {
#[pallet::constant]
type MaxAdditionalFields: Get<u32>;

#[pallet::constant]
type ProposalFeeAmount: Get<BalanceOf<Self>>;

/// Origin from which the next tabled referendum may be forced; this allows for the tabling
/// of a negative-turnout-bias (default-carries) referendum.
type ExternalDefaultOrigin: EnsureOrigin<Self::RuntimeOrigin>;
Expand Down Expand Up @@ -360,6 +363,8 @@ pub mod pallet {
type LLM: LLM<Self::AccountId, BalanceOf<Self>>;
type DelegateeFilter: Contains<Self::AccountId>;
type LLInitializer: LLInitializer<Self::AccountId>;

type ProposalFee: OnUnbalanced<<<Self as Config>::Currency as Currency<<Self as frame_system::Config>::AccountId>>::NegativeImbalance>;
}

/// The number of (public) proposals that have been made so far.
Expand Down Expand Up @@ -1237,7 +1242,14 @@ impl<T: Config> Pallet<T> {
fn do_propose(who: T::AccountId, proposal: BoundedCallOf<T>, value: BalanceOf<T>, dispatch_origin: DispatchOrigin) -> DispatchResult {
T::Citizenship::ensure_politics_allowed(&who)?;

ensure!(value >= T::MinimumDeposit::get(), Error::<T>::ValueLow);
T::ProposalFee::on_unbalanced(
T::Currency::withdraw(
&who,
T::ProposalFeeAmount::get(),
WithdrawReasons::FEE,
ExistenceRequirement::KeepAlive
)?
);

let index = Self::public_prop_count();
let real_prop_count = PublicProps::<T>::decode_len().unwrap_or(0) as u32;
Expand Down
7 changes: 5 additions & 2 deletions frame/democracy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,13 @@ impl Config for Test {
type LLM = LLM;
type LLInitializer = LiberlandInitializer;
type DelegateeFilter = Everything;
type ProposalFee = ();
type ProposalFeeAmount = ConstU64<10>;
}

pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
let balances = vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let balances = vec![(1, 100), (2, 200), (3, 300), (4, 400), (5, 500), (6, 600)];
let mut llm_balances: Vec<(u64, u64, u64)> = balances.iter().map(|(id, _)| (*id, 6000, 5000)).collect();
llm_balances.push((7, 1000, 1000));

Expand Down Expand Up @@ -358,7 +360,7 @@ fn params_should_work() {
new_test_ext().execute_with(|| {
assert_eq!(Democracy::referendum_count(), 0);
assert_eq!(Balances::free_balance(42), 0);
assert_eq!(Balances::total_issuance(), 210);
assert_eq!(Balances::total_issuance(), 2100);
});
}

Expand Down Expand Up @@ -394,6 +396,7 @@ fn fast_forward_to(n: u64) {

fn begin_referendum() -> ReferendumIndex {
System::set_block_number(0);
Balances::make_free_balance_be(&1, 100);
assert_ok!(propose_set_balance(1, 2, 1));
fast_forward_to(2);
0
Expand Down
27 changes: 13 additions & 14 deletions frame/democracy/src/tests/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ fn single_proposal_should_work_with_delegation() {
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
let r = 0;
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0 });

// Delegate a second vote.
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 1, Conviction::None, 30));
assert_eq!(tally(r), Tally { ayes: 60, nays: 0, turnout: 60, aye_voters: 30000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 140, nays: 0, turnout: 140, aye_voters: 30000, nay_voters: 0 });

// Reduce first vote.
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 10));
assert_eq!(tally(r), Tally { ayes: 50, nays: 0, turnout: 50, aye_voters: 30000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 130, nays: 0, turnout: 130, aye_voters: 30000, nay_voters: 0 });

// Second vote delegates to first; we don't do tiered delegation, so it doesn't get used.
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30));
assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 20000, nay_voters: 0 });

// Main voter cancels their vote
assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r));
Expand All @@ -60,7 +60,7 @@ fn single_proposal_should_work_with_delegation() {

// Main voter reinstates their vote
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 20000, nay_voters: 0 });
});
}

Expand All @@ -78,7 +78,6 @@ fn self_delegation_not_allowed() {
fn cyclic_delegation_should_unwind() {
new_test_ext().execute_with(|| {
System::set_block_number(0);

assert_ok!(propose_set_balance(1, 2, 1));

fast_forward_to(2);
Expand All @@ -94,7 +93,7 @@ fn cyclic_delegation_should_unwind() {
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1)));

// Delegated vote is counted.
assert_eq!(tally(r), Tally { ayes: 30, nays: 30, turnout: 60, aye_voters: 10000, nay_voters: 20000 });
assert_eq!(tally(r), Tally { ayes: 300, nays: 110, turnout: 410, aye_voters: 10000, nay_voters: 20000 });
});
}

Expand All @@ -111,13 +110,13 @@ fn single_proposal_should_work_with_vote_and_delegation() {
let r = 0;
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, nay(2)));
assert_eq!(tally(r), Tally { ayes: 10, nays: 20, turnout: 30, aye_voters: 10000, nay_voters: 10000 });
assert_eq!(tally(r), Tally { ayes: 90, nays: 200, turnout: 290, aye_voters: 10000, nay_voters: 10000 });

// Delegate vote.
assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r));
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
// Delegated vote replaces the explicit vote.
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30 , aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110 , aye_voters: 20000, nay_voters: 0 });
});
}

Expand All @@ -137,7 +136,7 @@ fn single_proposal_should_work_with_undelegation() {
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));

// Delegated vote is not counted.
assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 90, nays: 0, turnout: 90, aye_voters: 10000, nay_voters: 0 });
});
}

Expand All @@ -149,11 +148,11 @@ fn single_proposal_should_work_with_delegation_and_vote() {
// Delegate, undelegate and vote.
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0 });
assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2)));
assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2)));
// Delegated vote is not counted.
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 290, nays: 0, turnout: 290, aye_voters: 20000, nay_voters: 0 });
});
}

Expand All @@ -166,7 +165,7 @@ fn conviction_should_be_honored_in_delegation() {
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
// Delegated vote is huge.
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0 });
});
}

Expand Down Expand Up @@ -195,7 +194,7 @@ fn redelegation_keeps_lock() {
assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
// Delegated vote is huge.
assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0 });

let mut prior_lock = vote::PriorLock::default();

Expand Down
74 changes: 54 additions & 20 deletions frame/democracy/src/tests/public_proposals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ use super::*;
#[test]
fn backing_for_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(1, 3, 3));
assert_ok!(propose_set_balance(3, 2, 2));
assert_ok!(propose_set_balance(3, 4, 4));
assert_ok!(propose_set_balance(3, 3, 3));
assert_eq!(Democracy::backing_for(0), Some(2));
assert_eq!(Democracy::backing_for(1), Some(4));
assert_eq!(Democracy::backing_for(2), Some(3));
Expand All @@ -45,9 +45,9 @@ fn deposit_for_proposals_should_be_taken() {
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
// liberland specific - free balance shouldn't change, seconds shouldn't
// lock anything
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 20);
assert_eq!(Balances::free_balance(5), 50);
assert_eq!(Balances::free_balance(1), 90);
assert_eq!(Balances::free_balance(2), 200);
assert_eq!(Balances::free_balance(5), 500);
});
}

Expand All @@ -60,16 +60,50 @@ fn deposit_for_proposals_should_be_returned() {
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
fast_forward_to(3);
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 20);
assert_eq!(Balances::free_balance(5), 50);
assert_eq!(Balances::free_balance(1), 90);
assert_eq!(Balances::free_balance(2), 200);
assert_eq!(Balances::free_balance(5), 500);
});
}

#[test]
fn proposal_with_deposit_below_minimum_should_not_work() {
fn proposal_with_funds_below_save_value_should_not_work() {
new_test_ext().execute_with(|| {
assert_noop!(propose_set_balance(1, 2, 0), Error::<Test>::ValueLow);
assert_ok!(propose_set_balance(1, 2, 5));

Balances::make_free_balance_be(&1, 0);

assert_noop!(
propose_set_balance(1, 2, 0),
pallet_balances::Error::<Test, _>::InsufficientBalance,
);
});
}

#[test]
fn proposal_with_funds_below_minimum_should_not_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance(1, 2, 5));

Balances::make_free_balance_be(&1, 10);

assert_noop!(
propose_set_balance(1, 2, 0),
pallet_balances::pallet::Error::<Test>::Expendability
);
});
}

#[test]
fn creating_proposal_takes_fee() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_eq!(Balances::total_balance(&1), 100);

assert_ok!(propose_set_balance(1, 2, 5));

assert_eq!(Balances::total_balance(&1), 90);

});
}

Expand All @@ -94,12 +128,12 @@ fn poor_seconder_should_not_work() {
#[test]
fn cancel_proposal_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(2, 2, 2));
assert_ok!(propose_set_balance(2, 4, 4));
assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin);
let hash = note_preimage(1);
assert_ok!(Democracy::set_metadata(
RuntimeOrigin::signed(1),
RuntimeOrigin::signed(2),
MetadataOwner::Proposal(0),
Some(hash)
));
Expand All @@ -122,16 +156,16 @@ fn blacklisting_should_work() {
System::set_block_number(0);
let hash = set_balance_proposal(2).hash();

assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(3, 2, 2));
assert_ok!(propose_set_balance(3, 4, 4));

assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin);
assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));

assert_eq!(Democracy::backing_for(0), None);
assert_eq!(Democracy::backing_for(1), Some(4));

assert_noop!(propose_set_balance(1, 2, 2), Error::<Test>::ProposalBlacklisted);
assert_noop!(propose_set_balance(3, 2, 2), Error::<Test>::ProposalBlacklisted);

fast_forward_to(2);

Expand All @@ -146,9 +180,9 @@ fn blacklisting_should_work() {
fn runners_up_should_come_after() {
new_test_ext().execute_with(|| {
System::set_block_number(0);
assert_ok!(propose_set_balance(1, 2, 2));
assert_ok!(propose_set_balance(1, 4, 4));
assert_ok!(propose_set_balance(1, 3, 3));
assert_ok!(propose_set_balance(3, 2, 2));
assert_ok!(propose_set_balance(3, 4, 4));
assert_ok!(propose_set_balance(3, 3, 3));
fast_forward_to(2);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
fast_forward_to(4);
Expand Down
10 changes: 5 additions & 5 deletions frame/democracy/src/tests/scheduling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn simple_passing_should_work() {
0,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0 });
assert_eq!(Democracy::lowest_unbaked(), 0);
next_block();
next_block();
Expand All @@ -54,7 +54,7 @@ fn simple_failing_should_work() {
0,
);
assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1)));
assert_eq!(tally(r), Tally { ayes: 0, nays: 10, turnout: 10, aye_voters: 00000, nay_voters: 10000 });
assert_eq!(tally(r), Tally { ayes: 0, nays: 100, turnout: 100, aye_voters: 00000, nay_voters: 10000 });

next_block();
next_block();
Expand Down Expand Up @@ -82,12 +82,12 @@ fn ooo_inject_referendums_should_work() {
);

assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1)));
assert_eq!(tally(r2), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0 });
assert_eq!(tally(r2), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0 });

next_block();

assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1)));
assert_eq!(tally(r1), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0 });
assert_eq!(tally(r1), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0 });

next_block();
assert_eq!(Balances::free_balance(42), 2);
Expand All @@ -114,7 +114,7 @@ fn delayed_enactment_should_work() {
assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(5)));
assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, aye(6)));

assert_eq!(tally(r), Tally { ayes: 210, nays: 0, turnout: 210, aye_voters: 60000, nay_voters: 0 });
assert_eq!(tally(r), Tally { ayes: 2100, nays: 0, turnout: 2100, aye_voters: 60000, nay_voters: 0 });

next_block();
assert_eq!(Balances::free_balance(42), 0);
Expand Down
Loading

0 comments on commit 760a27d

Please sign in to comment.