1use rusqlite::types::Value;
20
21use darkfi::{tx::Transaction, Error, Result};
22use darkfi_serial::{deserialize_async, serialize_async};
23
24use crate::{
25 convert_named_params,
26 error::{WalletDbError, WalletDbResult},
27 Drk,
28};
29
30const WALLET_TXS_HISTORY_TABLE: &str = "transactions_history";
33const WALLET_TXS_HISTORY_COL_TX_HASH: &str = "transaction_hash";
34const WALLET_TXS_HISTORY_COL_STATUS: &str = "status";
35const WALLET_TXS_HISTORY_COL_TX: &str = "tx";
36
37impl Drk {
38 pub async fn put_tx_history_record(
41 &self,
42 tx: &Transaction,
43 status: &str,
44 ) -> WalletDbResult<String> {
45 let query = format!(
47 "INSERT OR REPLACE INTO {WALLET_TXS_HISTORY_TABLE} ({WALLET_TXS_HISTORY_COL_TX_HASH}, {WALLET_TXS_HISTORY_COL_STATUS}, {WALLET_TXS_HISTORY_COL_TX}) VALUES (?1, ?2, ?3);"
48 );
49
50 let tx_hash = tx.hash().to_string();
52 let inverse = self.wallet.create_prepared_statement(
54 &format!(
55 "UPDATE {WALLET_TXS_HISTORY_TABLE} SET {WALLET_TXS_HISTORY_COL_STATUS} = ?1 WHERE {WALLET_TXS_HISTORY_COL_TX_HASH} = ?2;"
56 ),
57 rusqlite::params!["Reverted", tx_hash],
58 )?;
59
60 self.wallet
62 .exec_sql(&query, rusqlite::params![tx_hash, status, &serialize_async(tx).await,])?;
63
64 self.wallet.cache_inverse(inverse)?;
66
67 Ok(tx_hash)
68 }
69
70 pub async fn put_tx_history_records(
73 &self,
74 txs: &[&Transaction],
75 status: &str,
76 ) -> WalletDbResult<Vec<String>> {
77 let mut ret = Vec::with_capacity(txs.len());
78 for tx in txs {
79 ret.push(self.put_tx_history_record(tx, status).await?);
80 }
81 Ok(ret)
82 }
83
84 pub async fn get_tx_history_record(
86 &self,
87 tx_hash: &str,
88 ) -> Result<(String, String, Transaction)> {
89 let row = match self.wallet.query_single(
90 WALLET_TXS_HISTORY_TABLE,
91 &[],
92 convert_named_params! {(WALLET_TXS_HISTORY_COL_TX_HASH, tx_hash)},
93 ) {
94 Ok(r) => r,
95 Err(e) => {
96 return Err(Error::DatabaseError(format!(
97 "[get_tx_history_record] Transaction history record retrieval failed: {e:?}"
98 )))
99 }
100 };
101
102 let Value::Text(ref tx_hash) = row[0] else {
103 return Err(Error::ParseFailed(
104 "[get_tx_history_record] Transaction hash parsing failed",
105 ))
106 };
107
108 let Value::Text(ref status) = row[1] else {
109 return Err(Error::ParseFailed("[get_tx_history_record] Status parsing failed"))
110 };
111
112 let Value::Blob(ref bytes) = row[2] else {
113 return Err(Error::ParseFailed(
114 "[get_tx_history_record] Transaction bytes parsing failed",
115 ))
116 };
117 let tx: Transaction = deserialize_async(bytes).await?;
118
119 Ok((tx_hash.clone(), status.clone(), tx))
120 }
121
122 pub fn get_txs_history(&self) -> WalletDbResult<Vec<(String, String)>> {
124 let rows = self.wallet.query_multiple(
125 WALLET_TXS_HISTORY_TABLE,
126 &[WALLET_TXS_HISTORY_COL_TX_HASH, WALLET_TXS_HISTORY_COL_STATUS],
127 &[],
128 )?;
129
130 let mut ret = Vec::with_capacity(rows.len());
131 for row in rows {
132 let Value::Text(ref tx_hash) = row[0] else {
133 return Err(WalletDbError::ParseColumnValueError)
134 };
135
136 let Value::Text(ref status) = row[1] else {
137 return Err(WalletDbError::ParseColumnValueError)
138 };
139
140 ret.push((tx_hash.clone(), status.clone()));
141 }
142
143 Ok(ret)
144 }
145
146 pub fn reset_tx_history(&self) -> WalletDbResult<()> {
148 println!("Resetting transactions history");
149 let query = format!("DELETE FROM {WALLET_TXS_HISTORY_TABLE};");
150 self.wallet.exec_sql(&query, &[])?;
151 println!("Successfully reset transactions history");
152
153 Ok(())
154 }
155
156 pub fn remove_reverted_txs(&self) -> WalletDbResult<()> {
159 println!("Removing reverted transactions history records");
160 let query = format!(
161 "DELETE FROM {WALLET_TXS_HISTORY_TABLE} WHERE {WALLET_TXS_HISTORY_COL_STATUS} = 'Reverted';"
162 );
163 self.wallet.exec_sql(&query, &[])?;
164 println!("Successfully removed reverted transactions history records");
165
166 Ok(())
167 }
168}