minor changes in client.rs

This commit is contained in:
ghassmo
2021-08-28 04:25:28 +03:00
parent a1c2ad5ee9
commit 8ebb0e2b7a
5 changed files with 51 additions and 445 deletions

View File

@@ -122,9 +122,6 @@ path = "src/bin/cashierd.rs"
name = "darkfid"
path = "src/bin/darkfid.rs"
[[bin]]
name = "darkfid-old"
path = "src/bin/darkfid-old.rs"
[[bin]]
name = "drk"

View File

@@ -1,383 +0,0 @@
use drk::blockchain::{rocks::columns, Rocks, RocksColumn, Slab};
use drk::cli::TransferParams;
use drk::cli::{Config, DarkfidCli, DarkfidConfig};
use drk::crypto::{
load_params,
merkle::{CommitmentTree, IncrementalWitness},
merkle_node::MerkleNode,
note::{EncryptedNote, Note},
nullifier::Nullifier,
save_params, setup_mint_prover, setup_spend_prover,
};
use drk::rpc::adapters::user_adapter::UserAdapter;
use drk::rpc::jsonserver;
use drk::serial::{deserialize, Decodable};
use drk::service::{CashierClient, GatewayClient, GatewaySlabsSubscriber};
use drk::state::{state_transition, ProgramState, StateUpdate};
use drk::util::{join_config_path, prepare_transaction};
use drk::wallet::{WalletDb, WalletPtr};
use drk::{tx, Result};
use async_executor::Executor;
use bellman::groth16;
use bls12_381::Bls12;
use easy_parallel::Parallel;
use ff::Field;
use log::*;
use rand::rngs::OsRng;
use rusqlite::Connection;
use async_std::sync::Arc;
use futures::FutureExt;
use std::net::SocketAddr;
use std::path::Path;
use std::path::PathBuf;
pub struct State {
// The entire merkle tree state
tree: CommitmentTree<MerkleNode>,
// List of all previous and the current merkle roots
// This is the hashed value of all the children.
merkle_roots: RocksColumn<columns::MerkleRoots>,
// Nullifiers prevent double spending
nullifiers: RocksColumn<columns::Nullifiers>,
// Mint verifying key used by ZK
mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
// Spend verifying key used by ZK
spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
// Public key of the cashier
// List of all our secret keys
wallet: WalletPtr,
}
impl ProgramState for State {
fn is_valid_cashier_public_key(&self, _public: &jubjub::SubgroupPoint) -> bool {
let conn = Connection::open(&self.wallet.path).expect("Failed to connect to database");
let mut stmt = conn
.prepare("SELECT key_public FROM cashier WHERE key_public IN (SELECT key_public)")
.expect("Cannot generate statement.");
stmt.exists([1i32]).expect("Failed to read database")
// do actual validity check
}
fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
self.merkle_roots
.key_exist(*merkle_root)
.expect("couldn't check if the merkle_root valid")
}
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
self.nullifiers
.key_exist(nullifier.repr)
.expect("couldn't check if nullifier exists")
}
// load from disk
fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
&self.mint_pvk
}
fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
&self.spend_pvk
}
}
impl State {
async fn apply(&mut self, update: StateUpdate) -> Result<()> {
// Extend our list of nullifiers with the ones from the update
for nullifier in update.nullifiers {
self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
}
// Update merkle tree and witnesses
for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.into_iter()) {
// Add the new coins to the merkle tree
let node = MerkleNode::from_coin(&coin);
self.tree.append(node).expect("Append to merkle tree");
// Keep track of all merkle roots that have existed
self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
// Also update all the coin witnesses
for witness in self.wallet.witnesses.lock().await.iter_mut() {
witness.append(node).expect("append to witness");
}
if let Some((note, secret)) = self.try_decrypt_note(enc_note).await {
// We need to keep track of the witness for this coin.
// This allows us to prove inclusion of the coin in the merkle tree with ZK.
// Just as we update the merkle tree with every new coin, so we do the same with
// the witness.
// Derive the current witness from the current tree.
// This is done right after we add our coin to the tree (but before any other
// coins are added)
// Make a new witness for this coin
let witness = IncrementalWitness::from_tree(&self.tree);
self.wallet
.put_own_coins(coin.clone(), note.clone(), witness.clone(), secret)?;
}
}
Ok(())
}
async fn try_decrypt_note(&self, ciphertext: EncryptedNote) -> Option<(Note, jubjub::Fr)> {
let secret = self.wallet.get_private().ok()?;
match ciphertext.decrypt(&secret) {
Ok(note) => {
// ... and return the decrypted note for this coin.
return Some((note, secret.clone()));
}
Err(_) => {}
}
// We weren't able to decrypt the note with our key.
None
}
}
//pub async fn subscribe(
// gateway_slabs_sub: GatewaySlabsSubscriber,
// mut state: State,
//) -> Result<()> {
//}
pub async fn futures_broker(
client: &mut GatewayClient,
cashier_client: &mut CashierClient,
state: &mut State,
secret: jubjub::Fr,
mint_params: bellman::groth16::Parameters<Bls12>,
spend_params: bellman::groth16::Parameters<Bls12>,
gateway_slabs_sub: async_channel::Receiver<Slab>,
deposit_req: async_channel::Receiver<jubjub::SubgroupPoint>,
deposit_rep: async_channel::Sender<Option<bitcoin::util::address::Address>>,
withdraw_req: async_channel::Receiver<String>,
withdraw_rep: async_channel::Sender<Option<jubjub::SubgroupPoint>>,
publish_tx_recv: async_channel::Receiver<TransferParams>,
) -> Result<()> {
loop {
futures::select! {
slab = gateway_slabs_sub.recv().fuse() => {
let slab = slab?;
let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
let update = state_transition(state, tx)?;
state.apply(update).await?;
}
deposit_addr = deposit_req.recv().fuse() => {
let btc_public = cashier_client.get_address(deposit_addr?).await?;
deposit_rep.send(btc_public).await?;
}
withdraw_addr = withdraw_req.recv().fuse() => {
let drk_public = cashier_client.withdraw(withdraw_addr?).await?;
withdraw_rep.send(drk_public).await?;
}
transfer_params = publish_tx_recv.recv().fuse() => {
let transfer_params = transfer_params?;
let address = bs58::decode(transfer_params.pub_key).into_vec()?;
let address: jubjub::SubgroupPoint = deserialize(&address)?;
let own_coins = state.wallet.get_own_coins()?;
let slab = prepare_transaction(
state,
secret.clone(),
mint_params.clone(),
spend_params.clone(),
address,
transfer_params.amount,
own_coins
)?;
client.put_slab(slab).await.expect("put slab");
}
}
}
}
async fn start(executor: Arc<Executor<'_>>, config: Arc<DarkfidConfig>) -> Result<()> {
let connect_addr: SocketAddr = config.connect_url.parse()?;
let sub_addr: SocketAddr = config.subscriber_url.parse()?;
let cashier_addr: SocketAddr = config.cashier_url.parse()?;
let database_path = config.database_path.clone();
let walletdb_path = config.walletdb_path.clone();
let database_path = join_config_path(&PathBuf::from(database_path))?;
let walletdb_path = join_config_path(&PathBuf::from(walletdb_path))?;
let rocks = Rocks::new(&database_path)?;
let rocks2 = rocks.clone();
let slabstore = RocksColumn::<columns::Slabs>::new(rocks2.clone());
// Auto create trusted ceremony parameters if they don't exist
if !Path::new("mint.params").exists() {
let params = setup_mint_prover();
save_params("mint.params", &params)?;
}
if !Path::new("spend.params").exists() {
let params = setup_spend_prover();
save_params("spend.params", &params)?;
}
// Load trusted setup parameters
let (mint_params, mint_pvk) = load_params("mint.params")?;
let (spend_params, spend_pvk) = load_params("spend.params")?;
//let cashier_secret = jubjub::Fr::random(&mut OsRng);
//let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
// wallet secret key
let secret = jubjub::Fr::random(&mut OsRng);
// wallet public key
let _public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
let wallet = Arc::new(WalletDb::new(&walletdb_path, config.password.clone())?);
let ex = executor.clone();
let mut state = State {
tree: CommitmentTree::empty(),
merkle_roots,
nullifiers,
mint_pvk,
spend_pvk,
wallet: wallet.clone(),
};
// create gateway client
debug!(target: "Client", "Creating client");
let mut client = GatewayClient::new(connect_addr, sub_addr, slabstore)?;
// create cashier client
debug!(target: "Cashier Client", "Creating cashier client");
let mut cashier_client = CashierClient::new(cashier_addr)?;
debug!(target: "Gateway", "Start subscriber");
// start subscribing
let gateway_slabs_sub: GatewaySlabsSubscriber =
client.start_subscriber(executor.clone()).await?;
// channels to request transfer from adapter
let (publish_tx_send, publish_tx_recv) = async_channel::unbounded::<TransferParams>();
// channels to request deposit from adapter, send DRK key and receive BTC key
let (deposit_req_send, deposit_req_recv) = async_channel::unbounded::<jubjub::SubgroupPoint>();
let (deposit_rep_send, deposit_rep_recv) =
async_channel::unbounded::<Option<bitcoin::util::address::Address>>();
// channel to request withdraw from adapter, send BTC key and receive DRK key
let (withdraw_req_send, withdraw_req_recv) = async_channel::unbounded::<String>();
let (withdraw_rep_send, withdraw_rep_recv) =
async_channel::unbounded::<Option<jubjub::SubgroupPoint>>();
// start gateway client
debug!(target: "fn::start client", "start() Client started");
client.start().await?;
cashier_client.start().await?;
let futures_broker_task = executor.spawn(async move {
futures_broker(
&mut client,
&mut cashier_client,
&mut state,
secret.clone(),
mint_params.clone(),
spend_params.clone(),
gateway_slabs_sub.clone(),
deposit_req_recv.clone(),
deposit_rep_send.clone(),
withdraw_req_recv.clone(),
withdraw_rep_send.clone(),
publish_tx_recv.clone(),
)
.await?;
Ok::<(), drk::Error>(())
});
let adapter = Arc::new(UserAdapter::new(
wallet.clone(),
publish_tx_send,
(deposit_req_send, deposit_rep_recv),
(withdraw_req_send, withdraw_rep_recv),
)?);
let rpc_url: std::net::SocketAddr = config.rpc_url.parse()?;
// start the rpc server
let io = Arc::new(adapter.handle_input()?);
jsonserver::start(ex.clone(), rpc_url, io).await?;
futures_broker_task.cancel().await;
Ok(())
}
fn main() -> Result<()> {
let options = Arc::new(DarkfidCli::load()?);
let config_path: PathBuf;
match options.config.as_ref() {
Some(path) => {
config_path = path.to_owned();
}
None => {
config_path = join_config_path(&PathBuf::from("darkfid.toml"))?;
}
}
let config: DarkfidConfig = if Path::new(&config_path).exists() {
Config::<DarkfidConfig>::load(config_path)?
} else {
Config::<DarkfidConfig>::load_default(config_path)?
};
let config = Arc::new(config);
let ex = Arc::new(Executor::new());
let (signal, shutdown) = async_channel::unbounded::<()>();
{
use simplelog::*;
let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
let debug_level = if options.verbose {
LevelFilter::Debug
} else {
LevelFilter::Off
};
let log_path = config.log_path.clone();
CombinedLogger::init(vec![
TermLogger::new(debug_level, logger_config, TerminalMode::Mixed).unwrap(),
WriteLogger::new(
LevelFilter::Debug,
Config::default(),
std::fs::File::create(log_path).unwrap(),
),
])
.unwrap();
}
let ex2 = ex.clone();
let (_, result) = Parallel::new()
// Run four executor threads.
.each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
// Run the main future on the current thread.
.finish(|| {
smol::future::block_on(async move {
start(ex2, config).await?;
drop(signal);
Ok::<(), drk::Error>(())
})
});
result
}

