Explorar el Código

drk: properly handle txs history and token auth is_frozen reset

skoupidi hace 1 año
padre
commit
041257447a
Se han modificado 5 ficheros con 100 adiciones y 89 borrados
  1. 23 18
      bin/drk/src/dao.rs
  2. 13 6
      bin/drk/src/money.rs
  3. 33 26
      bin/drk/src/rpc.rs
  4. 8 0
      bin/drk/src/token.rs
  5. 23 39
      bin/drk/src/txs_history.rs

+ 23 - 18
bin/drk/src/dao.rs

@@ -634,13 +634,14 @@ impl Drk {
         Ok(proposals)
         Ok(proposals)
     }
     }
 
 
-    // Auxiliary function to apply `DaoFunction::Mint` call data to the wallet.
+    /// Auxiliary function to apply `DaoFunction::Mint` call data to the wallet.
+    /// Returns a flag indicating if the provided call refers to our own wallet.
     async fn apply_dao_mint_data(
     async fn apply_dao_mint_data(
         &self,
         &self,
         new_bulla: DaoBulla,
         new_bulla: DaoBulla,
         tx_hash: TransactionHash,
         tx_hash: TransactionHash,
         call_index: u8,
         call_index: u8,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         let daos = self.get_daos().await?;
         let daos = self.get_daos().await?;
         let (mut daos_tree, proposals_tree) = self.get_dao_trees().await?;
         let (mut daos_tree, proposals_tree) = self.get_dao_trees().await?;
         daos_tree.append(MerkleNode::from(new_bulla.inner()));
         daos_tree.append(MerkleNode::from(new_bulla.inner()));
@@ -669,20 +670,21 @@ impl Drk {
                     )))
                     )))
                 }
                 }
 
 
-                break
+                return Ok(true);
             }
             }
         }
         }
 
 
-        Ok(())
+        Ok(false)
     }
     }
 
 
-    // Auxiliary function to apply `DaoFunction::Propose` call data to the wallet.
+    /// Auxiliary function to apply `DaoFunction::Propose` call data to the wallet.
+    /// Returns a flag indicating if the provided call refers to our own wallet.
     async fn apply_dao_propose_data(
     async fn apply_dao_propose_data(
         &self,
         &self,
         params: DaoProposeParams,
         params: DaoProposeParams,
         tx_hash: TransactionHash,
         tx_hash: TransactionHash,
         call_index: u8,
         call_index: u8,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         let daos = self.get_daos().await?;
         let daos = self.get_daos().await?;
         let (daos_tree, mut proposals_tree) = self.get_dao_trees().await?;
         let (daos_tree, mut proposals_tree) = self.get_dao_trees().await?;
         proposals_tree.append(MerkleNode::from(params.proposal_bulla.inner()));
         proposals_tree.append(MerkleNode::from(params.proposal_bulla.inner()));
@@ -733,23 +735,24 @@ impl Drk {
                     )))
                     )))
                 }
                 }
 
 
-                break
+                return Ok(true);
             }
             }
         }
         }
 
 
-        Ok(())
+        Ok(false)
     }
     }
 
 
-    // Auxiliary function to apply `DaoFunction::Vote` call data to the wallet.
+    /// Auxiliary function to apply `DaoFunction::Vote` call data to the wallet.
+    /// Returns a flag indicating if the provided call refers to our own wallet.
     async fn apply_dao_vote_data(
     async fn apply_dao_vote_data(
         &self,
         &self,
         params: DaoVoteParams,
         params: DaoVoteParams,
         tx_hash: TransactionHash,
         tx_hash: TransactionHash,
         call_index: u8,
         call_index: u8,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         // Check if we got the corresponding proposal
         // Check if we got the corresponding proposal
         let Ok(proposal) = self.get_dao_proposal_by_bulla(&params.proposal_bulla).await else {
         let Ok(proposal) = self.get_dao_proposal_by_bulla(&params.proposal_bulla).await else {
-            return Ok(())
+            return Ok(false)
         };
         };
 
 
         // Grab the proposal DAO
         // Grab the proposal DAO
@@ -807,18 +810,19 @@ impl Drk {
             )))
             )))
         }
         }
 
 
