dao_demo: execute DAO proposal from command-line. Includes a bug fix for proof/dao-exec.zk and exex contracts.

This commit is contained in:
lunar-mining
2022-09-21 07:54:50 +02:00
parent 4d06b1aede
commit 4585177ec3
10 changed files with 90 additions and 29 deletions

View File

@@ -61,7 +61,9 @@ pub enum CliDaoSubCommands {
vote: String,
},
/// Execute
Exec {},
Exec {
bulla: String,
},
}
/// DAO cli
@@ -156,8 +158,8 @@ async fn start(options: CliDao) -> Result<()> {
println!("Server replied: {}", &reply.to_string());
return Ok(())
}
Some(CliDaoSubCommands::Exec {}) => {
let reply = client.exec().await?;
Some(CliDaoSubCommands::Exec { bulla }) => {
let reply = client.exec(bulla).await?;
println!("Server replied: {}", &reply.to_string());
return Ok(())
}

View File

@@ -105,8 +105,8 @@ impl Rpc {
// --> {"jsonrpc": "2.0", "method": "exec", "params": [], "id": 42}
// <-- {"jsonrpc": "2.0", "result": "executing...", "id": 42}
pub async fn exec(&self) -> Result<Value> {
let req = JsonRequest::new("exec", json!([]));
pub async fn exec(&self, bulla: String) -> Result<Value> {
let req = JsonRequest::new("exec", json!([bulla]));
self.client.request(req).await
}
}

View File

@@ -91,7 +91,7 @@ circuit "DaoExec" {
proposal_token_id,
dao_serial,
dao_spend_hook,
proposal_bulla,
dao_bulla,
dao_coin_blind,
);
constrain_instance(coin_1);

View File

@@ -17,6 +17,8 @@ use crate::{
util::{CallDataBase, HashableBase, StateRegistry, Transaction, UpdateBase},
};
use log::debug;
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, thiserror::Error)]

View File

