diff --git a/Cargo.lock b/Cargo.lock index cd0855a87..d0b2fea7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1171,10 +1171,18 @@ dependencies = [ name = "darkfi-dao-contract" version = "0.3.0" dependencies = [ + "async-std", + "darkfi", "darkfi-money-contract", "darkfi-sdk", "darkfi-serial", "getrandom 0.2.8", + "halo2_proofs", + "log", + "rand", + "simplelog", + "sled", + "sqlx", ] [[package]] diff --git a/src/consensus/validator.rs b/src/consensus/validator.rs index 9509e86dc..d44ebf93a 100644 --- a/src/consensus/validator.rs +++ b/src/consensus/validator.rs @@ -23,8 +23,10 @@ use darkfi_sdk::{ crypto::{ constants::MERKLE_DEPTH, contract_id::MONEY_CONTRACT_ID, + //contract_id::{DAO_CONTRACT_ID, MONEY_CONTRACT_ID}, schnorr::{SchnorrPublic, SchnorrSecret}, - MerkleNode, PublicKey, + MerkleNode, + PublicKey, }, db::SMART_CONTRACT_ZKAS_DB_NAME, incrementalmerkletree::{bridgetree::BridgeTree, Tree}, @@ -154,12 +156,14 @@ impl ValidatorState { include_bytes!("../contract/money/money_contract.wasm").to_vec(), money_contract_deploy_payload, ), - //( - // "DAO Contract", - // *DAO_CONTRACT_ID, - // include_bytes!("../contract/dao/dao_contract.wasm").to_vec(), - // dao_contract_deploy_payload, - //), + /* + ( + "DAO Contract", + *DAO_CONTRACT_ID, + include_bytes!("../contract/dao/dao_contract.wasm").to_vec(), + dao_contract_deploy_payload, + ), + */ ]; info!("Deploying native wasm contracts"); diff --git a/src/contract/dao/Cargo.toml b/src/contract/dao/Cargo.toml index 333d2f9ec..ce04860ae 100644 --- a/src/contract/dao/Cargo.toml +++ b/src/contract/dao/Cargo.toml @@ -13,6 +13,21 @@ darkfi-sdk = { path = "../../sdk" } darkfi-serial = { path = "../../serial", features = ["derive", "crypto"] } darkfi-money-contract = { path = "../money", features = ["no-entrypoint"] } +# The following dependencies are used for the client API and +# probably shouldn't be in WASM +darkfi = { path = "../../../", features = ["zk", "rpc"], optional = true } +halo2_proofs = { version = "0.2.0", optional = true } +log = { version = "0.4.17", optional = true } +rand = { version = "0.8.5", optional = true } + +# These are used just for the integration tests +[dev-dependencies] +async-std = {version = "1.12.0", features = ["attributes"]} +darkfi = {path = "../../../", features = ["tx", "blockchain"]} +simplelog = "0.12.0" +sled = "0.34.7" +sqlx = {version = "0.6.2", features = ["runtime-async-std-native-tls", "sqlite"]} + # We need to disable random using "custom" which makes the crate a noop # so the wasm32-unknown-unknown target is enabled. [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -21,4 +36,9 @@ getrandom = { version = "0.2.8", features = ["custom"] } [features] default = [] no-entrypoint = [] -client = [] +client = [ + "darkfi", + "rand", + "log", + "halo2_proofs", +] diff --git a/src/contract/dao/Makefile b/src/contract/dao/Makefile index 31b5a13fa..22c26a764 100644 --- a/src/contract/dao/Makefile +++ b/src/contract/dao/Makefile @@ -28,8 +28,12 @@ $(WASM_BIN): $(WASM_SRC) $(PROOFS_BIN) $(PROOFS_BIN): $(ZKAS) $(PROOFS_SRC) $(ZKAS) $(basename $@) -o $@ -test: all - $(CARGO) test --release --features=no-entrypoint,client --package darkfi-dao-contract +test-integration: all + $(CARGO) test --release --features=no-entrypoint,client \ + --package darkfi-dao-contract \ + --test integration + +test: clean: rm -f $(PROOFS_BIN) $(WASM_BIN) diff --git a/src/contract/dao/src/client.rs b/src/contract/dao/src/client.rs new file mode 100644 index 000000000..ec55a1afb --- /dev/null +++ b/src/contract/dao/src/client.rs @@ -0,0 +1,140 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2022 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use darkfi::{ + zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::Witness, Proof}, + zkas::ZkBinary, + Result, +}; +use darkfi_sdk::{ + crypto::{poseidon_hash, PublicKey, SecretKey, TokenId}, + pasta::pallas, +}; +use halo2_proofs::circuit::Value; +use log::debug; +use rand::rngs::OsRng; + +use crate::state::{DaoBulla, DaoMintParams}; + +struct DaoMintRevealed { + pub bulla: DaoBulla, +} + +impl DaoMintRevealed { + pub fn compute( + dao_proposer_limit: pallas::Base, + dao_quorum: pallas::Base, + dao_approval_ratio_quot: pallas::Base, + dao_approval_ratio_base: pallas::Base, + gov_token_id: TokenId, + dao_pubkey: &PublicKey, + dao_bulla_blind: pallas::Base, + ) -> Self { + let (pub_x, pub_y) = dao_pubkey.xy(); + + let dao_bulla = poseidon_hash([ + dao_proposer_limit, + dao_quorum, + dao_approval_ratio_quot, + dao_approval_ratio_base, + gov_token_id.inner(), + pub_x, + pub_y, + dao_bulla_blind, + ]); + + Self { bulla: DaoBulla::from(dao_bulla) } + } + + pub fn to_vec(&self) -> Vec { + vec![self.bulla.inner()] + } +} + +fn create_dao_mint_proof( + zkbin: &ZkBinary, + pk: &ProvingKey, + dao_proposer_limit: pallas::Base, + dao_quorum: pallas::Base, + dao_approval_ratio_quot: pallas::Base, + dao_approval_ratio_base: pallas::Base, + gov_token_id: TokenId, + dao_pubkey: &PublicKey, + dao_bulla_blind: pallas::Base, +) -> Result<(Proof, DaoMintRevealed)> { + let revealed = DaoMintRevealed::compute( + dao_proposer_limit, + dao_quorum, + dao_approval_ratio_quot, + dao_approval_ratio_base, + gov_token_id, + dao_pubkey, + dao_bulla_blind, + ); + + let (pub_x, pub_y) = dao_pubkey.xy(); + + // NOTE: It's important to keep these in the same order as the zkas code. + let prover_witnesses = vec![ + Witness::Base(Value::known(dao_proposer_limit)), + Witness::Base(Value::known(dao_quorum)), + Witness::Base(Value::known(dao_approval_ratio_quot)), + Witness::Base(Value::known(dao_approval_ratio_base)), + Witness::Base(Value::known(gov_token_id.inner())), + Witness::Base(Value::known(pub_x)), + Witness::Base(Value::known(pub_y)), + Witness::Base(Value::known(dao_bulla_blind)), + ]; + + let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone()); + let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?; + + Ok((proof, revealed)) +} + +pub fn build_dao_mint_tx( + dao_proposer_limit: u64, + dao_quorum: u64, + dao_approval_ratio_quot: u64, + dao_approval_ratio_base: u64, + gov_token_id: TokenId, + dao_pubkey: &PublicKey, + dao_bulla_blind: pallas::Base, + signature_secret: &SecretKey, + dao_mint_zkbin: &ZkBinary, + dao_mint_pk: &ProvingKey, +) -> Result<(DaoMintParams, Vec)> { + debug!("Building DAO contract mint transaction"); + + let (proof, revealed) = create_dao_mint_proof( + dao_mint_zkbin, + dao_mint_pk, + pallas::Base::from(dao_proposer_limit), + pallas::Base::from(dao_quorum), + pallas::Base::from(dao_approval_ratio_quot), + pallas::Base::from(dao_approval_ratio_base), + gov_token_id, + dao_pubkey, + dao_bulla_blind, + )?; + + let dao_bulla = revealed.bulla; + let dao_mint_params = DaoMintParams { dao_bulla }; + + Ok((dao_mint_params, vec![proof])) +} diff --git a/src/contract/dao/src/entrypoint.rs b/src/contract/dao/src/entrypoint.rs index 01d2a6c99..c7d539eb7 100644 --- a/src/contract/dao/src/entrypoint.rs +++ b/src/contract/dao/src/entrypoint.rs @@ -42,7 +42,9 @@ use crate::{ DaoExecParams, DaoExecUpdate, DaoMintParams, DaoMintUpdate, DaoProposeParams, DaoProposeUpdate, DaoVoteParams, DaoVoteUpdate, ProposalVotes, }, - DaoFunction, + DaoFunction, DAO_CONTRACT_ZKAS_DAO_EXEC_NS, DAO_CONTRACT_ZKAS_DAO_MINT_NS, + DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS, + DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS, }; darkfi_sdk::define_contract!( @@ -63,15 +65,7 @@ pub const DAO_PROPOSAL_VOTES_TREE: &str = "dao_proposal_votes"; pub const DAO_MERKLE_TREE: &str = "dao_merkle_tree"; pub const DAO_PROPOSAL_MERKLE_TREE: &str = "dao_proposals_merkle_tree"; -// These are zkas circuit namespaces -pub const ZKAS_DAO_EXEC_NS: &str = "DaoExec"; -pub const ZKAS_DAO_MINT_NS: &str = "DaoMint"; -pub const ZKAS_DAO_VOTE_BURN_NS: &str = "DaoVoteInput"; -pub const ZKAS_DAO_VOTE_MAIN_NS: &str = "DaoVoteMain"; -pub const ZKAS_DAO_PROPOSE_BURN_NS: &str = "DaoProposeInput"; -pub const ZKAS_DAO_PROPOSE_MAIN_NS: &str = "DaoProposeMain"; - -fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult { +fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult { // The zkas circuits can simply be embedded in the wasm and set up by // the initialization. Note that the tree should then be called "zkas". // The lookups can then be done by `contract_id+_zkas+namespace`. @@ -86,12 +80,12 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult { let dao_propose_burn_bin = include_bytes!("../proof/dao-propose-burn.zk.bin"); let dao_propose_main_bin = include_bytes!("../proof/dao-propose-main.zk.bin"); - db_set(zkas_db, &serialize(&ZKAS_DAO_EXEC_NS), &dao_exec_bin[..])?; - db_set(zkas_db, &serialize(&ZKAS_DAO_MINT_NS), &dao_mint_bin[..])?; - db_set(zkas_db, &serialize(&ZKAS_DAO_VOTE_BURN_NS), &dao_vote_burn_bin[..])?; - db_set(zkas_db, &serialize(&ZKAS_DAO_VOTE_MAIN_NS), &dao_vote_main_bin[..])?; - db_set(zkas_db, &serialize(&ZKAS_DAO_PROPOSE_BURN_NS), &dao_propose_burn_bin[..])?; - db_set(zkas_db, &serialize(&ZKAS_DAO_PROPOSE_MAIN_NS), &dao_propose_main_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_EXEC_NS), &dao_exec_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_MINT_NS), &dao_mint_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS), &dao_vote_burn_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS), &dao_vote_main_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS), &dao_propose_burn_bin[..])?; + db_set(zkas_db, &serialize(&DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS), &dao_propose_main_bin[..])?; // Set up a database tree to hold the Merkle tree for DAO bullas let dao_bulla_db = match db_lookup(cid, DAO_BULLA_TREE) { @@ -108,7 +102,11 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult { None => { // We didn't find a tree, so just make a new one. let tree = MerkleTree::new(100); - db_set(dao_bulla_db, &serialize(&DAO_MERKLE_TREE), &serialize(&tree))?; + let mut tree_data = vec![]; + + tree_data.write_u32(0)?; + tree.encode(&mut tree_data)?; + db_set(dao_bulla_db, &serialize(&DAO_MERKLE_TREE), &tree_data)?; } }; @@ -133,7 +131,11 @@ fn init_contract(cid: ContractId, ix: &[u8]) -> ContractResult { None => { // We didn't find a tree, so just make a new one. let tree = MerkleTree::new(100); - db_set(dao_proposal_db, &serialize(&DAO_PROPOSAL_MERKLE_TREE), &serialize(&tree))?; + let mut tree_data = vec![]; + + tree_data.write_u32(0)?; + tree.encode(&mut tree_data)?; + db_set(dao_proposal_db, &serialize(&DAO_PROPOSAL_MERKLE_TREE), &tree_data)?; } }; @@ -163,6 +165,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult { let params: DaoMintParams = deserialize(&self_.data[1..])?; // No checks in Mint, just return the update. + // TODO: Should it check that there isn't an existing one? let update = DaoMintUpdate { dao_bulla: params.dao_bulla }; let mut update_data = vec![]; update_data.write_u8(DaoFunction::Mint as u8)?; @@ -396,9 +399,11 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let params: DaoMintParams = deserialize(&self_.data[1..])?; let mut zk_public_values: Vec<(String, Vec)> = vec![]; + // TODO: Why no signatures? Should it be signed with the DAO keypair? let signature_pubkeys: Vec = vec![]; - zk_public_values.push((ZKAS_DAO_MINT_NS.to_string(), vec![params.dao_bulla.inner()])); + zk_public_values + .push((DAO_CONTRACT_ZKAS_DAO_MINT_NS.to_string(), vec![params.dao_bulla.inner()])); let mut metadata = vec![]; zk_public_values.encode(&mut metadata)?; @@ -426,7 +431,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let (sig_x, sig_y) = input.signature_public.xy(); zk_public_values.push(( - ZKAS_DAO_PROPOSE_BURN_NS.to_string(), + DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS.to_string(), vec![ *value_coords.x(), *value_coords.y(), @@ -440,7 +445,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap(); zk_public_values.push(( - ZKAS_DAO_PROPOSE_MAIN_NS.to_string(), + DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS.to_string(), vec![ params.token_commit, params.dao_merkle_root.inner(), @@ -476,7 +481,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let (sig_x, sig_y) = input.signature_public.xy(); zk_public_values.push(( - ZKAS_DAO_VOTE_BURN_NS.to_string(), + DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS.to_string(), vec![ input.nullifier.inner(), *value_coords.x(), @@ -493,7 +498,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let all_vote_commit_coords = all_votes_commit.to_affine().coordinates().unwrap(); zk_public_values.push(( - ZKAS_DAO_VOTE_MAIN_NS.to_string(), + DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS.to_string(), vec![ params.token_commit, params.proposal_bulla, @@ -524,7 +529,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { let input_value_coords = params.input_value_commit.to_affine().coordinates().unwrap(); zk_public_values.push(( - ZKAS_DAO_EXEC_NS.to_string(), + DAO_CONTRACT_ZKAS_DAO_EXEC_NS.to_string(), vec![ params.proposal, params.coin_0, diff --git a/src/contract/dao/src/lib.rs b/src/contract/dao/src/lib.rs index 64dbe98b9..736800a6e 100644 --- a/src/contract/dao/src/lib.rs +++ b/src/contract/dao/src/lib.rs @@ -23,6 +23,18 @@ pub mod entrypoint; pub mod state; +#[cfg(feature = "client")] +/// Transaction building API for clients interacting with this contract +pub mod client; + +// These are the zkas circuit namespaces +pub const DAO_CONTRACT_ZKAS_DAO_MINT_NS: &str = "DaoMint"; +pub const DAO_CONTRACT_ZKAS_DAO_EXEC_NS: &str = "DaoExec"; +pub const DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS: &str = "DaoVoteInput"; +pub const DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS: &str = "DaoVoteMain"; +pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS: &str = "DaoProposeInput"; +pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS: &str = "DaoProposeMain"; + #[repr(u8)] pub enum DaoFunction { Mint = 0x00, diff --git a/src/contract/dao/tests.unused/harness.rs b/src/contract/dao/tests.unused/harness.rs new file mode 100644 index 000000000..46dd1b3cc --- /dev/null +++ b/src/contract/dao/tests.unused/harness.rs @@ -0,0 +1,129 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2022 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::collections::HashMap; + +use darkfi::{ + consensus::{ + constants::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP}, + ValidatorState, ValidatorStatePtr, + }, + wallet::WalletDb, + zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses}, + zkas::ZkBinary, + Result, +}; +use darkfi_sdk::{ + crypto::{ + contract_id::{DAO_CONTRACT_ID, MONEY_CONTRACT_ID}, + ContractId, Keypair, MerkleTree, + }, + db::SMART_CONTRACT_ZKAS_DB_NAME, + pasta::group::ff::PrimeField, +}; +use darkfi_serial::serialize; +use log::{info, warn}; +use rand::rngs::OsRng; + +use darkfi_dao_contract::DAO_CONTRACT_ZKAS_DAO_MINT_NS; + +pub fn init_logger() -> Result<()> { + let mut cfg = simplelog::ConfigBuilder::new(); + cfg.add_filter_ignore("sled".to_string()); + if let Err(_) = simplelog::TermLogger::init( + //simplelog::LevelFilter::Info, + simplelog::LevelFilter::Debug, + //simplelog::LevelFilter::Trace, + cfg.build(), + simplelog::TerminalMode::Mixed, + simplelog::ColorChoice::Auto, + ) { + warn!("Logger already initialized"); + } + + Ok(()) +} + +pub struct DaoTestHarness { + pub alice_kp: Keypair, + pub dao_kp: Keypair, + pub alice_state: ValidatorStatePtr, + pub alice_dao_merkle_tree: MerkleTree, + pub money_contract_id: ContractId, + pub dao_contract_id: ContractId, + pub proving_keys: HashMap<[u8; 32], Vec<(&'static str, ProvingKey)>>, + pub dao_mint_zkbin: ZkBinary, + pub dao_mint_pk: ProvingKey, +} + +impl DaoTestHarness { + pub async fn new() -> Result { + let alice_kp = Keypair::random(&mut OsRng); + let dao_kp = Keypair::random(&mut OsRng); + + let alice_wallet = WalletDb::new("sqlite::memory:", "foo").await?; + + let alice_sled_db = sled::Config::new().temporary(true).open()?; + + let alice_state = ValidatorState::new( + &alice_sled_db, + *TESTNET_GENESIS_TIMESTAMP, + *TESTNET_GENESIS_HASH_BYTES, + alice_wallet, + vec![], + false, + ) + .await?; + + let alice_dao_merkle_tree = MerkleTree::new(100); + + let money_contract_id = *MONEY_CONTRACT_ID; + let dao_contract_id = *DAO_CONTRACT_ID; + + let alice_sled = alice_state.read().await.blockchain.sled_db.clone(); + let db_handle = alice_state.read().await.blockchain.contracts.lookup( + &alice_sled, + &dao_contract_id, + SMART_CONTRACT_ZKAS_DB_NAME, + )?; + + let dao_mint_zkbin = db_handle.get(&serialize(&DAO_CONTRACT_ZKAS_DAO_MINT_NS))?.unwrap(); + info!("Decoding bincode"); + let dao_mint_zkbin = ZkBinary::decode(&dao_mint_zkbin)?; + let dao_mint_witnesses = empty_witnesses(&dao_mint_zkbin); + let dao_mint_circuit = ZkCircuit::new(dao_mint_witnesses, dao_mint_zkbin.clone()); + + info!("Creating zk proving keys"); + let k = 13; + let mut proving_keys = HashMap::<[u8; 32], Vec<(&str, ProvingKey)>>::new(); + let dao_mint_pk = ProvingKey::build(k, &dao_mint_circuit); + let pks = vec![(DAO_CONTRACT_ZKAS_DAO_MINT_NS, dao_mint_pk.clone())]; + proving_keys.insert(dao_contract_id.inner().to_repr(), pks); + + Ok(Self { + alice_kp, + dao_kp, + alice_state, + alice_dao_merkle_tree, + money_contract_id, + dao_contract_id, + proving_keys, + dao_mint_zkbin, + dao_mint_pk, + }) + } +} diff --git a/src/contract/dao/tests.unused/integration.rs b/src/contract/dao/tests.unused/integration.rs new file mode 100644 index 000000000..21849774f --- /dev/null +++ b/src/contract/dao/tests.unused/integration.rs @@ -0,0 +1,94 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2022 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use darkfi::{tx::Transaction, Result}; +use darkfi_sdk::{ + crypto::TokenId, + pasta::{group::ff::Field, pallas}, + tx::ContractCall, +}; +use darkfi_serial::Encodable; +use log::info; +use rand::rngs::OsRng; + +use darkfi_dao_contract::{client::build_dao_mint_tx, DaoFunction}; + +mod harness; +use harness::{init_logger, DaoTestHarness}; + +#[async_std::test] +async fn integration_test() -> Result<()> { + init_logger()?; + + let mut th = DaoTestHarness::new().await?; + + // Money parameters + //let xdrk_supply = 1_000_000; + //let xrdk_token_id = TokenId::from(pallas::Base::random(&mut OsRng)); + + // Governance token parameters + //let gdrk_supply = 1_000_000; + let gdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng)); + + // DAO parameters + let dao_proposer_limit = 110; + let dao_quorum = 110; + let dao_approval_ratio_quot = 1; + let dao_approval_ratio_base = 2; + + // ================= + // DaoFunction::Mint + // ================= + + let dao_bulla_blind = pallas::Base::random(&mut OsRng); + + info!("[Alice] ========================="); + info!("[Alice] Building Dao::Mint params"); + info!("[Alice] ========================="); + let (params, proofs) = build_dao_mint_tx( + dao_proposer_limit, + dao_quorum, + dao_approval_ratio_quot, + dao_approval_ratio_base, + gdrk_token_id, + &th.dao_kp.public, + dao_bulla_blind, + &th.dao_kp.secret, + &th.dao_mint_zkbin, + &th.dao_mint_pk, + )?; + + info!("[Alice] =========================================="); + info!("[Alice] Building Dao::Mint transaction with params"); + info!("[Alice] =========================================="); + let mut data = vec![DaoFunction::Mint as u8]; + params.encode(&mut data)?; + let calls = vec![ContractCall { contract_id: th.dao_contract_id, data }]; + let proofs = vec![proofs]; + let mut tx = Transaction { calls, proofs, signatures: vec![] }; + let sigs = tx.create_sigs(&mut OsRng, &[])?; + tx.signatures = vec![sigs]; + + info!("[Alice] ==============================="); + info!("[Alice] Executing Dao::Mint transaction"); + info!("[Alice] ==============================="); + th.alice_state.read().await.verify_transactions(&[tx.clone()], true).await?; + // TODO: Witness and add to wallet merkle tree? + + Ok(()) +} diff --git a/src/contract/money/src/client.rs b/src/contract/money/src/client.rs index 831a420e0..22262f4e8 100644 --- a/src/contract/money/src/client.rs +++ b/src/contract/money/src/client.rs @@ -696,7 +696,7 @@ pub fn build_transfer_tx( burn_pk: &ProvingKey, clear_input: bool, ) -> Result<(MoneyTransferParams, Vec, Vec, Vec)> { - debug!("Building money contract transaction"); + debug!("Building money contract transfer transaction"); assert!(value != 0); if !clear_input { assert!(!coins.is_empty()); diff --git a/src/contract/money/tests/drop_pay_swap.rs b/src/contract/money/tests/drop_pay_swap.rs index be54faa97..711adaee3 100644 --- a/src/contract/money/tests/drop_pay_swap.rs +++ b/src/contract/money/tests/drop_pay_swap.rs @@ -45,19 +45,11 @@ use darkfi_money_contract::{ }; mod harness; -use harness::MoneyTestHarness; +use harness::{init_logger, MoneyTestHarness}; #[async_std::test] async fn money_contract_transfer() -> Result<()> { - let mut cfg = simplelog::ConfigBuilder::new(); - cfg.add_filter_ignore("sled".to_string()); - simplelog::TermLogger::init( - //simplelog::LevelFilter::Debug, - simplelog::LevelFilter::Info, - cfg.build(), - simplelog::TerminalMode::Mixed, - simplelog::ColorChoice::Auto, - )?; + init_logger()?; // Some numbers we want to assert const ALICE_INITIAL: u64 = 100; diff --git a/tests/zkvm_opcodes.rs b/tests/zkvm_opcodes.rs index 54238e91d..056d59513 100644 --- a/tests/zkvm_opcodes.rs +++ b/tests/zkvm_opcodes.rs @@ -45,7 +45,7 @@ use darkfi::{ #[test] fn zkvm_opcodes() -> Result<()> { - TermLogger::init(LevelFilter::Debug, Config::default(), TerminalMode::Mixed, ColorChoice::Auto) + TermLogger::init(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto) .unwrap(); let bincode = include_bytes!("../proof/opcodes.zk.bin");