فهرست منبع

drk: Move Money scanning into wallet_money.rs

parazyd 3 سال پیش
والد
کامیت
f4367dbf49
2فایلهای تغییر یافته به همراه171 افزوده شده و 175 حذف شده
  1. 4 164
      bin/drk/src/rpc_blockchain.rs
  2. 167 11
      bin/drk/src/wallet_money.rs

+ 4 - 164
bin/drk/src/rpc_blockchain.rs

@@ -28,24 +28,8 @@ use darkfi::{
     tx::Transaction,
     wallet::walletdb::QueryType,
 };
-use darkfi_money_contract::{
-    client::{
-        Coin, EncryptedNote, OwnCoin, MONEY_COINS_COL_COIN, MONEY_COINS_COL_COIN_BLIND,
-        MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_LEAF_POSITION, MONEY_COINS_COL_MEMO,
-        MONEY_COINS_COL_NULLIFIER, MONEY_COINS_COL_SECRET, MONEY_COINS_COL_SERIAL,
-        MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID, MONEY_COINS_COL_VALUE,
-        MONEY_COINS_COL_VALUE_BLIND, MONEY_COINS_TABLE, MONEY_INFO_COL_LAST_SCANNED_SLOT,
-        MONEY_INFO_TABLE,
-    },
-    model::{MoneyTransferParams, Output},
-    MoneyFunction,
-};
-use darkfi_sdk::{
-    crypto::{
-        contract_id::MONEY_CONTRACT_ID, poseidon_hash, ContractId, MerkleNode, Nullifier, SecretKey,
-    },
-    incrementalmerkletree::Tree,
-};
+use darkfi_money_contract::client::{MONEY_INFO_COL_LAST_SCANNED_SLOT, MONEY_INFO_TABLE};
+use darkfi_sdk::crypto::ContractId;
 use darkfi_serial::{deserialize, serialize};
 use serde_json::json;
 use signal_hook::consts::{SIGINT, SIGQUIT, SIGTERM};
@@ -53,7 +37,6 @@ use signal_hook_async_std::Signals;
 use url::Url;
 
 use super::Drk;