-        Ok(())
+        Ok(true)
     }
     }
 
 
-    // Auxiliary function to apply `DaoFunction::Exec` call data to the wallet.
+    /// Auxiliary function to apply `DaoFunction::Exec` call data to the wallet.
+    /// Returns a flag indicating if the provided call refers to our own wallet.
     async fn apply_dao_exec_data(
     async fn apply_dao_exec_data(
         &self,
         &self,
         params: DaoExecParams,
         params: DaoExecParams,
         tx_hash: TransactionHash,
         tx_hash: TransactionHash,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         // Check if we got the corresponding proposal
         // Check if we got the corresponding proposal
         let Ok(mut proposal) = self.get_dao_proposal_by_bulla(&params.proposal_bulla).await else {
         let Ok(mut proposal) = self.get_dao_proposal_by_bulla(&params.proposal_bulla).await else {
-            return Ok(())
+            return Ok(false)
         };
         };
 
 
         // Update its exec transaction hash
         // Update its exec transaction hash
@@ -829,16 +833,17 @@ impl Drk {
             )))
             )))
         }
         }
 
 
-        Ok(())
+        Ok(true)
     }
     }
 
 
     /// Append data related to DAO contract transactions into the wallet database.
     /// Append data related to DAO contract transactions into the wallet database.
+    /// Returns a flag indicating if the provided data refer to our own wallet.
     pub async fn apply_tx_dao_data(
     pub async fn apply_tx_dao_data(
         &self,
         &self,
         data: &[u8],
         data: &[u8],
         tx_hash: TransactionHash,
         tx_hash: TransactionHash,
         call_idx: u8,
         call_idx: u8,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         // Run through the transaction call data and see what we got:
         // Run through the transaction call data and see what we got:
         match DaoFunction::try_from(data[0])? {
         match DaoFunction::try_from(data[0])? {
             DaoFunction::Mint => {
             DaoFunction::Mint => {
@@ -864,7 +869,7 @@ impl Drk {
             DaoFunction::AuthMoneyTransfer => {
             DaoFunction::AuthMoneyTransfer => {
                 println!("[apply_tx_dao_data] Found Dao::AuthMoneyTransfer call");
                 println!("[apply_tx_dao_data] Found Dao::AuthMoneyTransfer call");
                 // Does nothing, just verifies the other calls are correct
                 // Does nothing, just verifies the other calls are correct
-                Ok(())
+                Ok(false)
             }
             }
         }
         }
     }
     }

+ 13 - 6
bin/drk/src/money.rs

@@ -788,12 +788,13 @@ impl Drk {
     }
     }
 
 
     /// Append data related to Money contract transactions into the wallet database.
     /// Append data related to Money contract transactions into the wallet database.
+    /// Returns a flag indicating if the provided data refer to our own wallet.
     pub async fn apply_tx_money_data(
     pub async fn apply_tx_money_data(
         &self,
         &self,
         call_idx: usize,
         call_idx: usize,
         calls: &[DarkLeaf<ContractCall>],
         calls: &[DarkLeaf<ContractCall>],
         tx_hash: &String,
         tx_hash: &String,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         let (nullifiers, coins, notes, freezes) = self.parse_money_call(call_idx, calls).await?;
         let (nullifiers, coins, notes, freezes) = self.parse_money_call(call_idx, calls).await?;
         let secrets = self.get_money_secrets().await?;
         let secrets = self.get_money_secrets().await?;
         let dao_secrets = self.get_dao_secrets().await?;
         let dao_secrets = self.get_dao_secrets().await?;
@@ -826,7 +827,7 @@ impl Drk {
             )))
             )))
         }
         }
         self.smt_insert(&nullifiers)?;
         self.smt_insert(&nullifiers)?;
-        self.mark_spent_coins(&nullifiers, tx_hash).await?;
+        let wallet_spent_coins = self.mark_spent_coins(&nullifiers, tx_hash).await?;
 
 
         // This is the SQL query we'll be executing to insert new coins
         // This is the SQL query we'll be executing to insert new coins
         // into the wallet
         // into the wallet