@@ -40,7 +40,6 @@ pub struct Builder {
impl Builder {
pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
debug!(target: "dao_contract::exec::wallet::Builder", "build()");
debug!(target: "dao_contract::exec::wallet", "proposalserial{:?}", self.proposal.serial);
let mut proofs = vec![];
let proposal_dest_coords = self.proposal.dest.0.to_affine().coordinates().unwrap();
@@ -100,7 +99,7 @@ impl Builder {
self.proposal.token_id,
self.dao_serial,
self.hook_dao_exec,
proposal_bulla,
dao_bulla,
self.dao_coin_blind,
]);
@@ -123,6 +122,7 @@ impl Builder {
let zk_bin = zk_info.bincode.clone();
let prover_witnesses = vec![
//
// proposal params
Witness::Base(Value::known(*proposal_dest_coords.x())),
Witness::Base(Value::known(*proposal_dest_coords.y())),
@@ -173,7 +173,6 @@ impl Builder {
];
let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
debug!(target: "example_contract::foo::wallet::Builder", "input_proof Proof::create()");
let proving_key = &zk_info.proving_key;
let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
.expect("DAO::exec() proving error!)");

View File

@@ -22,6 +22,8 @@ use crate::{
util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
};
use log::debug;
#[derive(Debug, Clone, thiserror::Error)]
pub enum Error {
#[error("Invalid proposal")]

View File

@@ -1,4 +1,8 @@
use pasta_curves::group::ff::Field;
use pasta_curves::{
arithmetic::CurveAffine,
group::{ff::Field, Curve},
pallas,
};
use rand::rngs::OsRng;
use darkfi::{
@@ -25,6 +29,8 @@ use crate::{
util::{FuncCall, ZkContractInfo, ZkContractTable},
};
use log::debug;
#[derive(Clone, SerialEncodable, SerialDecodable)]
pub struct Note {
pub serial: DrkSerial,

View File

@@ -167,7 +167,6 @@ impl Client {
call_data.dao_bulla.clone()
};
// TODO: instead of this print statement, return DAO bulla to CLI
debug!(target: "demo", "Create DAO bulla: {:?}", dao_bulla.0);
// We create a hashmap so we can easily retrieve DAO values for the demo.
@@ -388,6 +387,21 @@ impl Client {
Ok(())
}
fn exec_proposal(&mut self, bulla: pallas::Base) -> Result<()> {
let proposal = self.dao_wallet.proposals[0].clone();
let dao_params = self.dao_wallet.params[0].clone();
let tx = self
.dao_wallet
.exec_tx(proposal, bulla, dao_params, &self.zk_bins, &mut self.states)
.unwrap();
self.validate(&tx).unwrap();
self.update_wallets().unwrap();
Ok(())
}
}
struct DaoWallet {
@@ -395,6 +409,7 @@ struct DaoWallet {
signature_secret: SecretKey,
bulla_blind: pallas::Base,
leaf_position: Position,
proposal_bullas: Vec<pallas::Base>,
bullas: Vec<DaoBulla>,
params: Vec<DaoParams>,
own_coins: Vec<(OwnCoin, bool)>,
@@ -407,6 +422,7 @@ impl DaoWallet {
let signature_secret = SecretKey::random(&mut OsRng);
let bulla_blind = pallas::Base::random(&mut OsRng);
let leaf_position = Position::zero();
let proposal_bullas = Vec::new();
let bullas = Vec::new();
let params = Vec::new();
let own_coins: Vec<(OwnCoin, bool)> = Vec::new();
@@ -418,6 +434,7 @@ impl DaoWallet {
signature_secret,
bulla_blind,
leaf_position,
proposal_bullas,
bullas,
params,
own_coins,
@@ -510,6 +527,8 @@ impl DaoWallet {
debug!(target: "demo", "Proposal bulla: {:?}", proposal_bulla);
self.proposals.push(proposal);
self.proposal_bullas.push(proposal_bulla);
Ok(proposal_bulla)
}
@@ -559,7 +578,7 @@ impl DaoWallet {
Ok((money_leaf_position, money_merkle_path))
}
fn build_exec_tx(
fn exec_tx(
&self,
proposal: Proposal,
proposal_bulla: pallas::Base,
@@ -567,6 +586,8 @@ impl DaoWallet {
zk_bins: &ZkContractTable,
states: &mut StateRegistry,
) -> Result<Transaction> {
let dao_bulla = self.bullas[0].clone();
let mut inputs = Vec::new();
let mut total_input_value = 0;
// TODO: move these to DAO struct?
@@ -581,8 +602,10 @@ impl DaoWallet {
let input_value_blind = pallas::Scalar::random(&mut OsRng);
let dao_serial = pallas::Base::random(&mut OsRng);
let dao_coin_blind = pallas::Base::random(&mut OsRng);
// disabled
let user_spend_hook = pallas::Base::from(0);
let user_data = pallas::Base::from(0);
// We must prove we have sufficient governance tokens to execute this.
for (coin, is_spent) in &self.own_coins {
let is_spent = is_spent.clone();
if is_spent {
@@ -621,22 +644,20 @@ impl DaoWallet {
public: proposal.dest,
serial: proposal.serial,
coin_blind: proposal.blind,
spend_hook: pallas::Base::from(0),
user_data: pallas::Base::from(0),
spend_hook: user_spend_hook,
user_data,
},
// Change back to DAO
money_contract::transfer::wallet::BuilderOutputInfo {
value: total_input_value - proposal.amount,
// TODO: this should be the token id of the treasury,
// rather than the token id of the proposal.
// total_id: own_coin.token_id,
token_id: proposal.token_id,
// TODO: Token id of the treasury.
token_id: *XDRK_ID,
public: self.keypair.public,
// ?
serial: dao_serial,
coin_blind: dao_coin_blind,
spend_hook: *dao_contract::exec::FUNC_ID,
user_data: proposal_bulla,
user_data: dao_bulla.0,
},
],
}
@@ -646,20 +667,43 @@ impl DaoWallet {
let mut yes_votes_value = 0;
let mut yes_votes_blind = pallas::Scalar::from(0);
let mut yes_votes_commit = pallas::Point::identity();
let mut all_votes_value = 0;
let mut all_votes_blind = pallas::Scalar::from(0);
let mut all_votes_commit = pallas::Point::identity();
for note in &self.vote_notes {
if note.vote.vote_option {
// this is a yes vote
for (i, note) in self.vote_notes.iter().enumerate() {
let vote_commit = pedersen_commitment_u64(note.vote_value, note.vote_value_blind);
all_votes_commit += vote_commit;
all_votes_blind += note.vote_value_blind;
let yes_vote_commit = pedersen_commitment_u64(
note.vote.vote_option as u64 * note.vote_value,
note.vote.vote_option_blind,
);
yes_votes_commit += yes_vote_commit;
yes_votes_blind += note.vote.vote_option_blind;
let vote_option = note.vote.vote_option;
if vote_option {
yes_votes_value += note.vote_value;
yes_votes_blind += note.vote_value_blind;
}
all_votes_value += note.vote_value;
all_votes_blind += note.vote_value_blind;
let vote_result: String =
if vote_option { "yes".to_string() } else { "no".to_string() };
debug!("Voter {} voted {}", i, vote_result);
}
debug!("Outcome = {} / {}", yes_votes_value, all_votes_value);
assert!(all_votes_commit == pedersen_commitment_u64(all_votes_value, all_votes_blind));
assert!(yes_votes_commit == pedersen_commitment_u64(yes_votes_value, yes_votes_blind));
let builder = {
dao_contract::exec::wallet::Builder {
proposal: proposal.clone(),
@@ -672,7 +716,7 @@ impl DaoWallet {
user_coin_blind,
dao_serial,
dao_coin_blind,
input_value: proposal.amount,
input_value: total_input_value,
input_value_blind,
hook_dao_exec: *dao_contract::exec::FUNC_ID,
signature_secret: exec_signature_secret,
@@ -846,6 +890,7 @@ impl MoneyWallet {
dao: dao_params.clone(),
}
};
let func_call = builder.build(zk_bins);
let func_calls = vec![func_call];

View File

@@ -239,10 +239,14 @@ impl JsonRpcInterface {
}
// --> {"method": "execute", "params": []}
// <-- {"result": "executing..."}
async fn execute(&self, id: Value, _params: &[Value]) -> JsonResult {
async fn execute(&self, id: Value, params: &[Value]) -> JsonResult {
let mut client = self.client.lock().await;
// client.client.dao_wallet.build_exec_tx(proposal, proposal_bulla)
//client.exec().unwrap();
let bulla_str = params[0].as_str().unwrap();
let bulla: pallas::Base = parse_b58(bulla_str).unwrap();
client.exec_proposal(bulla);
JsonResponse::new(json!("executed"), id).into()
}
}

View File

@@ -1244,6 +1244,7 @@ pub async fn demo() -> Result<()> {
serial: dao_serial,
coin_blind: dao_coin_blind,
spend_hook: *dao_contract::exec::FUNC_ID,
// TODO: should be DAO bulla
user_data: proposal_bulla,
},
],