Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Individual quorum for each proposal #152

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions voting_body/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ impl Contract {
self.pre_vote_proposals.insert(&self.prop_counter, &prop);
}

// Add proposal consent
let consent = match prop.kind.required_consent() {
ConsentKind::Simple => self.simple_consent.clone(),
ConsentKind::Super => self.super_consent.clone(),
};
self.proposal_consent.insert(&self.prop_counter, &consent);

Ok(self.prop_counter)
}

Expand Down
157 changes: 78 additions & 79 deletions voting_body/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct Contract {
/// As we don't have a way to remove people from the blacklist, we can add them to the whitelist
/// and allow them to vote directly.
pub iom_whitelist: LookupSet<AccountId>,
pub proposal_consent: LookupMap<u32, Consent>,
}

#[near_bindgen]
Expand Down Expand Up @@ -97,6 +98,7 @@ impl Contract {
simple_consent,
super_consent,
iom_whitelist: LookupSet::new(StorageKey::IomWhitelist),
proposal_consent: LookupMap::new(StorageKey::ProposalConsent),
}
}

Expand All @@ -108,16 +110,16 @@ impl Contract {
* TRANSACTIONS
**********/

#[payable]
pub fn create_proposal_whitelist(&mut self, payload: CreatePropPayload) -> u32 {
let caller = env::predecessor_account_id();
self.assert_whitelist(&caller);

match self.create_proposal_impl(caller, payload) {
Ok(id) => id,
Err(error) => error.panic(),
}
}
// #[payable]
// pub fn create_proposal_whitelist(&mut self, payload: CreatePropPayload) -> u32 {
// let caller = env::predecessor_account_id();
// self.assert_whitelist(&caller);
//
// match self.create_proposal_impl(caller, payload) {
// Ok(id) => id,
// Err(error) => error.panic(),
// }
// }

/// Must be called via `iah_registry.is_human_call`.
#[payable]
Expand Down Expand Up @@ -191,21 +193,21 @@ impl Contract {
Ok(true)
}

pub fn support_proposal_whitelist(&mut self, payload: u32) -> bool {
let caller = env::predecessor_account_id();
self.assert_whitelist(&caller);

match self.support_proposal_impl(
caller,
// Lock is required to prevent double voting by moving sbt to another account.
// It is not required for the whitelist version, as only whitelisted accounts can call
env::block_timestamp_ms() + MAX_DURATION + 1,
payload,
) {
Ok(supported) => supported,
Err(err) => err.panic(),
}
}
// pub fn support_proposal_whitelist(&mut self, payload: u32) -> bool {
// let caller = env::predecessor_account_id();
// self.assert_whitelist(&caller);
//
// match self.support_proposal_impl(
// caller,
// // Lock is required to prevent double voting by moving sbt to another account.
// // It is not required for the whitelist version, as only whitelisted accounts can call
// env::block_timestamp_ms() + MAX_DURATION + 1,
// payload,
// ) {
// Ok(supported) => supported,
// Err(err) => err.panic(),
// }
// }

/// Supports proposal in the pre-vote queue.
/// Returns false if the proposal can't be supported because it is overdue.
Expand Down Expand Up @@ -265,19 +267,19 @@ impl Contract {
Ok(true)
}

pub fn vote_whitelist(&mut self, payload: VotePayload) {
let caller = env::predecessor_account_id();
self.assert_whitelist(&caller);

match self.vote_impl(
caller,
env::block_timestamp_ms() + MAX_DURATION + 1,
payload,
) {
Ok(_) => (),
Err(err) => err.panic(),
}
}
// pub fn vote_whitelist(&mut self, payload: VotePayload) {
// let caller = env::predecessor_account_id();
// self.assert_whitelist(&caller);
//
// match self.vote_impl(
// caller,
// env::block_timestamp_ms() + MAX_DURATION + 1,
// payload,
// ) {
// Ok(_) => (),
// Err(err) => err.panic(),
// }
// }

/// Must be called via `iah_registry.is_human_call_lock` with
/// `lock_duration: self.vote_duration + 1`.
Expand Down Expand Up @@ -311,7 +313,7 @@ impl Contract {
return Err(ExecError::AlreadyFinalized);
}

prop.recompute_status(self.vote_duration, self.prop_consent(&prop));
prop.recompute_status(self.vote_duration, self.prop_consent(id));
match prop.status {
ProposalStatus::PreVote => panic_str("pre-vote proposal can't be in the active queue"),
ProposalStatus::InProgress => return Err(ExecError::InProgress),
Expand Down Expand Up @@ -408,16 +410,16 @@ impl Contract {
}

/// Allows admin to add a user to the whitelist.
pub fn admin_add_to_whitelist(&mut self, user: AccountId) {
self.assert_admin();
self.iom_whitelist.insert(user);
}
// pub fn admin_add_to_whitelist(&mut self, user: AccountId) {
// self.assert_admin();
// self.iom_whitelist.insert(user);
// }

/// Allows admin to remove a user from the whitelist.
pub fn admin_remove_from_whitelist(&mut self, user: AccountId) {
self.assert_admin();
self.iom_whitelist.remove(&user);
}
// pub fn admin_remove_from_whitelist(&mut self, user: AccountId) {
// self.assert_admin();
// self.iom_whitelist.remove(&user);
// }

// /// udpate voting time for e2e tests purposes
// /// TODO: remove
Expand Down Expand Up @@ -467,9 +469,9 @@ impl Contract {
);
}

fn assert_whitelist(&self, account_id: &AccountId) {
require!(self.iom_whitelist.contains(account_id), "not whitelisted");
}
// fn assert_whitelist(&self, account_id: &AccountId) {
// require!(self.iom_whitelist.contains(account_id), "not whitelisted");
// }

fn remove_pre_vote_prop(&mut self, id: u32) -> Result<Proposal, PrevoteError> {
self.pre_vote_proposals
Expand Down Expand Up @@ -497,11 +499,8 @@ impl Contract {
emit_prevote_prop_slashed(prop_id, amount);
}

fn prop_consent(&self, prop: &Proposal) -> Consent {
match prop.kind.required_consent() {
ConsentKind::Simple => self.simple_consent.clone(),
ConsentKind::Super => self.super_consent.clone(),
}
fn prop_consent(&self, id: u32) -> Consent {
self.proposal_consent.get(&id).unwrap()
}

fn add_vote(&mut self, prop_id: u32, user: AccountId, vote: Vote, prop: &mut Proposal) {
Expand Down Expand Up @@ -1340,30 +1339,30 @@ mod unit_tests {
assert_eq!(c2, ctr.super_consent);
}

#[test]
fn update_white_list() {
let (mut ctx, mut ctr, _) = setup_ctr(BOND);
ctx.predecessor_account_id = admin();
testing_env!(ctx.clone());

assert_eq!(ctr.is_iom_whitelisted(&acc(1)), false);
ctr.admin_add_to_whitelist(acc(1));
assert_eq!(ctr.is_iom_whitelisted(&acc(1)), true);
ctr.admin_remove_from_whitelist(acc(1));
assert_eq!(ctr.is_iom_whitelisted(&acc(1)), false);
}

#[test]
fn whitelisted_can_vote() {
let (mut ctx, mut ctr, id) = setup_ctr(BOND);
ctx.predecessor_account_id = admin();
testing_env!(ctx.clone());
ctr.admin_add_to_whitelist(acc(1));
ctx.predecessor_account_id = acc(1);
ctx.attached_deposit = VOTE_DEPOSIT;
testing_env!(ctx.clone());
ctr.vote_whitelist(vote_payload(id, Vote::Approve));
}
// #[test]
// fn update_white_list() {
// let (mut ctx, mut ctr, _) = setup_ctr(BOND);
// ctx.predecessor_account_id = admin();
// testing_env!(ctx.clone());
//
// assert_eq!(ctr.is_iom_whitelisted(&acc(1)), false);
// ctr.admin_add_to_whitelist(acc(1));
// assert_eq!(ctr.is_iom_whitelisted(&acc(1)), true);
// ctr.admin_remove_from_whitelist(acc(1));
// assert_eq!(ctr.is_iom_whitelisted(&acc(1)), false);
// }
//
// #[test]
// fn whitelisted_can_vote() {
// let (mut ctx, mut ctr, id) = setup_ctr(BOND);
// ctx.predecessor_account_id = admin();
// testing_env!(ctx.clone());
// ctr.admin_add_to_whitelist(acc(1));
// ctx.predecessor_account_id = acc(1);
// ctx.attached_deposit = VOTE_DEPOSIT;
// testing_env!(ctx.clone());
// ctr.vote_whitelist(vote_payload(id, Vote::Approve));
// }

#[test]
fn not_called_by_iah_registry() {
Expand Down
9 changes: 7 additions & 2 deletions voting_body/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub struct OldState {
pub pre_vote_duration: u64,
pub vote_duration: u64,
pub accounts: LazyOption<Accounts>,

pub iom_whitelist: LookupSet<AccountId>,
pub proposal_consent: LookupMap<u32, Consent>,
}

#[near_bindgen]
Expand All @@ -34,6 +37,7 @@ impl Contract {
#[init(ignore_state)]
pub fn migrate() -> Self {
let old_state: OldState = env::state_read().expect("Old state doesn't exist");

Self {
prop_counter: old_state.prop_counter,
pre_vote_proposals: old_state.pre_vote_proposals,
Expand All @@ -47,7 +51,8 @@ impl Contract {
pre_vote_duration: old_state.pre_vote_duration,
vote_duration: old_state.vote_duration,
accounts: old_state.accounts,
iom_whitelist: LookupSet::new(StorageKey::IomWhitelist),
iom_whitelist: old_state.iom_whitelist,
proposal_consent: old_state.proposal_consent,
}
}
}
}
1 change: 1 addition & 0 deletions voting_body/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum StorageKey {
Accounts,
Votes,
IomWhitelist,
ProposalConsent,
}

/// External account required for the Voting Body.
Expand Down
24 changes: 20 additions & 4 deletions voting_body/src/view.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cmp::{max, min};
use std::collections::HashMap;

use itertools::Either;
use near_sdk::serde::Serialize;
Expand Down Expand Up @@ -82,7 +83,7 @@ impl Contract {

iter.filter_map(|id| {
proposals.get(&id).map(|mut proposal| {
proposal.recompute_status(self.vote_duration, self.prop_consent(&proposal));
proposal.recompute_status(self.vote_duration, self.prop_consent(id));
ProposalOutput { id, proposal }
})
})
Expand All @@ -96,7 +97,7 @@ impl Contract {
p = self.pre_vote_proposals.get(&id);
}
p.map(|mut proposal| {
proposal.recompute_status(self.vote_duration, self.prop_consent(&proposal));
proposal.recompute_status(self.vote_duration, self.prop_consent(id));
ProposalOutput { id, proposal }
})
}
Expand Down Expand Up @@ -136,7 +137,22 @@ impl Contract {
self._get_proposals(from_index, limit, reverse, true)
}

pub fn is_iom_whitelisted(&self, account_id: &AccountId) -> bool {
self.iom_whitelist.contains(&account_id)
// pub fn is_iom_whitelisted(&self, account_id: &AccountId) -> bool {
// self.iom_whitelist.contains(&account_id)
// }

pub fn get_proposal_consent(&self, id: u32) -> Consent {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not option but panic?

self.proposal_consent.get(&id).unwrap_or_else(|| {
panic_str("No consent");
})
}

pub fn get_proposals_consent(&self, id_list: Vec<u32>) -> HashMap<u32, Consent> {
let mut results = HashMap::new();
for id in id_list {
let consent = self.get_proposal_consent(id);
results.insert(id, consent);
}
results
}
}
Loading