View File

@@ -29,11 +29,16 @@ async fn start(executor: Arc<Executor<'_>>, config: Arc<DarkfidConfig>) -> Resul
let rocks = Rocks::new(&database_path)?;
// wallet secret key
let secret = jubjub::Fr::random(&mut OsRng);
let wallet = Arc::new(WalletDb::new(&walletdb_path, config.password.clone())?);
// wallet secret key
let secret: jubjub::Fr;
if let Some(prv) = wallet.get_private().ok() {
secret = prv;
} else {
secret = jubjub::Fr::random(&mut OsRng);
}
let mut client = Client::new(
secret,
rocks,

View File

@@ -10,10 +10,10 @@ use crate::crypto::{
};
use crate::rpc::adapters::user_adapter::UserAdapter;
use crate::rpc::jsonserver;
use crate::serial::Encodable;
use crate::serial::{deserialize, Decodable};
use crate::service::{CashierClient, GatewayClient, GatewaySlabsSubscriber};
use crate::state::{state_transition, ProgramState, StateUpdate};
use crate::util::prepare_transaction;
use crate::wallet::WalletPtr;
use crate::{tx, Result};
@@ -50,7 +50,7 @@ impl Client {
let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
let mint_params_path = params_paths.0.to_str().unwrap_or("mint.params");
let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
// Auto create trusted ceremony parameters if they don't exist
if !params_paths.0.exists() {
@@ -211,24 +211,57 @@ impl Client {
let address = bs58::decode(transfer_params.pub_key).into_vec()?;
let address: jubjub::SubgroupPoint = deserialize(&address)?;
let own_coins = wallet.get_own_coins()?;
let slab = prepare_transaction(
&self.state,
self.secret.clone(),
self.mint_params.clone(),
self.spend_params.clone(),
let slab = self.prepare_transaction(
address,
transfer_params.amount,
own_coins
wallet.clone()
)?;
self.gateway.put_slab(slab).await.expect("put slab");
self.gateway.put_slab(slab).await?;
}
}
}
}
pub fn prepare_transaction(
&self,
address: jubjub::SubgroupPoint,
amount: f64,
wallet: WalletPtr,
) -> Result<Slab> {
let own_coins = wallet.get_own_coins()?;
let witness = &own_coins[0].3;
let merkle_path = witness.path().unwrap();
// Construct a new tx spending the coin
let builder = tx::TransactionBuilder {
clear_inputs: vec![],
inputs: vec![tx::TransactionBuilderInputInfo {
merkle_path,
secret: self.secret.clone(),
note: own_coins[0].1.clone(),
}],
// We can add more outputs to this list.
// The only constraint is that sum(value in) == sum(value out)
outputs: vec![tx::TransactionBuilderOutputInfo {
value: amount as u64,
asset_id: 1,
public: address,
}],
};
// Build the tx
let mut tx_data = vec![];
{
let tx = builder.build(&self.mint_params, &self.spend_params);
tx.encode(&mut tx_data).expect("encode tx");
}
// build slab from the transaction
let slab = Slab::new(tx_data);
return Ok(slab);
}
}
pub struct State {

View File

@@ -1,12 +1,5 @@
use crate::blockchain::Slab;
use crate::crypto::OwnCoins;
use crate::serial::Encodable;
use crate::state::ProgramState;
use crate::tx;
use crate::Result;
use bls12_381::Bls12;
use std::path::{Path, PathBuf};
pub fn join_config_path(file: &PathBuf) -> Result<PathBuf> {
@@ -25,42 +18,3 @@ pub fn join_config_path(file: &PathBuf) -> Result<PathBuf> {
Ok(path)
}
pub fn prepare_transaction(
_state: &dyn ProgramState,
secret: jubjub::Fr,
mint_params: bellman::groth16::Parameters<Bls12>,
spend_params: bellman::groth16::Parameters<Bls12>,
address: jubjub::SubgroupPoint,
amount: f64,
own_coins: OwnCoins,
) -> Result<Slab> {
let witness = &own_coins[0].3;
let merkle_path = witness.path().unwrap();
// Construct a new tx spending the coin
let builder = tx::TransactionBuilder {
clear_inputs: vec![],
inputs: vec![tx::TransactionBuilderInputInfo {
merkle_path,
secret: secret.clone(),
note: own_coins[0].1.clone(),
}],
// We can add more outputs to this list.
// The only constraint is that sum(value in) == sum(value out)
outputs: vec![tx::TransactionBuilderOutputInfo {
value: amount as u64,
asset_id: 1,
public: address,
}],
};
// Build the tx
let mut tx_data = vec![];
{
let tx = builder.build(&mint_params, &spend_params);
tx.encode(&mut tx_data).expect("encode tx");
}
// build slab from the transaction
let slab = Slab::new(tx_data);
return Ok(slab);
}