-use crate::cli_util::kaching;
 
 impl Drk {
     /// Subscribes to darkfid's JSON-RPC notification endpoint that serves
@@ -147,145 +130,8 @@ impl Drk {
     async fn scan_block_money(&self, block: &BlockInfo) -> Result<()> {
         eprintln!("Iterating over {} transactions", block.txs.len());
 
-        let mut nullifiers: Vec<Nullifier> = vec![];
-        let mut outputs: Vec<Output> = vec![];
-
-        for (i, tx) in block.txs.iter().enumerate() {
-            for (j, call) in tx.calls.iter().enumerate() {
-                if call.contract_id == *MONEY_CONTRACT_ID &&
-                    call.data[0] == MoneyFunction::Transfer as u8
-                {
-                    eprintln!("Found Money::Transfer in call {} in tx {}", j, i);
-                    let params: MoneyTransferParams = deserialize(&call.data[1..])?;
-                    for input in params.inputs {
-                        nullifiers.push(input.nullifier);
-                    }
-                    for output in params.outputs {
-                        outputs.push(output);
-                    }
-                    continue
-                }
-
-                if call.contract_id == *MONEY_CONTRACT_ID &&
-                    call.data[0] == MoneyFunction::OtcSwap as u8
-                {
-                    eprintln!("Found Money::OtcSwap in call {} in tx {}", j, i);
-                    let params: MoneyTransferParams = deserialize(&call.data[1..])?;
-                    for input in params.inputs {
-                        nullifiers.push(input.nullifier);
-                    }
-                    for output in params.outputs {
-                        outputs.push(output);
-                    }
-                    continue
-                }
-            }
-        }
-
-        // Fetch our secret keys from the wallet
-        eprintln!("Fetching secret keys from wallet");
-        let secrets: Vec<SecretKey> = self.get_money_secrets().await?;
-        if secrets.is_empty() {
-            eprintln!("Warning: No secrets found in wallet");
-        }
-
-        eprintln!("Fetching Money Merkle tree from wallet");
-        let mut tree = self.get_money_tree().await?;
-
-        let mut owncoins = vec![];
-
-        for output in outputs {
-            let coin = output.coin;
-
-            // Append the new coin to the Merkle tree. Every coin has to be added.
-            tree.append(&MerkleNode::from(coin));
-
-            // Attempt to decrypt the note
-            let enc_note =
-                EncryptedNote { ciphertext: output.ciphertext, ephem_public: output.ephem_public };
-
-            for secret in &secrets {
-                if let Ok(note) = enc_note.decrypt(secret) {
-                    eprintln!("Successfully decrypted a note");
-                    eprintln!("Witnessing coin in Merkle tree");
-                    let leaf_position = tree.witness().unwrap();
-
-                    let owncoin = OwnCoin {
-                        coin: Coin::from(coin),
-                        note: note.clone(),
-                        secret: *secret,
-                        nullifier: Nullifier::from(poseidon_hash([secret.inner(), note.serial])),
-                        leaf_position,
-                    };
-
-                    owncoins.push(owncoin);
-                }
-            }
-        }
-
-        eprintln!("Serializing the Merkle tree into the wallet");
-        self.put_money_tree(&tree).await?;
-        eprintln!("Merkle tree written successfully");
-
-        if !nullifiers.is_empty() {
-            eprintln!("Found {} spent coins, marking as spent", nullifiers.len());
-            self.mark_spent_coins(&nullifiers).await?;
-            eprintln!("Spent coins marked successfully");
-        }
-
-        // This is the SQL query we'll be executing to insert coins into the wallet
-        let query = format!(
-            "INSERT INTO {} ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12);",
-            MONEY_COINS_TABLE,
-            MONEY_COINS_COL_COIN,
-            MONEY_COINS_COL_IS_SPENT,
-            MONEY_COINS_COL_SERIAL,
-            MONEY_COINS_COL_VALUE,
-            MONEY_COINS_COL_TOKEN_ID,
-            MONEY_COINS_COL_COIN_BLIND,
-            MONEY_COINS_COL_VALUE_BLIND,
-            MONEY_COINS_COL_TOKEN_BLIND,
-            MONEY_COINS_COL_SECRET,
-            MONEY_COINS_COL_NULLIFIER,
-            MONEY_COINS_COL_LEAF_POSITION,
-            MONEY_COINS_COL_MEMO,
-        );
-
-        eprintln!("Found {} OwnCoin(s) in block", owncoins.len());
-        for owncoin in &owncoins {
-            eprintln!("Owncoin: {:?}", owncoin.coin);
-            let params = json!([
-                query,
-                QueryType::Blob as u8,
-                serialize(&owncoin.coin),
-                QueryType::Integer as u8,
-                0, // <-- is_spent
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.serial),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.value),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.token_id),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.coin_blind),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.value_blind),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.token_blind),
-                QueryType::Blob as u8,
-                serialize(&owncoin.secret),
-                QueryType::Blob as u8,
-                serialize(&owncoin.nullifier),
-                QueryType::Blob as u8,
-                serialize(&owncoin.leaf_position),
-                QueryType::Blob as u8,
-                serialize(&owncoin.note.memo),
-            ]);
-
-            eprintln!("Executing JSON-RPC request to add OwnCoin to wallet");
-            let req = JsonRequest::new("wallet.exec_sql", params);
-            self.rpc_client.request(req).await?;
-            eprintln!("Coin added successfully");
+        for tx in block.txs.iter() {
+            self.apply_tx_money_data(tx, true).await?;
         }
 
         // Write this slot into `last_scanned_slot`
@@ -295,12 +141,6 @@ impl Drk {
         let req = JsonRequest::new("wallet.exec_sql", params);
         let _ = self.rpc_client.request(req).await?;
 
-        if !owncoins.is_empty() {
-            if let Err(_) = kaching().await {
-                return Ok(())
-            }
-        }
-
         Ok(())
     }
 

+ 167 - 11
bin/drk/src/wallet_money.rs

@@ -18,20 +18,28 @@
 use std::collections::HashMap;
 
 use anyhow::{anyhow, Result};
