From f642524e816c37140dbbeb5aee69780ac2cb2fd8 Mon Sep 17 00:00:00 2001 From: parazyd Date: Tue, 10 Jan 2023 15:08:58 +0100 Subject: [PATCH] drk: DAO list. --- bin/drk/src/main.rs | 16 +++- bin/drk/src/rpc_dao.rs | 167 +++++++++++++++++++++++++++++++++++--- bin/drk/src/rpc_wallet.rs | 21 +++-- 3 files changed, 178 insertions(+), 26 deletions(-) diff --git a/bin/drk/src/main.rs b/bin/drk/src/main.rs index dd5ca1875..4dc08b02c 100644 --- a/bin/drk/src/main.rs +++ b/bin/drk/src/main.rs @@ -249,8 +249,8 @@ enum DaoSubcmd { /// List imported DAOs (or info about a specific one) List { - /// Named identifier for the DAO (optional) - dao_name: Option, + /// Numeric identifier for the DAO (optional) + dao_id: Option, }, /// Mint an imported DAO on-chain @@ -762,7 +762,17 @@ async fn main() -> Result<()> { Ok(()) } - DaoSubcmd::List { dao_name } => todo!(), + DaoSubcmd::List { dao_id } => { + let rpc_client = RpcClient::new(args.endpoint.clone()) + .await + .with_context(|| "Could not connect to darkfid RPC endpoint")?; + + let drk = Drk { rpc_client }; + + drk.dao_list(dao_id).await.with_context(|| "Failed to list DAO")?; + + Ok(()) + } DaoSubcmd::Mint { dao_name } => todo!(), diff --git a/bin/drk/src/rpc_dao.rs b/bin/drk/src/rpc_dao.rs index 024538437..ac46eb132 100644 --- a/bin/drk/src/rpc_dao.rs +++ b/bin/drk/src/rpc_dao.rs @@ -20,29 +20,37 @@ use anyhow::{anyhow, Result}; use darkfi::{rpc::jsonrpc::JsonRequest, wallet::walletdb::QueryType}; use darkfi_dao_contract::dao_client::{ DAO_DAOS_COL_APPROVAL_RATIO_BASE, DAO_DAOS_COL_APPROVAL_RATIO_QUOT, DAO_DAOS_COL_BULLA_BLIND, - DAO_DAOS_COL_DAO_ID, DAO_DAOS_COL_GOV_TOKEN_ID, DAO_DAOS_COL_NAME, DAO_DAOS_COL_PROPOSER_LIMIT, - DAO_DAOS_COL_QUORUM, DAO_DAOS_COL_SECRET, DAO_DAOS_TABLE, + DAO_DAOS_COL_CALL_INDEX, DAO_DAOS_COL_DAO_ID, DAO_DAOS_COL_GOV_TOKEN_ID, + DAO_DAOS_COL_LEAF_POSITION, DAO_DAOS_COL_NAME, DAO_DAOS_COL_PROPOSER_LIMIT, + DAO_DAOS_COL_QUORUM, DAO_DAOS_COL_SECRET, DAO_DAOS_COL_TX_HASH, DAO_DAOS_TABLE, }; -use darkfi_serial::serialize; +use darkfi_serial::{deserialize, serialize}; use serde_json::json; use super::Drk; -use crate::DaoParams; +use crate::{dao::Dao, DaoParams}; impl Drk { /// Import given DAO into the wallet pub async fn dao_import(&self, dao_name: String, dao_params: DaoParams) -> Result<()> { // First let's check if we've imported this DAO before. We use the name // as the identifier. - let query = format!( - "SELECT {} FROM {} WHERE {} = {}", - DAO_DAOS_COL_DAO_ID, DAO_DAOS_TABLE, DAO_DAOS_COL_NAME, dao_name - ); - let params = json!([query, QueryType::Integer as u8, DAO_DAOS_COL_DAO_ID]); - let req = JsonRequest::new("wallet.query_row_single", params); + let query = format!("SELECT {} FROM {}", DAO_DAOS_COL_NAME, DAO_DAOS_TABLE); + let params = json!([query, QueryType::Blob as u8, DAO_DAOS_COL_NAME]); + let req = JsonRequest::new("wallet.query_row_multi", params); + let rep = self.rpc_client.request(req).await?; - if (self.rpc_client.request(req).await).is_ok() { - return Err(anyhow!("DAO \"{}\" already imported in wallet.", dao_name)) + // The returned thing should be an array of found rows. + let Some(rows) = rep.as_array() else { + return Err(anyhow!("Unexpected response from darkfid: {}", rep)) + }; + + for row in rows { + let name_bytes: Vec = serde_json::from_value(row[0].clone())?; + let name: String = deserialize(&name_bytes)?; + if name == dao_name { + return Err(anyhow!("DAO \"{}\" already imported in wallet", dao_name)) + } } eprintln!("Importing \"{}\" DAO into wallet", dao_name); @@ -81,4 +89,139 @@ impl Drk { Ok(()) } + + async fn dao_list_single(&self, dao_id: u64) -> Result<()> { + let query = + format!("SELECT * FROM {} WHERE {} = {}", DAO_DAOS_TABLE, DAO_DAOS_COL_DAO_ID, dao_id); + + let params = json!([ + query, + QueryType::Integer as u8, + DAO_DAOS_COL_DAO_ID, + QueryType::Blob as u8, + DAO_DAOS_COL_NAME, + QueryType::Integer as u8, + DAO_DAOS_COL_PROPOSER_LIMIT, + QueryType::Integer as u8, + DAO_DAOS_COL_QUORUM, + QueryType::Integer as u8, + DAO_DAOS_COL_APPROVAL_RATIO_BASE, + QueryType::Integer as u8, + DAO_DAOS_COL_APPROVAL_RATIO_QUOT, + QueryType::Blob as u8, + DAO_DAOS_COL_GOV_TOKEN_ID, + QueryType::Blob as u8, + DAO_DAOS_COL_SECRET, + QueryType::Blob as u8, + DAO_DAOS_COL_BULLA_BLIND, + QueryType::OptionBlob as u8, + DAO_DAOS_COL_LEAF_POSITION, + QueryType::OptionBlob as u8, + DAO_DAOS_COL_TX_HASH, + QueryType::OptionInteger as u8, + DAO_DAOS_COL_CALL_INDEX, + ]); + + let req = JsonRequest::new("wallet.query_row_single", params); + let rep = self.rpc_client.request(req).await?; + + let Some(row) = rep.as_array() else { + return Err(anyhow!("Unexpected response from darkfid: {}", rep)); + }; + + let dao_id: u64 = serde_json::from_value(row[0].clone())?; + + let name_bytes: Vec = serde_json::from_value(row[1].clone())?; + let name = deserialize(&name_bytes)?; + let proposer_limit = serde_json::from_value(row[2].clone())?; + let quorum = serde_json::from_value(row[3].clone())?; + let approval_ratio_base = serde_json::from_value(row[4].clone())?; + let approval_ratio_quot = serde_json::from_value(row[5].clone())?; + let gov_token_bytes: Vec = serde_json::from_value(row[6].clone())?; + let gov_token_id = deserialize(&gov_token_bytes)?; + let secret_bytes: Vec = serde_json::from_value(row[7].clone())?; + let secret_key = deserialize(&secret_bytes)?; + let bulla_blind_bytes: Vec = serde_json::from_value(row[8].clone())?; + let bulla_blind = deserialize(&bulla_blind_bytes)?; + + let leaf_position_bytes: Vec = serde_json::from_value(row[9].clone())?; + let tx_hash_bytes: Vec = serde_json::from_value(row[10].clone())?; + let call_index = serde_json::from_value(row[11].clone())?; + + let leaf_position = if leaf_position_bytes.is_empty() { + None + } else { + Some(deserialize(&leaf_position_bytes)?) + }; + + let tx_hash = + if tx_hash_bytes.is_empty() { None } else { Some(deserialize(&tx_hash_bytes)?) }; + + let dao = Dao { + name, + proposer_limit, + quorum, + approval_ratio_base, + approval_ratio_quot, + gov_token_id, + secret_key, + bulla_blind, + leaf_position, + tx_hash, + call_index, + }; + + println!("DAO Parameters:"); + println!("Name: {}", dao.name); + println!("Proposer limit: {}", dao.proposer_limit); + println!("Quorum: {}", dao.quorum); + println!( + "Approval ratio: {}", + dao.approval_ratio_base as f64 / dao.approval_ratio_quot as f64 + ); + println!("Governance token ID: {}", dao.gov_token_id); + println!("Secret key: {}", dao.secret_key); + println!("Bulla blind: {:?}", dao.bulla_blind); + println!("Leaf position: {:?}", dao.leaf_position); + println!("Tx hash: {:?}", dao.tx_hash); + println!("Call idx: {:?}", dao.call_index); + + Ok(()) + } + + /// List DAO(s) imported in the wallet + pub async fn dao_list(&self, dao_id: Option) -> Result<()> { + if dao_id.is_some() { + return self.dao_list_single(dao_id.unwrap()).await + } + + let query = format!( + "SELECT {}, {} FROM {}", + DAO_DAOS_COL_DAO_ID, DAO_DAOS_COL_NAME, DAO_DAOS_TABLE + ); + + let params = json!([ + query, + QueryType::Integer as u8, + DAO_DAOS_COL_DAO_ID, + QueryType::Blob as u8, + DAO_DAOS_COL_NAME + ]); + + let req = JsonRequest::new("wallet.query_row_multi", params); + let rep = self.rpc_client.request(req).await?; + + let Some(rows) = rep.as_array() else { + return Err(anyhow!("Unexpected response from darkfid: {}", rep)) + }; + + for row in rows { + let dao_id: u64 = serde_json::from_value(row[0].clone())?; + let dao_name_bytes: Vec = serde_json::from_value(row[1].clone())?; + let dao_name: String = deserialize(&dao_name_bytes)?; + println!("[{}] {}", dao_id, dao_name); + } + + Ok(()) + } } diff --git a/bin/drk/src/rpc_wallet.rs b/bin/drk/src/rpc_wallet.rs index cee670b24..060b0e2ee 100644 --- a/bin/drk/src/rpc_wallet.rs +++ b/bin/drk/src/rpc_wallet.rs @@ -595,21 +595,20 @@ impl Drk { proposals_tree: &BridgeTree, ) -> Result<()> { let query = format!( - "DELETE FROM {}; INSERT INTO {} ({}) VALUES (?1);", - DAO_TREES_TABLE, DAO_TREES_TABLE, DAO_TREES_COL_DAOS_TREE + "DELETE FROM {}; INSERT INTO {} ({}, {}) VALUES (?1, ?2);", + DAO_TREES_TABLE, DAO_TREES_TABLE, DAO_TREES_COL_DAOS_TREE, DAO_TREES_COL_PROPOSALS_TREE ); - let params = json!([query, QueryType::Blob as u8, serialize(daos_tree)]); - let req = JsonRequest::new("wallet.exec_sql", params); - let _ = self.rpc_client.request(req).await?; + let params = json!([ + query, + QueryType::Blob as u8, + serialize(daos_tree), + QueryType::Blob as u8, + serialize(proposals_tree) + ]); - let query = format!( - "DELETE FROM {}; INSERT INTO {} ({}) VALUES (?1);", - DAO_TREES_TABLE, DAO_TREES_TABLE, DAO_TREES_COL_PROPOSALS_TREE - ); - - let params = json!([query, QueryType::Blob as u8, serialize(proposals_tree)]); let req = JsonRequest::new("wallet.exec_sql", params); + let _ = self.rpc_client.request(req).await?; Ok(())