@@ -872,6 +873,7 @@ impl Drk {
             }
             }
         }
         }
 
 
+        let mut wallet_freezes = false;
         for token_id in freezes {
         for token_id in freezes {
             let query = format!(
             let query = format!(
                 "UPDATE {} SET {} = 1 WHERE {} = ?1;",
                 "UPDATE {} SET {} = 1 WHERE {} = ?1;",
@@ -885,13 +887,15 @@ impl Drk {
                     "[apply_tx_money_data] Inserting Money coin failed: {e:?}"
                     "[apply_tx_money_data] Inserting Money coin failed: {e:?}"
                 )))
                 )))
             }
             }
+
+            wallet_freezes = true;
         }
         }
 
 
         if self.fun && !owncoins.is_empty() {
         if self.fun && !owncoins.is_empty() {
             kaching().await;
             kaching().await;
         }
         }
 
 
-        Ok(())
+        Ok(wallet_spent_coins || !owncoins.is_empty() || wallet_freezes)
     }
     }
 
 
     /// Auxiliary function to  grab all the nullifiers from a transaction money call.
     /// Auxiliary function to  grab all the nullifiers from a transaction money call.
@@ -958,15 +962,17 @@ impl Drk {
     }
     }
 
 
     /// Marks all coins in the wallet as spent, if their nullifier is in the given set.
     /// Marks all coins in the wallet as spent, if their nullifier is in the given set.
+    /// Returns a flag indicating if any of the provided nullifiers refer to our own wallet.
     pub async fn mark_spent_coins(
     pub async fn mark_spent_coins(
         &self,
         &self,
         nullifiers: &[Nullifier],
         nullifiers: &[Nullifier],
         spent_tx_hash: &String,
         spent_tx_hash: &String,
-    ) -> Result<()> {
+    ) -> Result<bool> {
         if nullifiers.is_empty() {
         if nullifiers.is_empty() {
-            return Ok(())
+            return Ok(false)
         }
         }
 
 
+        let mut wallet_spent_coins = false;
         for (coin, _, _) in self.get_coins(false).await? {
         for (coin, _, _) in self.get_coins(false).await? {
             if nullifiers.contains(&coin.nullifier()) {
             if nullifiers.contains(&coin.nullifier()) {
                 if let Err(e) = self.mark_spent_coin(&coin.coin, spent_tx_hash).await {
                 if let Err(e) = self.mark_spent_coin(&coin.coin, spent_tx_hash).await {
@@ -974,10 +980,11 @@ impl Drk {
                         "[mark_spent_coins] Marking spent coin failed: {e:?}"
                         "[mark_spent_coins] Marking spent coin failed: {e:?}"
                     )))
                     )))
                 }
                 }
+                wallet_spent_coins = true;
             }
             }
         }
         }
 
 
-        Ok(())
+        Ok(wallet_spent_coins)
     }
     }
 
 
     /// Inserts given slice to the wallets nullifiers Sparse Merkle Tree.
     /// Inserts given slice to the wallets nullifiers Sparse Merkle Tree.

+ 33 - 26
bin/drk/src/rpc.rs

@@ -145,21 +145,6 @@ impl Drk {
                                 "[subscribe_blocks] Scanning block failed: {e:?}"
                                 "[subscribe_blocks] Scanning block failed: {e:?}"
                             )))
                             )))
                         }
                         }
-                        let txs_hashes = match self.insert_tx_history_records(&block_data.txs).await {
-                            Ok(hashes) => hashes,
-                            Err(e) => {
-                                return Err(Error::DatabaseError(format!(
-                                    "[subscribe_blocks] Inserting transaction history records failed: {e:?}"
-                                )))
-                            },
-                        };
-                        if let Err(e) =
-                            self.update_tx_history_records_status(&txs_hashes, "Finalized")
-                        {
-                            return Err(Error::DatabaseError(format!(
-                                "[subscribe_blocks] Update transaction history record status failed: {e:?}"
-                            )))
-                        }
                     }
                     }
                 }
                 }
 
 
