| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- use async_std::sync::{Arc, Mutex};
- use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
- use log::{debug, info, trace, warn};
- use smol::Executor;
- use url::Url;
- use crate::{
- blockchain::{rocks::columns, Rocks, RocksColumn, Slab},
- circuit::{MintContract, SpendContract},
- crypto::{
- coin::Coin,
- keypair::{Keypair, PublicKey, SecretKey},
- merkle_node::MerkleNode,
- proof::ProvingKey,
- OwnCoin,
- },
- serial::{Decodable, Encodable},
- service::GatewayClient,
- state::{state_transition, State, StateUpdate},
- tx,
- types::DrkTokenId,
- util::Address,
- wallet::{
- cashierdb::CashierDbPtr,
- walletdb::{Balances, WalletPtr},
- },
- Result,
- };
- #[derive(Debug, Clone, thiserror::Error)]
- pub enum ClientFailed {
- #[error("Here is not enough value {0}")]
- NotEnoughValue(u64),
- #[error("Invalid Address {0}")]
- InvalidAddress(String),
- #[error("Invalid Amount {0}")]
- InvalidAmount(u64),
- #[error("Unable to get deposit address")]
- UnableToGetDepositAddress,
- #[error("Unable to get withdraw address")]
- UnableToGetWithdrawAddress,
- #[error("Does not have cashier public key")]
- DoesNotHaveCashierPublicKey,
- #[error("Does not have keypair")]
- DoesNotHaveKeypair,
- #[error("Password is empty. Cannot create database")]
- EmptyPassword,
- #[error("Wallet already initialized")]
- WalletInitialized,
- #[error("Keypair already exists")]
- KeyExists,
- #[error("{0}")]
- ClientError(String),
- #[error("Verify error: {0}")]
- VerifyError(String),
- #[error("Merkle tree already exists")]
- TreeExists,
- }
- pub type ClientResult<T> = std::result::Result<T, ClientFailed>;
- impl From<super::error::Error> for ClientFailed {
- fn from(err: super::error::Error) -> ClientFailed {
- ClientFailed::ClientError(err.to_string())
- }
- }
- impl From<crate::state::VerifyFailed> for ClientFailed {
- fn from(err: crate::state::VerifyFailed) -> ClientFailed {
- ClientFailed::VerifyError(err.to_string())
- }
- }
- pub struct Client {
- pub main_keypair: Keypair,
- gateway: GatewayClient,
- wallet: WalletPtr,
- mint_pk: ProvingKey,
- spend_pk: ProvingKey,
- }
- impl Client {
- pub async fn new(
- rocks: Arc<Rocks>,
- gateway_addrs: (Url, Url),
- wallet: WalletPtr,
- ) -> Result<Self> {
- wallet.init_db().await?;
- // Check if there is a default keypair
- if wallet.get_default_keypair().await.is_err() {
- // Generate a new keypair if we don't have any.
- if wallet.get_keypairs().await?.is_empty() {
- wallet.key_gen().await?;
- }
- // set the first keypair as the default one
- wallet.set_default_keypair(&wallet.get_keypairs().await?[0].public).await?;
- }
- // Generate merkle tree if we don't have one.
- if wallet.get_tree().await.is_err() {
- wallet.tree_gen().await?;
- }
- let main_keypair = wallet.get_default_keypair().await?;
- info!("Main keypair: {}", Address::from(main_keypair.public).to_string());
- trace!("Creating GatewayClient");
- let slabstore = RocksColumn::<columns::Slabs>::new(rocks);
- let gateway = GatewayClient::new(gateway_addrs.0, gateway_addrs.1, slabstore)?;
- // TODO: These should go to a better place.
- debug!("Building proving key for the mint contract...");
- let mint_pk = ProvingKey::build(11, MintContract::default());
- debug!("Building proving key for the spend contract...");
- let spend_pk = ProvingKey::build(11, SpendContract::default());
- let client = Client { main_keypair, gateway, wallet, mint_pk, spend_pk };
- Ok(client)
- }
- pub async fn start(&mut self) -> Result<()> {
- self.gateway.start().await
- }
- async fn build_slab_from_tx(
- &mut self,
- pubkey: PublicKey,
- value: u64,
- token_id: DrkTokenId,
- clear_input: bool,
- state: Arc<Mutex<State>>,
- ) -> ClientResult<Vec<Coin>> {
- trace!("Begin building slab from tx");
- let mut clear_inputs: Vec<tx::TransactionBuilderClearInputInfo> = vec![];
- let mut inputs: Vec<tx::TransactionBuilderInputInfo> = vec![];
- let mut outputs: Vec<tx::TransactionBuilderOutputInfo> = vec![];
- let mut coins: Vec<Coin> = vec![];
- if clear_input {
- // TODO: FIXME:
- let signature_secret = self.main_keypair.secret;
- let input = tx::TransactionBuilderClearInputInfo { value, token_id, signature_secret };
- clear_inputs.push(input);
- } else {
- trace!("Start building tx inputs");
- let mut inputs_value = 0_u64;
- let state_m = state.lock().await;
- let own_coins = self.wallet.get_own_coins().await?;
- for own_coin in own_coins.iter() {
- if inputs_value >= value {
- break
- }
- let node = MerkleNode(own_coin.coin.0);
- let (leaf_position, merkle_path) = state_m.tree.authentication_path(&node).unwrap();
- // TODO: What is this counting? Is it everything or does it know to separate
- // different tokens?
- inputs_value += own_coin.note.value;
- let input = tx::TransactionBuilderInputInfo {
- leaf_position,
- merkle_path,
- secret: own_coin.secret,
- note: own_coin.note,
- };
- inputs.push(input);
- coins.push(own_coin.coin);
- }
- if inputs_value < value {
- return Err(ClientFailed::NotEnoughValue(inputs_value))
- }
- if inputs_value > value {
- let return_value: u64 = inputs_value - value;
- outputs.push(tx::TransactionBuilderOutputInfo {
- value: return_value,
- token_id,
- public: self.main_keypair.public,
- });
- }
- trace!("Finish building inputs");
- }
- outputs.push(tx::TransactionBuilderOutputInfo { value, token_id, public: pubkey });
- let builder = tx::TransactionBuilder { clear_inputs, inputs, outputs };
- let mut tx_data = vec![];
- let tx: tx::Transaction = builder.build(&self.mint_pk, &self.spend_pk)?;
- tx.encode(&mut tx_data).expect("encode tx");
- let slab = Slab::new(tx_data);
- trace!("Finish building slab from tx");
- // Check if it's valid before sending to gateway
- let state = &*state.lock().await;
- state_transition(state, tx)?;
- trace!("Sending slab to gateway");
- self.gateway.put_slab(slab).await?;
- trace!("Slab sent to gateway successfully");
- Ok(coins)
- }
- pub async fn send(
- &mut self,
- pubkey: PublicKey,
- amount: u64,
- token_id: DrkTokenId,
- clear_input: bool,
- state: Arc<Mutex<State>>,
- ) -> ClientResult<()> {
- // TODO: TOKEN debug
- debug!("Sending {}", amount);
- if amount == 0 {
- return Err(ClientFailed::InvalidAmount(0))
- }
- let coins = self.build_slab_from_tx(pubkey, amount, token_id, clear_input, state).await?;
- for coin in coins.iter() {
- self.wallet.confirm_spend_coin(coin).await?;
- }
- debug!("Sent {}", amount);
- Ok(())
- }
- pub async fn transfer(
- &mut self,
- token_id: DrkTokenId,
- pubkey: PublicKey,
- amount: u64,
- state: Arc<Mutex<State>>,
- ) -> ClientResult<()> {
- debug!("Start transfer {}", amount);
- let token_id_exists = self.wallet.token_id_exists(token_id).await?;
- if token_id_exists {
- self.send(pubkey, amount, token_id, false, state).await?;
- } else {
- return Err(ClientFailed::NotEnoughValue(amount))
- }
- debug!("Finish transfer {}", amount);
- Ok(())
- }
- async fn update_state(
- secret_keys: Vec<SecretKey>,
- slab: &Slab,
- state: Arc<Mutex<State>>,
- wallet: WalletPtr,
- notify: Option<async_channel::Sender<(PublicKey, u64)>>,
- ) -> Result<()> {
- trace!("Building tx from slab and updating the state");
- let payload = slab.get_payload();
- /*
- use std::io::Write;
- let mut file = std::fs::File::create("/tmp/payload.txt")?;
- file.write_all(&payload)?;
- */
- trace!("Decoding payload");
- let tx = tx::Transaction::decode(&payload[..])?;
- let update: StateUpdate;
- // This is separate because otherwise the mutex is never unlocked.
- {
- trace!("Acquiring state lock");
- let state = &*state.lock().await;
- update = state_transition(state, tx)?;
- trace!("Successfully passed state_transition");
- }
- trace!("Acquiring state lock");
- let mut state = state.lock().await;
- trace!("Trying to apply the new state");
- state.apply(update, secret_keys, notify, wallet).await?;
- trace!("Successfully passed state.apply");
- Ok(())
- }
- pub async fn connect_to_subscriber_from_cashier(
- &self,
- state: Arc<Mutex<State>>,
- cashier_wallet: CashierDbPtr,
- notify: async_channel::Sender<(PublicKey, u64)>,
- executor: Arc<Executor<'_>>,
- ) -> Result<()> {
- trace!("Start subscriber for cashier");
- let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
- let secret_key = self.main_keypair.secret;
- let wallet = self.wallet.clone();
- let task: smol::Task<Result<()>> = executor.spawn(async move {
- loop {
- let slab = gateway_slabs_sub.recv().await?;
- trace!("Received new slab");
- let mut secret_keys = vec![secret_key];
- let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys().await?;
- secret_keys.append(&mut withdraw_keys);
- let update_state = Self::update_state(
- secret_keys,
- &slab,
- state.clone(),
- wallet.clone(),
- Some(notify.clone()),
- )
- .await;
- if let Err(e) = update_state {
- warn!("Update state: {}", e);
- continue
- }
- }
- });
- task.detach();
- Ok(())
- }
- pub async fn connect_to_subscriber(
- &self,
- state: Arc<Mutex<State>>,
- executor: Arc<Executor<'_>>,
- ) -> Result<()> {
- trace!("Start subscriber for darkfid");
- let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
- let secret_key = self.main_keypair.secret;
- let wallet = self.wallet.clone();
- let task: smol::Task<Result<()>> = executor.spawn(async move {
- loop {
- let slab = gateway_slabs_sub.recv().await?;
- trace!("Received new slab");
- let update_state = Self::update_state(
- vec![secret_key],
- &slab,
- state.clone(),
- wallet.clone(),
- None,
- )
- .await;
- if let Err(e) = update_state {
- warn!("Update state: {}", e);
- continue
- }
- }
- });
- task.detach();
- Ok(())
- }
- pub async fn init_db(&self) -> Result<()> {
- self.wallet.init_db().await
- }
- pub async fn get_own_coins(&self) -> Result<Vec<OwnCoin>> {
- self.wallet.get_own_coins().await
- }
- pub async fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
- self.wallet.confirm_spend_coin(coin).await
- }
- pub async fn get_keypairs(&self) -> Result<Vec<Keypair>> {
- self.wallet.get_keypairs().await
- }
- pub async fn put_keypair(&self, keypair: &Keypair) -> Result<()> {
- self.wallet.put_keypair(keypair).await
- }
- pub async fn set_default_keypair(&mut self, public: &PublicKey) -> Result<()> {
- self.wallet.set_default_keypair(public).await?;
- self.main_keypair = self.wallet.get_default_keypair().await?;
- Ok(())
- }
- pub async fn key_gen(&self) -> Result<()> {
- self.wallet.key_gen().await
- }
- pub async fn get_balances(&self) -> Result<Balances> {
- self.wallet.get_balances().await
- }
- pub async fn get_tree(&self) -> Result<BridgeTree<MerkleNode, 32>> {
- self.wallet.get_tree().await
- }
- }
|