-use darkfi::{rpc::jsonrpc::JsonRequest, wallet::walletdb::QueryType};
-use darkfi_money_contract::client::{
-    Coin, Note, OwnCoin, MONEY_COINS_COL_COIN, MONEY_COINS_COL_COIN_BLIND,
-    MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_LEAF_POSITION, MONEY_COINS_COL_MEMO,
-    MONEY_COINS_COL_NULLIFIER, MONEY_COINS_COL_SECRET, MONEY_COINS_COL_SERIAL,
-    MONEY_COINS_COL_SPEND_HOOK, MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID,
-    MONEY_COINS_COL_USER_DATA, MONEY_COINS_COL_VALUE, MONEY_COINS_COL_VALUE_BLIND,
-    MONEY_COINS_TABLE, MONEY_INFO_COL_LAST_SCANNED_SLOT, MONEY_INFO_TABLE,
-    MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID, MONEY_KEYS_COL_PUBLIC, MONEY_KEYS_COL_SECRET,
-    MONEY_KEYS_TABLE, MONEY_TREE_COL_TREE, MONEY_TREE_TABLE,
+use darkfi::{rpc::jsonrpc::JsonRequest, tx::Transaction, wallet::walletdb::QueryType};
+use darkfi_money_contract::{
+    client::{
+        Coin, EncryptedNote, Note, OwnCoin, MONEY_COINS_COL_COIN, MONEY_COINS_COL_COIN_BLIND,
+        MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_LEAF_POSITION, MONEY_COINS_COL_MEMO,
+        MONEY_COINS_COL_NULLIFIER, MONEY_COINS_COL_SECRET, MONEY_COINS_COL_SERIAL,
+        MONEY_COINS_COL_SPEND_HOOK, MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID,
+        MONEY_COINS_COL_USER_DATA, MONEY_COINS_COL_VALUE, MONEY_COINS_COL_VALUE_BLIND,
+        MONEY_COINS_TABLE, MONEY_INFO_COL_LAST_SCANNED_SLOT, MONEY_INFO_TABLE,
+        MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID, MONEY_KEYS_COL_PUBLIC,
+        MONEY_KEYS_COL_SECRET, MONEY_KEYS_TABLE, MONEY_TREE_COL_TREE, MONEY_TREE_TABLE,
+    },
+    model::{MoneyTransferParams, Output},
+    MoneyFunction,
 };
 use darkfi_sdk::{
-    crypto::{Keypair, MerkleTree, Nullifier, PublicKey, SecretKey, TokenId},
+    crypto::{
+        poseidon_hash, Keypair, MerkleNode, MerkleTree, Nullifier, PublicKey, SecretKey, TokenId,
+        MONEY_CONTRACT_ID,
+    },
     incrementalmerkletree,
+    incrementalmerkletree::Tree,
     pasta::pallas,
 };
 use darkfi_serial::{deserialize, serialize};
@@ -39,6 +47,7 @@ use rand::rngs::OsRng;
 use serde_json::json;
 
 use super::Drk;
+use crate::cli_util::kaching;
 
 impl Drk {
     /// Initialize wallet with tables for the Money contract
@@ -512,6 +521,153 @@ impl Drk {
         Ok(balmap)
     }
 
+    /// Append data related to Money contract transactions into the wallet database.
+    pub async fn apply_tx_money_data(&self, tx: &Transaction, _confirm: bool) -> Result<()> {
+        let cid = *MONEY_CONTRACT_ID;
+
+        let mut nullifiers: Vec<Nullifier> = vec![];
+        let mut outputs: Vec<Output> = vec![];
+
+        for (i, call) in tx.calls.iter().enumerate() {
+            if call.contract_id == cid && call.data[0] == MoneyFunction::Transfer as u8 {
+                eprintln!("Found Money::Transfer in call {}", i);
+                let params: MoneyTransferParams = deserialize(&call.data[1..])?;
+
+                for input in params.inputs {
+                    nullifiers.push(input.nullifier);
+                }
+
+                for output in params.outputs {
+                    outputs.push(output);
+                }
+
+                continue
+            }
+
+            if call.contract_id == cid && call.data[0] == MoneyFunction::OtcSwap as u8 {
+                eprintln!("Found Money::OtcSwap in call {}", i);
+                let params: MoneyTransferParams = deserialize(&call.data[1..])?;
+
+                for input in params.inputs {
+                    nullifiers.push(input.nullifier);
+                }
+
+                for output in params.outputs {
+                    outputs.push(output);
+                }
+
+                continue
+            }
+        }
+
+        let secrets = self.get_money_secrets().await?;
+        let mut tree = self.get_money_tree().await?;
+
+        let mut owncoins = vec![];
+
+        for output in outputs {
+            let coin = output.coin;
+
+            // Append the new coin to the Merkle tree. Every coin has to be added.
+            tree.append(&MerkleNode::from(coin));
+
+            // Attempt to decrypt the note
+            let enc_note =
+                EncryptedNote { ciphertext: output.ciphertext, ephem_public: output.ephem_public };
+
+            for secret in &secrets {
+                if let Ok(note) = enc_note.decrypt(secret) {
+                    eprintln!("Successfully decrypted a Money Note");
+                    eprintln!("Witnessing coin in Merkle tree");
+                    let leaf_position = tree.witness().unwrap();
+
+                    let owncoin = OwnCoin {
+                        coin: Coin::from(coin),
+                        note: note.clone(),
+                        secret: *secret,
+                        nullifier: Nullifier::from(poseidon_hash([secret.inner(), note.serial])),
+                        leaf_position,
+                    };
+
+                    owncoins.push(owncoin);
+                }
+            }
+        }
+
+        self.put_money_tree(&tree).await?;
+        if !nullifiers.is_empty() {
+            self.mark_spent_coins(&nullifiers).await?;
+        }
+
+        // This is the SQL query we'll be executing to insert new coins
+        // into the wallet
+        let query = format!(
+            "INSERT INTO {} ({}, {}, {}, {}, {} {}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);",
+            MONEY_COINS_TABLE,
+            MONEY_COINS_COL_COIN,
+            MONEY_COINS_COL_IS_SPENT,
+            MONEY_COINS_COL_SERIAL,
+            MONEY_COINS_COL_VALUE,
+            MONEY_COINS_COL_TOKEN_ID,
+            MONEY_COINS_COL_SPEND_HOOK,
+            MONEY_COINS_COL_USER_DATA,
+            MONEY_COINS_COL_COIN_BLIND,
+            MONEY_COINS_COL_VALUE_BLIND,
+            MONEY_COINS_COL_TOKEN_BLIND,
+            MONEY_COINS_COL_SECRET,
+            MONEY_COINS_COL_NULLIFIER,
+            MONEY_COINS_COL_LEAF_POSITION,
+            MONEY_COINS_COL_MEMO,
+        );
+
+        eprintln!("Found {} OwnCoin(s) in transaction", owncoins.len());
+        for owncoin in &owncoins {
+            eprintln!("OwnCoin: {:?}", owncoin.coin);
+            let params = json!([
+                query,
+                QueryType::Blob as u8,
+                serialize(&owncoin.coin),
+                QueryType::Integer as u8,
+                0, // <-- is_spent
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.serial),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.value),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.token_id),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.spend_hook),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.user_data),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.coin_blind),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.value_blind),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.token_blind),
+                QueryType::Blob as u8,
+                serialize(&owncoin.secret),
+                QueryType::Blob as u8,
+                serialize(&owncoin.nullifier),
+                QueryType::Blob as u8,
+                serialize(&owncoin.leaf_position),
+                QueryType::Blob as u8,
+                serialize(&owncoin.note.memo),
+            ]);
+
+            let req = JsonRequest::new("wallet.exec_sql", params);
+            let _ = self.rpc_client.request(req).await?;
+        }
+
+        if !owncoins.is_empty() {
+            if let Err(_) = kaching().await {
+                return Ok(())
+            }
+        }
+
+        Ok(())
+    }
+
     /// Get the last scanned slot from the wallet
     pub async fn last_scanned_slot(&self) -> Result<u64> {
         let query =