@@ -184,28 +169,39 @@ impl Drk {
     /// based on the called contract. Additionally, will update `last_scanned_block` to
     /// based on the called contract. Additionally, will update `last_scanned_block` to
     /// the probided block height.
     /// the probided block height.
     async fn scan_block(&self, block: &BlockInfo) -> Result<()> {
     async fn scan_block(&self, block: &BlockInfo) -> Result<()> {
+        // Keep track of our wallet transactions
+        let mut wallet_txs = vec![];
         println!("=======================================");
         println!("=======================================");
         println!("{}", block.header);
         println!("{}", block.header);
         println!("=======================================");
         println!("=======================================");
         println!("[scan_block] Iterating over {} transactions", block.txs.len());
         println!("[scan_block] Iterating over {} transactions", block.txs.len());
         for tx in block.txs.iter() {
         for tx in block.txs.iter() {
             let tx_hash = tx.hash().to_string();
             let tx_hash = tx.hash().to_string();
+            let mut wallet_tx = false;
             println!("[scan_block] Processing transaction: {tx_hash}");
             println!("[scan_block] Processing transaction: {tx_hash}");
             for (i, call) in tx.calls.iter().enumerate() {
             for (i, call) in tx.calls.iter().enumerate() {
                 if call.data.contract_id == *MONEY_CONTRACT_ID {
                 if call.data.contract_id == *MONEY_CONTRACT_ID {
                     println!("[scan_block] Found Money contract in call {i}");
                     println!("[scan_block] Found Money contract in call {i}");
-                    self.apply_tx_money_data(i, &tx.calls, &tx_hash).await?;
+                    if self.apply_tx_money_data(i, &tx.calls, &tx_hash).await? {
+                        wallet_tx = true;
+                    };
                     continue
                     continue
                 }
                 }
 
 
                 if call.data.contract_id == *DAO_CONTRACT_ID {
                 if call.data.contract_id == *DAO_CONTRACT_ID {
                     println!("[scan_block] Found DAO contract in call {i}");
                     println!("[scan_block] Found DAO contract in call {i}");
-                    self.apply_tx_dao_data(
-                        &call.data.data,
-                        TransactionHash::new(*blake3::hash(&serialize_async(tx).await).as_bytes()),
-                        i as u8,
-                    )
-                    .await?;
+                    if self
+                        .apply_tx_dao_data(
+                            &call.data.data,
+                            TransactionHash::new(
+                                *blake3::hash(&serialize_async(tx).await).as_bytes(),
+                            ),
+                            i as u8,
+                        )
+                        .await?
+                    {
+                        wallet_tx = true;
+                    };
                     continue
                     continue
                 }
                 }
 
 
@@ -218,6 +214,18 @@ impl Drk {
                 // TODO: For now we skip non-native contract calls
                 // TODO: For now we skip non-native contract calls
                 println!("[scan_block] Found non-native contract in call {i}, skipping.");
                 println!("[scan_block] Found non-native contract in call {i}, skipping.");
             }
             }
+
+            // If this is our wallet tx we mark it for update
+            if wallet_tx {
+                wallet_txs.push(tx);
+            }
+        }
+
+        // Update wallet transactions records
+        if let Err(e) = self.put_tx_history_records(&wallet_txs, "Finalized").await {
+            return Err(Error::DatabaseError(format!(
+                "[scan_block] Inserting transaction history records failed: {e:?}"
+            )))
         }
         }
 
 
         // Write this block height into `last_scanned_block`
         // Write this block height into `last_scanned_block`
@@ -244,11 +252,12 @@ impl Drk {
             self.reset_money_tree().await?;
             self.reset_money_tree().await?;
             self.reset_money_smt()?;
             self.reset_money_smt()?;
             self.reset_money_coins()?;
             self.reset_money_coins()?;
+            self.reset_mint_authorities()?;
             self.reset_dao_trees().await?;
             self.reset_dao_trees().await?;
             self.reset_daos().await?;
             self.reset_daos().await?;
             self.reset_dao_proposals().await?;
             self.reset_dao_proposals().await?;
             self.reset_dao_votes()?;
             self.reset_dao_votes()?;
-            self.update_all_tx_history_records_status("Rejected")?;
+            self.reset_tx_history()?;
             height = 0;
             height = 0;
         } else {
         } else {
             height += 1;
             height += 1;
@@ -289,8 +298,6 @@ impl Drk {
                     eprintln!("[scan_blocks] Scan block failed: {e:?}");
                     eprintln!("[scan_blocks] Scan block failed: {e:?}");
                     return Err(WalletDbError::GenericError)
                     return Err(WalletDbError::GenericError)
                 };
                 };
-                let txs_hashes = self.insert_tx_history_records(&block.txs).await?;
-                self.update_tx_history_records_status(&txs_hashes, "Finalized")?;
                 height += 1;
                 height += 1;
             }
             }
         }
         }
