From bb2769a20708b227f75f63e286cfd82172575b63 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 25 Dec 2023 12:13:53 +0100 Subject: [PATCH] dao: proposals now have a duration, votes are not allowed past the expiry time --- src/contract/dao/proof/dao-auth-money-transfer.zk | 4 ++++ src/contract/dao/proof/dao-exec.zk | 4 ++++ src/contract/dao/proof/dao-propose-main.zk | 5 +++++ src/contract/dao/proof/dao-vote-main.zk | 12 ++++++++++++ src/contract/dao/src/client/auth_xfer.rs | 2 ++ src/contract/dao/src/client/exec.rs | 2 ++ src/contract/dao/src/client/propose.rs | 3 +++ src/contract/dao/src/client/vote.rs | 7 +++++++ src/contract/dao/src/entrypoint/propose.rs | 6 ++++++ src/contract/dao/src/entrypoint/vote.rs | 6 ++++++ src/contract/dao/src/model.rs | 4 ++++ src/contract/test-harness/src/dao_propose.rs | 6 ++++++ src/contract/test-harness/src/dao_vote.rs | 5 +++++ src/contract/test-harness/src/vks.rs | 4 ++-- 14 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/contract/dao/proof/dao-auth-money-transfer.zk b/src/contract/dao/proof/dao-auth-money-transfer.zk index a8e4bc459..5b6350b28 100644 --- a/src/contract/dao/proof/dao-auth-money-transfer.zk +++ b/src/contract/dao/proof/dao-auth-money-transfer.zk @@ -9,6 +9,8 @@ constant "DaoAuthMoneyTransfer" { witness "DaoAuthMoneyTransfer" { # Proposal parameters Base proposal_auth_calls_commit, + Base proposal_current_day, + Base proposal_duration_days, Base proposal_user_data, Base proposal_blind, @@ -51,6 +53,8 @@ circuit "DaoAuthMoneyTransfer" { # proposal - so it is redundant to check DAO bulla exists here. proposal_bulla = poseidon_hash( proposal_auth_calls_commit, + proposal_current_day, + proposal_duration_days, proposal_user_data, dao_bulla, proposal_blind, diff --git a/src/contract/dao/proof/dao-exec.zk b/src/contract/dao/proof/dao-exec.zk index d0bca5a42..d5c2309fb 100644 --- a/src/contract/dao/proof/dao-exec.zk +++ b/src/contract/dao/proof/dao-exec.zk @@ -9,6 +9,8 @@ constant "DaoExec" { witness "DaoExec" { # Proposal parameters Base proposal_auth_calls_commit, + Base proposal_current_day, + Base proposal_duration_days, Base proposal_user_data, Base proposal_blind, @@ -46,6 +48,8 @@ circuit "DaoExec" { # proposal - so it is redundant to check DAO bulla exists here. proposal_bulla = poseidon_hash( proposal_auth_calls_commit, + proposal_current_day, + proposal_duration_days, proposal_user_data, dao_bulla, proposal_blind, diff --git a/src/contract/dao/proof/dao-propose-main.zk b/src/contract/dao/proof/dao-propose-main.zk index dce1238bb..6e7827714 100644 --- a/src/contract/dao/proof/dao-propose-main.zk +++ b/src/contract/dao/proof/dao-propose-main.zk @@ -16,6 +16,8 @@ witness "DaoProposeMain" { # Proposal parameters Base proposal_auth_calls_commit, + Base proposal_current_day, + Base proposal_duration_days, Base proposal_user_data, Base proposal_blind, @@ -54,11 +56,14 @@ circuit "DaoProposeMain" { proposal_bulla = poseidon_hash( proposal_auth_calls_commit, + proposal_current_day, + proposal_duration_days, proposal_user_data, dao_bulla, proposal_blind, ); constrain_instance(proposal_bulla); + constrain_instance(proposal_current_day); # This is the main check # We check that dao_proposer_limit <= total_funds diff --git a/src/contract/dao/proof/dao-vote-main.zk b/src/contract/dao/proof/dao-vote-main.zk index de50d33a8..d13240b8e 100644 --- a/src/contract/dao/proof/dao-vote-main.zk +++ b/src/contract/dao/proof/dao-vote-main.zk @@ -9,6 +9,8 @@ constant "DaoVoteMain" { witness "DaoVoteMain" { # Proposal parameters Base proposal_auth_calls_commit, + Base proposal_current_day, + Base proposal_duration_days, Base proposal_user_data, Base proposal_blind, @@ -32,6 +34,9 @@ witness "DaoVoteMain" { # Check the inputs and this proof are for the same token Base gov_token_blind, + + # Check whether the proposal has expired or not + Base current_day, } circuit "DaoVoteMain" { @@ -51,6 +56,8 @@ circuit "DaoVoteMain" { proposal_bulla = poseidon_hash( proposal_auth_calls_commit, + proposal_current_day, + proposal_duration_days, proposal_user_data, dao_bulla, proposal_blind, @@ -75,4 +82,9 @@ circuit "DaoVoteMain" { # Vote option should be 0 or 1 bool_check(vote_option); + + # Enforce that the proposal has not expired + end_time = base_add(proposal_current_day, proposal_duration_days); + less_than_strict(current_day, end_time); + constrain_instance(current_day); } diff --git a/src/contract/dao/src/client/auth_xfer.rs b/src/contract/dao/src/client/auth_xfer.rs index bb3696a8f..6597b796a 100644 --- a/src/contract/dao/src/client/auth_xfer.rs +++ b/src/contract/dao/src/client/auth_xfer.rs @@ -61,6 +61,8 @@ impl DaoAuthMoneyTransferCall { let prover_witnesses = vec![ // proposal params Witness::Base(Value::known(self.proposal.auth_calls.commit())), + Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))), + Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))), Witness::Base(Value::known(self.proposal.user_data)), Witness::Base(Value::known(self.proposal.blind)), // DAO params diff --git a/src/contract/dao/src/client/exec.rs b/src/contract/dao/src/client/exec.rs index 8e4bba035..8beaabaed 100644 --- a/src/contract/dao/src/client/exec.rs +++ b/src/contract/dao/src/client/exec.rs @@ -79,6 +79,8 @@ impl DaoExecCall { let prover_witnesses = vec![ // proposal params Witness::Base(Value::known(proposal_auth_calls_commit)), + Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))), + Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))), Witness::Base(Value::known(self.proposal.user_data)), Witness::Base(Value::known(self.proposal.blind)), // DAO params diff --git a/src/contract/dao/src/client/propose.rs b/src/contract/dao/src/client/propose.rs index 6b9d2bbab..7688e5f7a 100644 --- a/src/contract/dao/src/client/propose.rs +++ b/src/contract/dao/src/client/propose.rs @@ -173,6 +173,8 @@ impl DaoProposeCall { Witness::Base(Value::known(gov_token_blind)), // proposal params Witness::Base(Value::known(self.proposal.auth_calls.commit())), + Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))), + Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))), Witness::Base(Value::known(self.proposal.user_data)), Witness::Base(Value::known(self.proposal.blind)), // DAO params @@ -191,6 +193,7 @@ impl DaoProposeCall { token_commit, self.dao_merkle_root.inner(), proposal_bulla.inner(), + pallas::Base::from(self.proposal.creation_day), *total_funds_coords.x(), *total_funds_coords.y(), ]; diff --git a/src/contract/dao/src/client/vote.rs b/src/contract/dao/src/client/vote.rs index 7d40eb1ac..94838dfac 100644 --- a/src/contract/dao/src/client/vote.rs +++ b/src/contract/dao/src/client/vote.rs @@ -63,6 +63,7 @@ pub struct DaoVoteCall { pub vote_keypair: Keypair, pub proposal: DaoProposal, pub dao: Dao, + pub current_day: u64, } impl DaoVoteCall { @@ -189,9 +190,12 @@ impl DaoVoteCall { let all_vote_commit = pedersen_commitment_u64(all_vote_value, all_vote_blind); let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap(); + let current_day = pallas::Base::from(self.current_day); let prover_witnesses = vec![ // proposal params Witness::Base(Value::known(self.proposal.auth_calls.commit())), + Witness::Base(Value::known(pallas::Base::from(self.proposal.creation_day))), + Witness::Base(Value::known(pallas::Base::from(self.proposal.duration_days))), Witness::Base(Value::known(self.proposal.user_data)), Witness::Base(Value::known(self.proposal.blind)), // DAO params @@ -211,6 +215,8 @@ impl DaoVoteCall { Witness::Scalar(Value::known(all_vote_blind)), // gov token Witness::Base(Value::known(gov_token_blind)), + // time checks + Witness::Base(Value::known(current_day)), ]; let public_inputs = vec![ @@ -220,6 +226,7 @@ impl DaoVoteCall { *yes_vote_commit_coords.y(), *all_vote_commit_coords.x(), *all_vote_commit_coords.y(), + current_day, ]; let circuit = ZkCircuit::new(prover_witnesses, main_zkbin); diff --git a/src/contract/dao/src/entrypoint/propose.rs b/src/contract/dao/src/entrypoint/propose.rs index f9968586f..4b4952cf0 100644 --- a/src/contract/dao/src/entrypoint/propose.rs +++ b/src/contract/dao/src/entrypoint/propose.rs @@ -26,6 +26,7 @@ use darkfi_sdk::{ error::{ContractError, ContractResult}, msg, pasta::pallas, + util::get_blockchain_time, ContractCall, }; use darkfi_serial::{deserialize, serialize, Encodable, WriteExt}; @@ -37,6 +38,8 @@ use crate::{ DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS, }; +const SECS_IN_DAY: u64 = 24 * 60 * 60; + /// `get_metdata` function for `Dao::Propose` pub(crate) fn dao_propose_get_metadata( _cid: ContractId, @@ -80,6 +83,8 @@ pub(crate) fn dao_propose_get_metadata( )); } + let current_day = get_blockchain_time() / SECS_IN_DAY; + let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap(); zk_public_inputs.push(( DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS.to_string(), @@ -87,6 +92,7 @@ pub(crate) fn dao_propose_get_metadata( params.token_commit, params.dao_merkle_root.inner(), params.proposal_bulla.inner(), + pallas::Base::from(current_day), *total_funds_coords.x(), *total_funds_coords.y(), ], diff --git a/src/contract/dao/src/entrypoint/vote.rs b/src/contract/dao/src/entrypoint/vote.rs index af97961e8..2b8c253bc 100644 --- a/src/contract/dao/src/entrypoint/vote.rs +++ b/src/contract/dao/src/entrypoint/vote.rs @@ -24,6 +24,7 @@ use darkfi_sdk::{ error::{ContractError, ContractResult}, msg, pasta::pallas, + util::get_blockchain_time, ContractCall, }; use darkfi_serial::{deserialize, serialize, Encodable, WriteExt}; @@ -35,6 +36,8 @@ use crate::{ DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS, }; +const SECS_IN_DAY: u64 = 24 * 60 * 60; + /// `get_metdata` function for `Dao::Vote` pub(crate) fn dao_vote_get_metadata( _cid: ContractId, @@ -84,6 +87,8 @@ pub(crate) fn dao_vote_get_metadata( )); } + let current_day = get_blockchain_time() / SECS_IN_DAY; + let yes_vote_commit_coords = params.yes_vote_commit.to_affine().coordinates().unwrap(); let all_vote_commit_coords = all_vote_commit.to_affine().coordinates().unwrap(); @@ -96,6 +101,7 @@ pub(crate) fn dao_vote_get_metadata( *yes_vote_commit_coords.y(), *all_vote_commit_coords.x(), *all_vote_commit_coords.y(), + pallas::Base::from(current_day), ], )); diff --git a/src/contract/dao/src/model.rs b/src/contract/dao/src/model.rs index f15b2fee3..c8c1575d9 100644 --- a/src/contract/dao/src/model.rs +++ b/src/contract/dao/src/model.rs @@ -139,6 +139,8 @@ impl VecAuthCallCommit for Vec { #[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct DaoProposal { pub auth_calls: Vec, + pub creation_day: u64, + pub duration_days: u64, /// Arbitrary data provided by the user. We don't use this. pub user_data: pallas::Base, pub dao_bulla: DaoBulla, @@ -149,6 +151,8 @@ impl DaoProposal { pub fn to_bulla(&self) -> DaoProposalBulla { let bulla = poseidon_hash([ self.auth_calls.commit(), + pallas::Base::from(self.creation_day), + pallas::Base::from(self.duration_days), self.user_data, self.dao_bulla.inner(), self.blind, diff --git a/src/contract/test-harness/src/dao_propose.rs b/src/contract/test-harness/src/dao_propose.rs index cd5aaedbc..d1cefabf6 100644 --- a/src/contract/test-harness/src/dao_propose.rs +++ b/src/contract/test-harness/src/dao_propose.rs @@ -38,6 +38,8 @@ use rand::rngs::OsRng; use super::{Holder, TestHarness, TxAction}; +const SECS_IN_DAY: u64 = 24 * 60 * 60; + impl TestHarness { pub fn dao_propose( &mut self, @@ -97,8 +99,12 @@ impl TestHarness { }, ]; + let creation_day = + wallet.validator.consensus.time_keeper.blockchain_timestamp() / SECS_IN_DAY; let proposal = DaoProposal { auth_calls, + creation_day, + duration_days: 30, user_data, dao_bulla: dao.to_bulla(), blind: pallas::Base::random(&mut OsRng), diff --git a/src/contract/test-harness/src/dao_vote.rs b/src/contract/test-harness/src/dao_vote.rs index 2d4aa2819..7bf518e7b 100644 --- a/src/contract/test-harness/src/dao_vote.rs +++ b/src/contract/test-harness/src/dao_vote.rs @@ -38,6 +38,8 @@ use rand::rngs::OsRng; use super::{Holder, TestHarness, TxAction}; +const SECS_IN_DAY: u64 = 24 * 60 * 60; + impl TestHarness { pub fn dao_vote( &mut self, @@ -78,6 +80,8 @@ impl TestHarness { signature_secret, }; + let current_day = + wallet.validator.consensus.time_keeper.blockchain_timestamp() / SECS_IN_DAY; let call = DaoVoteCall { inputs: vec![input], vote_option, @@ -85,6 +89,7 @@ impl TestHarness { vote_keypair: *dao_kp, proposal: proposal.clone(), dao: dao.clone(), + current_day, }; let (params, proofs) = call.make( diff --git a/src/contract/test-harness/src/vks.rs b/src/contract/test-harness/src/vks.rs index 7f6af83a9..d8ccf8923 100644 --- a/src/contract/test-harness/src/vks.rs +++ b/src/contract/test-harness/src/vks.rs @@ -49,8 +49,8 @@ use darkfi_serial::{deserialize, serialize}; use log::debug; /// Update this if any circuits are changed -const VKS_HASH: &str = "3f47adca36cd4e17c625d838425793ad7d9ac4ddcc3ed6739add3adb4dfbab8c"; -const PKS_HASH: &str = "0d3fef220868380aeb9146a9530bd4e9cbe3b7c1d05b20bfe5c8335741367bc8"; +const VKS_HASH: &str = "3571f82a2ff9f05dda4a280b6100aae77fc743f8dc2d6aa02c885ccc2a8f14c3"; +const PKS_HASH: &str = "f3399d23e4b917b2156e140227dac5ee5ba3977064ec2132954636441c4fbfb7"; fn pks_path(typ: &str) -> Result { let output = Command::new("git").arg("rev-parse").arg("--show-toplevel").output()?.stdout;