Преглед изворни кода

dao: proposals now have a duration, votes are not allowed past the expiry time

zero пре 2 година
родитељ
комит
bb2769a207

+ 4 - 0
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,

+ 4 - 0
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,

+ 5 - 0
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

+ 12 - 0
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);
 }

+ 2 - 0
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

+ 2 - 0
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

+ 3 - 0
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(),
         ];

+ 7 - 0
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);

+ 6 - 0
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(),
         ],

+ 6 - 0
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),
         ],
     ));
 

+ 4 - 0
src/contract/dao/src/model.rs

@@ -139,6 +139,8 @@ impl VecAuthCallCommit for Vec<DaoAuthCall> {
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 pub struct DaoProposal {
     pub auth_calls: Vec<DaoAuthCall>,
+    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,

+ 6 - 0
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),

+ 5 - 0
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(

+ 2 - 2
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<PathBuf> {
     let output = Command::new("git").arg("rev-parse").arg("--show-toplevel").output()?.stdout;