@@ -322,7 +329,7 @@ impl Drk {
         let txid = rep.get::<String>().unwrap().clone();
         let txid = rep.get::<String>().unwrap().clone();
 
 
         // Store transactions history record
         // Store transactions history record
-        if let Err(e) = self.insert_tx_history_record(tx).await {
+        if let Err(e) = self.put_tx_history_record(tx, "Broadcasted").await {
             return Err(Error::DatabaseError(format!(
             return Err(Error::DatabaseError(format!(
                 "[broadcast_tx] Inserting transaction history record failed: {e:?}"
                 "[broadcast_tx] Inserting transaction history record failed: {e:?}"
             )))
             )))

+ 8 - 0
bin/drk/src/token.rs

@@ -48,6 +48,7 @@ use darkfi_serial::{deserialize_async, serialize_async, AsyncEncodable};
 
 
 use crate::{
 use crate::{
     convert_named_params,
     convert_named_params,
+    error::WalletDbResult,
     money::{
     money::{
         BALANCE_BASE10_DECIMALS, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_MINT_AUTHORITY,
         BALANCE_BASE10_DECIMALS, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_MINT_AUTHORITY,
         MONEY_TOKENS_COL_TOKEN_BLIND, MONEY_TOKENS_COL_TOKEN_ID, MONEY_TOKENS_TABLE,
         MONEY_TOKENS_COL_TOKEN_BLIND, MONEY_TOKENS_COL_TOKEN_ID, MONEY_TOKENS_TABLE,
@@ -152,6 +153,13 @@ impl Drk {
         Ok((token_id, mint_authority, token_blind, frozen != 0))
         Ok((token_id, mint_authority, token_blind, frozen != 0))
     }
     }
 
 
+    /// Reset all token mint authorities frozen status in the wallet.
+    pub fn reset_mint_authorities(&self) -> WalletDbResult<()> {
+        let query =
+            format!("UPDATE {} SET {} = 0", *MONEY_TOKENS_TABLE, MONEY_TOKENS_COL_IS_FROZEN,);
+        self.wallet.exec_sql(&query, &[])
+    }
+
     /// Fetch all token mint authorities from the wallet.
     /// Fetch all token mint authorities from the wallet.
     pub async fn get_mint_authorities(&self) -> Result<Vec<(TokenId, SecretKey, BaseBlind, bool)>> {
     pub async fn get_mint_authorities(&self) -> Result<Vec<(TokenId, SecretKey, BaseBlind, bool)>> {
         let rows = match self.wallet.query_multiple(&MONEY_TOKENS_TABLE, &[], &[]) {
         let rows = match self.wallet.query_multiple(&MONEY_TOKENS_TABLE, &[], &[]) {

+ 23 - 39
bin/drk/src/txs_history.rs

@@ -35,32 +35,37 @@ const WALLET_TXS_HISTORY_COL_STATUS: &str = "status";
 const WALLET_TXS_HISTORY_COL_TX: &str = "tx";
 const WALLET_TXS_HISTORY_COL_TX: &str = "tx";
 
 
 impl Drk {
 impl Drk {
-    /// Insert a `Transaction` history record into the wallet.
-    pub async fn insert_tx_history_record(&self, tx: &Transaction) -> WalletDbResult<String> {
+    /// Insert or update a `Transaction` history record into the wallet,
+    /// with the provided status.
+    pub async fn put_tx_history_record(
+        &self,
+        tx: &Transaction,
+        status: &str,
+    ) -> WalletDbResult<String> {
         let query = format!(
         let query = format!(
-            "INSERT OR IGNORE INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
+            "INSERT OR UPDATE INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
             WALLET_TXS_HISTORY_TABLE,
             WALLET_TXS_HISTORY_TABLE,
             WALLET_TXS_HISTORY_COL_TX_HASH,
             WALLET_TXS_HISTORY_COL_TX_HASH,
             WALLET_TXS_HISTORY_COL_STATUS,
             WALLET_TXS_HISTORY_COL_STATUS,
             WALLET_TXS_HISTORY_COL_TX,
             WALLET_TXS_HISTORY_COL_TX,
         );
         );
         let tx_hash = tx.hash().to_string();
         let tx_hash = tx.hash().to_string();
-        self.wallet.exec_sql(
-            &query,
-            rusqlite::params![tx_hash, "Broadcasted", &serialize_async(tx).await,],
-        )?;
+        self.wallet
+            .exec_sql(&query, rusqlite::params![tx_hash, status, &serialize_async(tx).await,])?;
 
 
         Ok(tx_hash)
         Ok(tx_hash)
     }
     }
 
 
-    /// Insert a slice of [`Transaction`] history records into the wallet.
-    pub async fn insert_tx_history_records(
+    /// Insert or update a slice of [`Transaction`] history records into the wallet,
+    /// with the provided status.
+    pub async fn put_tx_history_records(
         &self,
         &self,
-        txs: &[Transaction],
+        txs: &[&Transaction],
+        status: &str,
     ) -> WalletDbResult<Vec<String>> {
     ) -> WalletDbResult<Vec<String>> {
         let mut ret = Vec::with_capacity(txs.len());
         let mut ret = Vec::with_capacity(txs.len());
         for tx in txs {
         for tx in txs {
-            ret.push(self.insert_tx_history_record(tx).await?);
+            ret.push(self.put_tx_history_record(tx, status).await?);
         }
         }
         Ok(ret)
         Ok(ret)
     }
     }
@@ -127,34 +132,13 @@ impl Drk {
         Ok(ret)
         Ok(ret)
     }
     }
 
 
-    /// Update given transactions history record statuses to the given one.
-    pub fn update_tx_history_records_status(
-        &self,
-        txs_hashes: &[String],
-        status: &str,
-    ) -> WalletDbResult<()> {
-        if txs_hashes.is_empty() {
-            return Ok(())
-        }
+    /// Reset the transaction history records in the wallet.
+    pub fn reset_tx_history(&self) -> WalletDbResult<()> {
+        println!("Resetting transactions history");
+        let query = format!("DELETE FROM {};", WALLET_TXS_HISTORY_TABLE);
+        self.wallet.exec_sql(&query, &[])?;
+        println!("Successfully reset transactions history");
 
 
-        let txs_hashes_string = format!("{:?}", txs_hashes).replace('[', "(").replace(']', ")");
-        let query = format!(
-            "UPDATE {} SET {} = ?1 WHERE {} IN {};",
-            WALLET_TXS_HISTORY_TABLE,
-            WALLET_TXS_HISTORY_COL_STATUS,
-            WALLET_TXS_HISTORY_COL_TX_HASH,
-            txs_hashes_string
-        );
-
-        self.wallet.exec_sql(&query, rusqlite::params![status])
-    }
-
-    /// Update all transaction history records statuses to the given one.
-    pub fn update_all_tx_history_records_status(&self, status: &str) -> WalletDbResult<()> {
-        let query = format!(
-            "UPDATE {} SET {} = ?1",
-            WALLET_TXS_HISTORY_TABLE, WALLET_TXS_HISTORY_COL_STATUS,
-        );
-        self.wallet.exec_sql(&query, rusqlite::params![status])
+        Ok(())
     }
     }
 }
 }