From 81ea21bca596401e1080232a74925871ea2e60b5 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 29 Feb 2024 13:06:06 +0100 Subject: [PATCH 01/15] save dev state --- mm2src/coins/z_coin.rs | 123 +-------- .../z_coin/storage/walletdb/wasm/storage.rs | 2 +- mm2src/coins/z_coin/z_tx_history.rs | 248 ++++++++++++++++++ 3 files changed, 259 insertions(+), 114 deletions(-) create mode 100644 mm2src/coins/z_coin/z_tx_history.rs diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 3ec97cd558..8de595c3c5 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -86,10 +86,7 @@ pub use z_rpc::{FirstSyncBlock, SyncStatus}; cfg_native!( use crate::utxo::utxo_common::{addresses_from_script, big_decimal_from_sat}; - use common::{async_blocking, sha256_digest, calc_total_pages, PagingOptionsEnum}; - use db_common::sqlite::offset_by_id; - use db_common::sqlite::rusqlite::{Error as SqlError, Row}; - use db_common::sqlite::sql_builder::{name, SqlBuilder, SqlName}; + use common::{async_blocking, sha256_digest, calc_total_pages}; use zcash_client_sqlite::error::SqliteClientError as ZcashClientError; use zcash_client_sqlite::wallet::get_balance; use zcash_proofs::default_params_folder; @@ -106,12 +103,14 @@ cfg_wasm32!( #[allow(unused)] mod z_coin_errors; use crate::z_coin::storage::{BlockDbImpl, WalletDbShared}; +use crate::z_coin::z_tx_history::{fetch_tx_history_from_db, ZCoinTxHistoryItem}; pub use z_coin_errors::*; pub mod storage; #[cfg(all(test, feature = "zhtlc-native-tests"))] mod z_coin_native_tests; #[cfg(target_arch = "wasm32")] mod z_params; +mod z_tx_history; /// `ZP2SHSpendError` compatible `TransactionErr` handling macro. macro_rules! try_ztx_s { @@ -138,7 +137,6 @@ cfg_native!( const SAPLING_OUTPUT_NAME: &str = "sapling-output.params"; const SAPLING_SPEND_NAME: &str = "sapling-spend.params"; const BLOCKS_TABLE: &str = "blocks"; - const TRANSACTIONS_TABLE: &str = "transactions"; const SAPLING_SPEND_EXPECTED_HASH: &str = "8e48ffd23abb3a5fd9c5589204f32d9c31285a04b78096ba40a79b75677efc13"; const SAPLING_OUTPUT_EXPECTED_HASH: &str = "2f0ebbcbb9bb0bcffe95a397e7eba89c29eb4dde6191c339db88570e3f3fb0e4"; ); @@ -240,39 +238,6 @@ pub struct ZOutput { pub memo: Option, } -#[cfg(not(target_arch = "wasm32"))] -struct ZCoinSqlTxHistoryItem { - tx_hash: Vec, - internal_id: i64, - height: i64, - timestamp: i64, - received_amount: i64, - spent_amount: i64, -} - -#[cfg(not(target_arch = "wasm32"))] -impl ZCoinSqlTxHistoryItem { - fn try_from_sql_row(row: &Row<'_>) -> Result { - let mut tx_hash: Vec = row.get(0)?; - tx_hash.reverse(); - Ok(ZCoinSqlTxHistoryItem { - tx_hash, - internal_id: row.get(1)?, - height: row.get(2)?, - timestamp: row.get(3)?, - received_amount: row.get(4)?, - spent_amount: row.get(5)?, - }) - } -} - -#[cfg(not(target_arch = "wasm32"))] -struct SqlTxHistoryRes { - transactions: Vec, - total_tx_count: u32, - skipped: usize, -} - #[derive(Serialize)] pub struct ZcoinTxDetails { /// Transaction hash in hexadecimal format @@ -531,72 +496,6 @@ impl ZCoin { Ok(tx) } - #[cfg(not(target_arch = "wasm32"))] - async fn tx_history_from_sql( - &self, - limit: usize, - paging_options: PagingOptionsEnum, - ) -> Result> { - let wallet_db = self.z_fields.light_wallet_db.clone(); - async_blocking(move || { - let db_guard = wallet_db.db.inner(); - let db_guard = db_guard.lock().unwrap(); - let conn = db_guard.sql_conn(); - - let total_sql = SqlBuilder::select_from(TRANSACTIONS_TABLE) - .field("COUNT(id_tx)") - .sql() - .expect("valid SQL"); - let total_tx_count = conn.query_row(&total_sql, [], |row| row.get(0))?; - - let mut sql_builder = SqlBuilder::select_from(name!(TRANSACTIONS_TABLE; "txes")); - sql_builder - .field("txes.txid") - .field("txes.id_tx as internal_id") - .field("txes.block as block"); - - let offset = match paging_options { - PagingOptionsEnum::PageNumber(page) => (page.get() - 1) * limit, - PagingOptionsEnum::FromId(id) => { - offset_by_id(conn, &sql_builder, [id], "id_tx", "block DESC, id_tx ASC", "id_tx = ?1")? - .ok_or(SqlTxHistoryError::FromIdDoesNotExist(id))? - }, - }; - - let sql = sql_builder - .field("blocks.time") - .field("COALESCE(rn.received_amount, 0)") - .field("COALESCE(sn.sent_amount, 0)") - .left() - .join("(SELECT tx, SUM(value) as received_amount FROM received_notes GROUP BY tx) as rn") - .on("txes.id_tx = rn.tx") - // detecting spent amount by "spent" field in received_notes table - .join("(SELECT spent, SUM(value) as sent_amount FROM received_notes GROUP BY spent) as sn") - .on("txes.id_tx = sn.spent") - .join(BLOCKS_TABLE) - .on("txes.block = blocks.height") - .group_by("internal_id") - .order_by("block", true) - .order_by("internal_id", false) - .offset(offset) - .limit(limit) - .sql() - .expect("valid query"); - - let sql_items = conn - .prepare(&sql)? - .query_map([], ZCoinSqlTxHistoryItem::try_from_sql_row)? - .collect::, _>>()?; - - Ok(SqlTxHistoryRes { - transactions: sql_items, - total_tx_count, - skipped: offset, - }) - }) - .await - } - #[cfg(not(target_arch = "wasm32"))] async fn z_transactions_from_cache_or_rpc( &self, @@ -616,7 +515,7 @@ impl ZCoin { #[cfg(not(target_arch = "wasm32"))] fn tx_details_from_sql_item( &self, - sql_item: ZCoinSqlTxHistoryItem, + sql_item: ZCoinTxHistoryItem, transactions: &mut HashMap, prev_transactions: &HashMap, current_block: u64, @@ -715,11 +614,9 @@ impl ZCoin { request: MyTxHistoryRequestV2, ) -> Result, MmError> { let current_block = self.utxo_rpc_client().get_block_count().compat().await?; - let sql_result = self - .tx_history_from_sql(request.limit, request.paging_options.clone()) - .await?; + let req_result = fetch_tx_history_from_db(self, request.limit, request.paging_options.clone()).await?; - let hashes_for_verbose = sql_result + let hashes_for_verbose = req_result .transactions .iter() .map(|item| H256Json::from(item.tx_hash.as_slice())) @@ -738,7 +635,7 @@ impl ZCoin { .collect(); let prev_transactions = self.z_transactions_from_cache_or_rpc(prev_tx_hashes).await?; - let transactions = sql_result + let transactions = req_result .transactions .into_iter() .map(|sql_item| { @@ -754,9 +651,9 @@ impl ZCoin { // Zcoin is activated only after the state is synced sync_status: HistorySyncState::Finished, limit: request.limit, - skipped: sql_result.skipped, - total: sql_result.total_tx_count as usize, - total_pages: calc_total_pages(sql_result.total_tx_count as usize, request.limit), + skipped: req_result.skipped, + total: req_result.total_tx_count as usize, + total_pages: calc_total_pages(req_result.total_tx_count as usize, request.limit), paging_options: request.paging_options, }) } diff --git a/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs b/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs index e55b9e64d0..bf99dec6ca 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs @@ -146,7 +146,7 @@ impl<'a> WalletIndexedDb { Ok(db) } - async fn lock_db(&self) -> ZcoinStorageRes> { + pub(crate) async fn lock_db(&self) -> ZcoinStorageRes> { self.db .get_or_initialize() .await diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs new file mode 100644 index 0000000000..761d862842 --- /dev/null +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -0,0 +1,248 @@ +use crate::my_tx_history_v2::MyTxHistoryErrorV2; +use crate::z_coin::storage::wasm::tables::{WalletDbAccountsTable, WalletDbBlocksTable, WalletDbReceivedNotesTable, + WalletDbSentNotesTable, WalletDbTransactionsTable}; +use crate::z_coin::ZCoin; +use crate::MarketCoinOps; +use common::PagingOptionsEnum; +use mm2_db::indexed_db::cursor_prelude::CursorError; +use mm2_db::indexed_db::DbTransactionError; +use mm2_err_handle::prelude::MmError; +use mm2_number::BigInt; +use std::collections::HashMap; + +cfg_native!( + use db_common::sqlite::sql_builder::{name, SqlBuilder, SqlName}; + use db_common::sqlite::rusqlite::Error as SqliteError; + use db_common::sqlite::rusqlite::Row; + use db_common::sqlite::offset_by_id; + use common::async_blocking; + use crate::z_coin::{BLOCKS_TABLE}; +); + +#[cfg(not(target_arch = "wasm32"))] +const TRANSACTIONS_TABLE: &str = "transactions"; + +pub(crate) enum ZTxHistoryError { + #[cfg(not(target_arch = "wasm32"))] + Sql(SqliteError), + #[cfg(target_arch = "wasm32")] + IndexedDbError(String), + FromIdDoesNotExist(i64), +} + +impl From for MyTxHistoryErrorV2 { + fn from(err: ZTxHistoryError) -> Self { + match err { + #[cfg(not(target_arch = "wasm32"))] + ZTxHistoryError::Sql(sql) => MyTxHistoryErrorV2::StorageError(sql.to_string()), + ZTxHistoryError::FromIdDoesNotExist(id) => { + MyTxHistoryErrorV2::StorageError(format!("from_id {} does not exist", id)) + }, + #[cfg(target_arch = "wasm32")] + ZTxHistoryError::IndexedDbError(err) => MyTxHistoryErrorV2::StorageError(err), + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl From for ZTxHistoryError { + fn from(err: SqliteError) -> Self { ZTxHistoryError::Sql(err) } +} + +#[cfg(target_arch = "wasm32")] +impl From for ZTxHistoryError { + fn from(err: DbTransactionError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } +} + +#[cfg(target_arch = "wasm32")] +impl From for ZTxHistoryError { + fn from(err: DbTransactionError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } +} + +pub(crate) struct ZCoinTxHistoryItem { + pub(crate) tx_hash: Vec, + pub(crate) internal_id: i64, + pub(crate) height: i64, + pub(crate) timestamp: i64, + pub(crate) received_amount: i64, + pub(crate) spent_amount: i64, +} + +#[cfg(not(target_arch = "wasm32"))] +impl ZCoinTxHistoryItem { + fn try_from_sql_row(row: &Row<'_>) -> Result { + let mut tx_hash: Vec = row.get(0)?; + tx_hash.reverse(); + Ok(ZCoinTxHistoryItem { + tx_hash, + internal_id: row.get(1)?, + height: row.get(2)?, + timestamp: row.get(3)?, + received_amount: row.get(4)?, + spent_amount: row.get(5)?, + }) + } +} + +pub(crate) struct ZTxHistoryRes { + pub(crate) transactions: Vec, + pub(crate) total_tx_count: u32, + pub(crate) skipped: usize, +} + +#[cfg(target_arch = "wasm32")] +pub(crate) async fn fetch_tx_history_from_db( + z: &ZCoin, + limit: usize, + paging_options: PagingOptionsEnum, +) -> Result> { + let wallet_db = z.z_fields.light_wallet_db.clone(); + let wallet_db = wallet_db.db.lock_db().await.unwrap(); + let db_transaction = wallet_db.get_inner().transaction().await?; + let tx_table = db_transaction.table::().await?; + let tx_count = tx_table.count_all().await?; + let offset = match paging_options { + PagingOptionsEnum::FromId(from_address_id) => from_address_id + 1, + PagingOptionsEnum::PageNumber(page_number) => ((page_number.get() - 1) * limit) as u32, + }; + + let txs = tx_table + .cursor_builder() + .only("ticker", &z.ticker())? + .bound("height", 0u32, u32::MAX) + .where_first() + .open_cursor(WalletDbAccountsTable::TICKER_ACCOUNT_INDEX) + .await? + .collect() + .await?; + + let rn_table = db_transaction.table::().await?; + let received_notes = rn_table + .cursor_builder() + .only("ticker", &z.ticker())? + .bound("height", 0u32, u32::MAX) + .where_first() + .open_cursor(WalletDbReceivedNotesTable::TICKER_ACCOUNT_INDEX) + .await? + .collect() + .await?; + + // detect blocks + let blocks_table = db_transaction.table::().await?; + let blocks = blocks_table + .cursor_builder() + .only("ticker", &z.ticker())? + .where_first() + .open_cursor("ticker") + .await? + .collect() + .await?; + + let mut tx_details = vec![]; + for (tx_id, tx) in txs { + let height = blocks + .iter() + .find(|(_, block)| tx.block.map(|b| b == block.height).unwrap_or_default()); + if let Some((_, WalletDbBlocksTable { height, time, .. })) = height { + let internal_id = tx_id; + let mut tx_hash = tx.txid; + let mut received_amount = 0; + let mut spent_amount = 0; + + for (_, note) in received_notes { + if let Some(_) = txs.iter().find(|(id_tx, tx)| *internal_id == note.tx) { + *received_amount += ¬e.value; + }; + + // detecting spent amount by "spent" field in received_notes table + if let Some(spent) = ¬e.spent { + if let Some(_) = txs.iter().find(|(id_tx, tx)| &BigInt::from(internal_id) == spent) { + *spent_amount += ¬e.value; + }; + } + } + + tx_hash.reverse(); + tx_details.push(ZCoinTxHistoryItem { + tx_hash, + internal_id: internal_id as i64, + height: *height as i64, + timestamp: *time as i64, + received_amount, + spent_amount, + }); + } + } + + Ok(ZTxHistoryRes { + transactions: tx_details, + total_tx_count, + skipped: offset as usize, + }) +} + +#[cfg(not(target_arch = "wasm32"))] +pub(crate) async fn fetch_tx_history_from_db( + z: &ZCoin, + limit: usize, + paging_options: PagingOptionsEnum, +) -> Result> { + let wallet_db = z.z_fields.light_wallet_db.clone(); + async_blocking(move || { + let db_guard = wallet_db.db.inner(); + let db_guard = db_guard.lock().unwrap(); + let conn = db_guard.sql_conn(); + + let total_sql = SqlBuilder::select_from(TRANSACTIONS_TABLE) + .field("COUNT(id_tx)") + .sql() + .expect("valid SQL"); + let total_tx_count = conn.query_row(&total_sql, [], |row| row.get(0))?; + + let mut sql_builder = SqlBuilder::select_from(name!(TRANSACTIONS_TABLE; "txes")); + sql_builder + .field("txes.txid") + .field("txes.id_tx as internal_id") + .field("txes.block as block"); + + let offset = match paging_options { + PagingOptionsEnum::PageNumber(page) => (page.get() - 1) * limit, + PagingOptionsEnum::FromId(id) => { + offset_by_id(conn, &sql_builder, [id], "id_tx", "block DESC, id_tx ASC", "id_tx = ?1")? + .ok_or(ZTxHistoryError::FromIdDoesNotExist(id))? + }, + }; + + let sql = sql_builder + .field("blocks.time") + .field("COALESCE(rn.received_amount, 0)") + .field("COALESCE(sn.sent_amount, 0)") + .left() + .join("(SELECT tx, SUM(value) as received_amount FROM received_notes GROUP BY tx) as rn") + .on("txes.id_tx = rn.tx") + // detecting spent amount by "spent" field in received_notes table + .join("(SELECT spent, SUM(value) as sent_amount FROM received_notes GROUP BY spent) as sn") + .on("txes.id_tx = sn.spent") + .join(BLOCKS_TABLE) + .on("txes.block = blocks.height") + .group_by("internal_id") + .order_by("block", true) + .order_by("internal_id", false) + .offset(offset) + .limit(limit) + .sql() + .expect("valid query"); + + let sql_items = conn + .prepare(&sql)? + .query_map([], ZCoinTxHistoryItem::try_from_sql_row)? + .collect::, _>>()?; + + Ok(ZTxHistoryRes { + transactions: sql_items, + total_tx_count, + skipped: offset, + }) + }) + .await +} From 2f0bade54a32b9dbcc81487cf0ab7c7235d01342 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 29 Feb 2024 13:16:17 +0100 Subject: [PATCH 02/15] remove all where_first --- mm2src/coins/z_coin/z_tx_history.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index 761d862842..d224a76e8f 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -110,7 +110,6 @@ pub(crate) async fn fetch_tx_history_from_db( .cursor_builder() .only("ticker", &z.ticker())? .bound("height", 0u32, u32::MAX) - .where_first() .open_cursor(WalletDbAccountsTable::TICKER_ACCOUNT_INDEX) .await? .collect() @@ -121,7 +120,6 @@ pub(crate) async fn fetch_tx_history_from_db( .cursor_builder() .only("ticker", &z.ticker())? .bound("height", 0u32, u32::MAX) - .where_first() .open_cursor(WalletDbReceivedNotesTable::TICKER_ACCOUNT_INDEX) .await? .collect() @@ -132,7 +130,6 @@ pub(crate) async fn fetch_tx_history_from_db( let blocks = blocks_table .cursor_builder() .only("ticker", &z.ticker())? - .where_first() .open_cursor("ticker") .await? .collect() From 0811bd73c0b698397bf86282ceafe99aabfc7437 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 29 Feb 2024 13:20:28 +0100 Subject: [PATCH 03/15] update note finding logic --- mm2src/coins/z_coin/z_tx_history.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index d224a76e8f..5d8f1c8171 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -147,15 +147,15 @@ pub(crate) async fn fetch_tx_history_from_db( let mut spent_amount = 0; for (_, note) in received_notes { - if let Some(_) = txs.iter().find(|(id_tx, tx)| *internal_id == note.tx) { + if *internal_id == note.tx { *received_amount += ¬e.value; - }; + } // detecting spent amount by "spent" field in received_notes table if let Some(spent) = ¬e.spent { - if let Some(_) = txs.iter().find(|(id_tx, tx)| &BigInt::from(internal_id) == spent) { + if &BigInt::from(internal_id) == spent { *spent_amount += ¬e.value; - }; + } } } From e8167fd4a113bd4b306bbefa6c5c485ba1cb0dd6 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 29 Feb 2024 17:16:35 +0100 Subject: [PATCH 04/15] save dev state --- mm2src/coins/z_coin.rs | 37 +++++++++++++---------------- mm2src/coins/z_coin/z_tx_history.rs | 23 +++++++++++------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 8de595c3c5..191248076c 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1,5 +1,4 @@ use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; -#[cfg(not(target_arch = "wasm32"))] use crate::my_tx_history_v2::{MyTxHistoryErrorV2, MyTxHistoryRequestV2, MyTxHistoryResponseV2}; use crate::rpc_command::init_withdraw::{InitWithdrawCoin, WithdrawInProgressStatus, WithdrawTaskHandleShared}; use crate::utxo::rpc_clients::{ElectrumRpcRequest, UnspentInfo, UtxoRpcClientEnum, UtxoRpcError, UtxoRpcFut, @@ -7,6 +6,7 @@ use crate::utxo::rpc_clients::{ElectrumRpcRequest, UnspentInfo, UtxoRpcClientEnu use crate::utxo::utxo_builder::UtxoCoinBuildError; use crate::utxo::utxo_builder::{UtxoCoinBuilder, UtxoCoinBuilderCommonOps, UtxoFieldsWithGlobalHDBuilder, UtxoFieldsWithHardwareWalletBuilder, UtxoFieldsWithIguanaSecretBuilder}; +use crate::utxo::utxo_common::{addresses_from_script, big_decimal_from_sat}; use crate::utxo::utxo_common::{big_decimal_from_sat_unsigned, payment_script}; use crate::utxo::{sat_from_big_decimal, utxo_common, ActualTxFee, AdditionalTxData, AddrFromStrError, Address, BroadcastTxErr, FeePolicy, GetUtxoListOps, HistoryUtxoTx, HistoryUtxoTxMap, MatureUnspentList, @@ -35,6 +35,7 @@ use bitcrypto::dhash256; use chain::constants::SEQUENCE_FINAL; use chain::{Transaction as UtxoTx, TransactionOutput}; use common::executor::{AbortableSystem, AbortedError}; +use common::{calc_total_pages, sha256_digest}; use common::{log, one_thousand_u32}; use crypto::privkey::{key_pair_from_secret, secp_privkey_from_hash}; use crypto::{Bip32DerPathOps, GlobalHDAccountArc}; @@ -85,12 +86,11 @@ use z_rpc::init_light_client; pub use z_rpc::{FirstSyncBlock, SyncStatus}; cfg_native!( - use crate::utxo::utxo_common::{addresses_from_script, big_decimal_from_sat}; - use common::{async_blocking, sha256_digest, calc_total_pages}; + use common::async_blocking; use zcash_client_sqlite::error::SqliteClientError as ZcashClientError; use zcash_client_sqlite::wallet::get_balance; use zcash_proofs::default_params_folder; - use z_rpc::{init_native_client}; + use z_rpc::init_native_client; ); cfg_wasm32!( @@ -496,7 +496,6 @@ impl ZCoin { Ok(tx) } - #[cfg(not(target_arch = "wasm32"))] async fn z_transactions_from_cache_or_rpc( &self, hashes: HashSet, @@ -512,23 +511,22 @@ impl ZCoin { .map_to_mm(|e| UtxoRpcError::InvalidResponse(e.to_string())) } - #[cfg(not(target_arch = "wasm32"))] - fn tx_details_from_sql_item( + fn tx_details_from_db_item( &self, - sql_item: ZCoinTxHistoryItem, + tx_item: ZCoinTxHistoryItem, transactions: &mut HashMap, prev_transactions: &HashMap, current_block: u64, ) -> Result> { let mut from = HashSet::new(); - let mut confirmations = current_block as i64 - sql_item.height + 1; + let mut confirmations = current_block as i64 - tx_item.height + 1; if confirmations < 0 { confirmations = 0; } let mut transparent_input_amount = Amount::zero(); - let hash = H256Json::from(sql_item.tx_hash.as_slice()); + let hash = H256Json::from(tx_item.tx_hash.as_slice()); let z_tx = transactions.remove(&hash).or_mm_err(|| NoInfoAboutTx(hash))?; for input in z_tx.vin.iter() { let mut hash = H256Json::from(*input.prevout.hash()); @@ -556,11 +554,11 @@ impl ZCoin { } let fee_amount = z_tx.value_balance + transparent_input_amount - transparent_output_amount; - if sql_item.spent_amount > 0 { + if tx_item.spent_amount > 0 { from.insert(self.my_z_address_encoded()); } - if sql_item.received_amount > 0 { + if tx_item.received_amount > 0 { to.insert(self.my_z_address_encoded()); } @@ -590,25 +588,24 @@ impl ZCoin { } } - let spent_by_me = big_decimal_from_sat(sql_item.spent_amount, self.decimals()); - let received_by_me = big_decimal_from_sat(sql_item.received_amount, self.decimals()); + let spent_by_me = big_decimal_from_sat(tx_item.spent_amount, self.decimals()); + let received_by_me = big_decimal_from_sat(tx_item.received_amount, self.decimals()); Ok(ZcoinTxDetails { - tx_hash: hex::encode(sql_item.tx_hash), + tx_hash: hex::encode(tx_item.tx_hash), from, to, my_balance_change: &received_by_me - &spent_by_me, spent_by_me, received_by_me, - block_height: sql_item.height, + block_height: tx_item.height, confirmations, - timestamp: sql_item.timestamp, + timestamp: tx_item.timestamp, transaction_fee: big_decimal_from_sat(fee_amount.into(), self.decimals()), coin: self.ticker().into(), - internal_id: sql_item.internal_id, + internal_id: tx_item.internal_id, }) } - #[cfg(not(target_arch = "wasm32"))] pub async fn tx_history( &self, request: MyTxHistoryRequestV2, @@ -639,7 +636,7 @@ impl ZCoin { .transactions .into_iter() .map(|sql_item| { - self.tx_details_from_sql_item(sql_item, &mut transactions, &prev_transactions, current_block) + self.tx_details_from_db_item(sql_item, &mut transactions, &prev_transactions, current_block) }) .collect::>()?; diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index 5d8f1c8171..cb2f4cf316 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -1,6 +1,6 @@ use crate::my_tx_history_v2::MyTxHistoryErrorV2; use crate::z_coin::storage::wasm::tables::{WalletDbAccountsTable, WalletDbBlocksTable, WalletDbReceivedNotesTable, - WalletDbSentNotesTable, WalletDbTransactionsTable}; + WalletDbTransactionsTable}; use crate::z_coin::ZCoin; use crate::MarketCoinOps; use common::PagingOptionsEnum; @@ -8,7 +8,7 @@ use mm2_db::indexed_db::cursor_prelude::CursorError; use mm2_db::indexed_db::DbTransactionError; use mm2_err_handle::prelude::MmError; use mm2_number::BigInt; -use std::collections::HashMap; +use num_traits::ToPrimitive; cfg_native!( use db_common::sqlite::sql_builder::{name, SqlBuilder, SqlName}; @@ -27,6 +27,7 @@ pub(crate) enum ZTxHistoryError { Sql(SqliteError), #[cfg(target_arch = "wasm32")] IndexedDbError(String), + #[cfg(not(target_arch = "wasm32"))] FromIdDoesNotExist(i64), } @@ -56,7 +57,7 @@ impl From for ZTxHistoryError { #[cfg(target_arch = "wasm32")] impl From for ZTxHistoryError { - fn from(err: DbTransactionError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } + fn from(err: CursorError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } } pub(crate) struct ZCoinTxHistoryItem { @@ -100,10 +101,10 @@ pub(crate) async fn fetch_tx_history_from_db( let wallet_db = wallet_db.db.lock_db().await.unwrap(); let db_transaction = wallet_db.get_inner().transaction().await?; let tx_table = db_transaction.table::().await?; - let tx_count = tx_table.count_all().await?; + let total_tx_count = tx_table.count_all().await? as u32; let offset = match paging_options { PagingOptionsEnum::FromId(from_address_id) => from_address_id + 1, - PagingOptionsEnum::PageNumber(page_number) => ((page_number.get() - 1) * limit) as u32, + PagingOptionsEnum::PageNumber(page_number) => ((page_number.get() - 1) * limit) as i64, }; let txs = tx_table @@ -146,15 +147,19 @@ pub(crate) async fn fetch_tx_history_from_db( let mut received_amount = 0; let mut spent_amount = 0; - for (_, note) in received_notes { - if *internal_id == note.tx { - *received_amount += ¬e.value; + for (_, note) in &received_notes { + if internal_id == note.tx { + received_amount += (*¬e.value.to_u64().ok_or_else(|| { + ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) + })?) as i64; } // detecting spent amount by "spent" field in received_notes table if let Some(spent) = ¬e.spent { if &BigInt::from(internal_id) == spent { - *spent_amount += ¬e.value; + spent_amount += (*¬e.value.to_u64().ok_or_else(|| { + ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) + })?) as i64; } } } From e4c926651f65bb6d3bd17f59bf9823297c488690 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 4 Mar 2024 12:47:24 +0100 Subject: [PATCH 05/15] impl tx_history for WASM and refactoring --- mm2src/coins/z_coin.rs | 4 +- mm2src/coins/z_coin/z_coin_errors.rs | 40 ++++++++++++----- mm2src/coins/z_coin/z_tx_history.rs | 66 ++++++---------------------- 3 files changed, 44 insertions(+), 66 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 191248076c..47d8d8bee9 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -34,8 +34,8 @@ use async_trait::async_trait; use bitcrypto::dhash256; use chain::constants::SEQUENCE_FINAL; use chain::{Transaction as UtxoTx, TransactionOutput}; +use common::calc_total_pages; use common::executor::{AbortableSystem, AbortedError}; -use common::{calc_total_pages, sha256_digest}; use common::{log, one_thousand_u32}; use crypto::privkey::{key_pair_from_secret, secp_privkey_from_hash}; use crypto::{Bip32DerPathOps, GlobalHDAccountArc}; @@ -86,7 +86,7 @@ use z_rpc::init_light_client; pub use z_rpc::{FirstSyncBlock, SyncStatus}; cfg_native!( - use common::async_blocking; + use common::{async_blocking, sha256_digest}; use zcash_client_sqlite::error::SqliteClientError as ZcashClientError; use zcash_client_sqlite::wallet::get_balance; use zcash_proofs::default_params_folder; diff --git a/mm2src/coins/z_coin/z_coin_errors.rs b/mm2src/coins/z_coin/z_coin_errors.rs index f556435f57..3ac5d3ce36 100644 --- a/mm2src/coins/z_coin/z_coin_errors.rs +++ b/mm2src/coins/z_coin/z_coin_errors.rs @@ -272,29 +272,45 @@ impl From for ZCoinBuildError { fn from(err: ZcoinClientInitError) -> Self { ZCoinBuildError::RpcClientInitErr(err) } } -#[cfg(not(target_arch = "wasm32"))] -pub(super) enum SqlTxHistoryError { +pub(crate) enum ZTxHistoryError { + #[cfg(not(target_arch = "wasm32"))] Sql(SqliteError), + #[cfg(target_arch = "wasm32")] + IndexedDbError(String), + #[cfg(not(target_arch = "wasm32"))] FromIdDoesNotExist(i64), } -#[cfg(not(target_arch = "wasm32"))] -impl From for SqlTxHistoryError { - fn from(err: SqliteError) -> Self { SqlTxHistoryError::Sql(err) } -} - -#[cfg(not(target_arch = "wasm32"))] -impl From for MyTxHistoryErrorV2 { - fn from(err: SqlTxHistoryError) -> Self { +impl From for MyTxHistoryErrorV2 { + fn from(err: ZTxHistoryError) -> Self { match err { - SqlTxHistoryError::Sql(sql) => MyTxHistoryErrorV2::StorageError(sql.to_string()), - SqlTxHistoryError::FromIdDoesNotExist(id) => { + #[cfg(not(target_arch = "wasm32"))] + ZTxHistoryError::Sql(sql) => MyTxHistoryErrorV2::StorageError(sql.to_string()), + #[cfg(not(target_arch = "wasm32"))] + ZTxHistoryError::FromIdDoesNotExist(id) => { MyTxHistoryErrorV2::StorageError(format!("from_id {} does not exist", id)) }, + #[cfg(target_arch = "wasm32")] + ZTxHistoryError::IndexedDbError(err) => MyTxHistoryErrorV2::StorageError(err), } } } +#[cfg(not(target_arch = "wasm32"))] +impl From for ZTxHistoryError { + fn from(err: SqliteError) -> Self { ZTxHistoryError::Sql(err) } +} + +#[cfg(target_arch = "wasm32")] +impl From for ZTxHistoryError { + fn from(err: DbTransactionError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } +} + +#[cfg(target_arch = "wasm32")] +impl From for ZTxHistoryError { + fn from(err: CursorError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } +} + pub(super) struct NoInfoAboutTx(pub(super) H256Json); impl From for MyTxHistoryErrorV2 { diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index cb2f4cf316..b1fc509067 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -1,14 +1,14 @@ -use crate::my_tx_history_v2::MyTxHistoryErrorV2; -use crate::z_coin::storage::wasm::tables::{WalletDbAccountsTable, WalletDbBlocksTable, WalletDbReceivedNotesTable, - WalletDbTransactionsTable}; -use crate::z_coin::ZCoin; -use crate::MarketCoinOps; +use crate::z_coin::{ZCoin, ZTxHistoryError}; use common::PagingOptionsEnum; -use mm2_db::indexed_db::cursor_prelude::CursorError; -use mm2_db::indexed_db::DbTransactionError; use mm2_err_handle::prelude::MmError; -use mm2_number::BigInt; -use num_traits::ToPrimitive; + +cfg_wasm32!( + use crate::z_coin::storage::wasm::tables::{WalletDbAccountsTable, WalletDbBlocksTable, WalletDbReceivedNotesTable, + WalletDbTransactionsTable}; + use crate::MarketCoinOps; + use mm2_number::BigInt; + use num_traits::ToPrimitive; +); cfg_native!( use db_common::sqlite::sql_builder::{name, SqlBuilder, SqlName}; @@ -22,44 +22,6 @@ cfg_native!( #[cfg(not(target_arch = "wasm32"))] const TRANSACTIONS_TABLE: &str = "transactions"; -pub(crate) enum ZTxHistoryError { - #[cfg(not(target_arch = "wasm32"))] - Sql(SqliteError), - #[cfg(target_arch = "wasm32")] - IndexedDbError(String), - #[cfg(not(target_arch = "wasm32"))] - FromIdDoesNotExist(i64), -} - -impl From for MyTxHistoryErrorV2 { - fn from(err: ZTxHistoryError) -> Self { - match err { - #[cfg(not(target_arch = "wasm32"))] - ZTxHistoryError::Sql(sql) => MyTxHistoryErrorV2::StorageError(sql.to_string()), - ZTxHistoryError::FromIdDoesNotExist(id) => { - MyTxHistoryErrorV2::StorageError(format!("from_id {} does not exist", id)) - }, - #[cfg(target_arch = "wasm32")] - ZTxHistoryError::IndexedDbError(err) => MyTxHistoryErrorV2::StorageError(err), - } - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl From for ZTxHistoryError { - fn from(err: SqliteError) -> Self { ZTxHistoryError::Sql(err) } -} - -#[cfg(target_arch = "wasm32")] -impl From for ZTxHistoryError { - fn from(err: DbTransactionError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } -} - -#[cfg(target_arch = "wasm32")] -impl From for ZTxHistoryError { - fn from(err: CursorError) -> Self { ZTxHistoryError::IndexedDbError(err.to_string()) } -} - pub(crate) struct ZCoinTxHistoryItem { pub(crate) tx_hash: Vec, pub(crate) internal_id: i64, @@ -109,7 +71,7 @@ pub(crate) async fn fetch_tx_history_from_db( let txs = tx_table .cursor_builder() - .only("ticker", &z.ticker())? + .only("ticker", z.ticker())? .bound("height", 0u32, u32::MAX) .open_cursor(WalletDbAccountsTable::TICKER_ACCOUNT_INDEX) .await? @@ -119,7 +81,7 @@ pub(crate) async fn fetch_tx_history_from_db( let rn_table = db_transaction.table::().await?; let received_notes = rn_table .cursor_builder() - .only("ticker", &z.ticker())? + .only("ticker", z.ticker())? .bound("height", 0u32, u32::MAX) .open_cursor(WalletDbReceivedNotesTable::TICKER_ACCOUNT_INDEX) .await? @@ -130,7 +92,7 @@ pub(crate) async fn fetch_tx_history_from_db( let blocks_table = db_transaction.table::().await?; let blocks = blocks_table .cursor_builder() - .only("ticker", &z.ticker())? + .only("ticker", z.ticker())? .open_cursor("ticker") .await? .collect() @@ -149,7 +111,7 @@ pub(crate) async fn fetch_tx_history_from_db( for (_, note) in &received_notes { if internal_id == note.tx { - received_amount += (*¬e.value.to_u64().ok_or_else(|| { + received_amount += (note.value.to_u64().ok_or_else(|| { ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) })?) as i64; } @@ -157,7 +119,7 @@ pub(crate) async fn fetch_tx_history_from_db( // detecting spent amount by "spent" field in received_notes table if let Some(spent) = ¬e.spent { if &BigInt::from(internal_id) == spent { - spent_amount += (*¬e.value.to_u64().ok_or_else(|| { + spent_amount += (note.value.to_u64().ok_or_else(|| { ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) })?) as i64; } From b9fbba94644865ac169ed03876212f76ebc6aa9b Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 01:01:13 +0100 Subject: [PATCH 06/15] test commit for test_z_coin_tx_history test in ci --- mm2src/coins/z_coin.rs | 24 +++++++++++----------- mm2src/coins/z_coin/z_tx_history.rs | 5 ++++- mm2src/mm2_main/src/wasm_tests.rs | 31 ++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 47d8d8bee9..4e125b0f3a 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -13,22 +13,22 @@ use crate::utxo::{sat_from_big_decimal, utxo_common, ActualTxFee, AdditionalTxDa RecentlySpentOutPointsGuard, UtxoActivationParams, UtxoAddressFormat, UtxoArc, UtxoCoinFields, UtxoCommonOps, UtxoRpcMode, UtxoTxBroadcastOps, UtxoTxGenerationOps, VerboseTransactionFrom}; use crate::utxo::{UnsupportedAddr, UtxoFeeDetails}; -use crate::TxFeeDetails; +use crate::z_coin::storage::{BlockDbImpl, WalletDbShared}; +use crate::z_coin::z_tx_history::{fetch_tx_history_from_db, ZCoinTxHistoryItem}; use crate::{BalanceError, BalanceFut, CheckIfMyPaymentSentArgs, CoinBalance, CoinFutSpawner, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MakerSwapTakerCoin, MarketCoinOps, MmCoin, - MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, + MmCoinEnum, NegotiateSwapContractAddrErr, NumConversError, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyActivationPolicy, PrivKeyBuildPolicy, PrivKeyPolicyNotAllowed, RawTransactionFut, RawTransactionRequest, RawTransactionResult, RefundError, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SignRawTransactionRequest, SignatureError, SignatureResult, SpendPaymentArgs, SwapOps, TakerSwapMakerCoin, - TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionEnum, TransactionFut, - TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, - ValidateInstructionsErr, ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, - ValidatePaymentInput, ValidateWatcherSpendInput, VerificationError, VerificationResult, - WaitForHTLCTxSpendArgs, WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, - WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawFut, WithdrawRequest}; -use crate::{NumConversError, TransactionDetails}; -use crate::{Transaction, WithdrawError}; + TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, + TransactionEnum, TransactionFut, TransactionResult, TxFeeDetails, TxMarshalingErr, + UnexpectedDerivationMethod, ValidateAddressResult, ValidateFeeArgs, ValidateInstructionsErr, + ValidateOtherPubKeyErr, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, + ValidateWatcherSpendInput, VerificationError, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, + WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, + WatcherValidateTakerFeeInput, WithdrawError, WithdrawFut, WithdrawRequest}; use async_trait::async_trait; use bitcrypto::dhash256; @@ -102,8 +102,6 @@ cfg_wasm32!( ); #[allow(unused)] mod z_coin_errors; -use crate::z_coin::storage::{BlockDbImpl, WalletDbShared}; -use crate::z_coin::z_tx_history::{fetch_tx_history_from_db, ZCoinTxHistoryItem}; pub use z_coin_errors::*; pub mod storage; @@ -182,6 +180,8 @@ impl Parameters for ZcoinConsensusParams { NetworkUpgrade::Blossom => self.blossom_activation_height.map(BlockHeight::from), NetworkUpgrade::Heartwood => self.heartwood_activation_height.map(BlockHeight::from), NetworkUpgrade::Canopy => self.canopy_activation_height.map(BlockHeight::from), + #[cfg(feature = "zfuture")] + NetworkUpgrade::ZFuture => unimplemented!(), } } diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index b1fc509067..c5b7007cc9 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -65,19 +65,22 @@ pub(crate) async fn fetch_tx_history_from_db( let tx_table = db_transaction.table::().await?; let total_tx_count = tx_table.count_all().await? as u32; let offset = match paging_options { - PagingOptionsEnum::FromId(from_address_id) => from_address_id + 1, PagingOptionsEnum::PageNumber(page_number) => ((page_number.get() - 1) * limit) as i64, + PagingOptionsEnum::FromId(tx_id) => tx_id, }; + // received notes let txs = tx_table .cursor_builder() .only("ticker", z.ticker())? .bound("height", 0u32, u32::MAX) + .offset(offset as u32) .open_cursor(WalletDbAccountsTable::TICKER_ACCOUNT_INDEX) .await? .collect() .await?; + // received notes let rn_table = db_transaction.table::().await?; let received_notes = rn_table .cursor_builder() diff --git a/mm2src/mm2_main/src/wasm_tests.rs b/mm2src/mm2_main/src/wasm_tests.rs index 5899f98b42..2a9a4d7723 100644 --- a/mm2src/mm2_main/src/wasm_tests.rs +++ b/mm2src/mm2_main/src/wasm_tests.rs @@ -1,5 +1,7 @@ use crate::mm2::lp_init; +use common::block_on; use common::executor::{spawn, Timer}; +use common::log::info; use common::log::wasm_log::register_wasm_log; use crypto::StandardHDCoinAddress; use mm2_core::mm_ctx::MmArc; @@ -8,11 +10,11 @@ use mm2_rpc::data::legacy::OrderbookResponse; use mm2_test_helpers::electrums::{doc_electrums, marty_electrums}; use mm2_test_helpers::for_tests::{check_recent_swaps, enable_electrum_json, enable_z_coin_light, morty_conf, pirate_conf, rick_conf, start_swaps, test_qrc20_history_impl, - wait_for_swaps_finish_and_check_status, MarketMakerIt, Mm2InitPrivKeyPolicy, - Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, PIRATE_ELECTRUMS, - PIRATE_LIGHTWALLETD_URLS, RICK}; + wait_for_swaps_finish_and_check_status, z_coin_tx_history, MarketMakerIt, + Mm2InitPrivKeyPolicy, Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, + PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, RICK, ZOMBIE_TICKER}; use mm2_test_helpers::get_passphrase; -use mm2_test_helpers::structs::EnableCoinBalance; +use mm2_test_helpers::structs::{EnableCoinBalance, RpcV2Response, ZcoinHistoryRes}; use serde_json::json; use wasm_bindgen_test::wasm_bindgen_test; @@ -249,7 +251,6 @@ async fn trade_v2_test_rick_and_morty() { #[wasm_bindgen_test] async fn activate_z_coin_light() { - register_wasm_log(); let coins = json!([pirate_conf()]); let conf = Mm2TestConf::seednode(PIRATE_TEST_BALANCE_SEED, &coins); @@ -266,3 +267,23 @@ async fn activate_z_coin_light() { }; assert_eq!(balance.balance.spendable, BigDecimal::default()); } + +#[wasm_bindgen_test] +async fn test_z_coin_tx_history() { + register_wasm_log(); + let coins = json!([pirate_conf()]); + + let conf = Mm2TestConf::seednode(PIRATE_TEST_BALANCE_SEED, &coins); + let mm = MarketMakerIt::start_async(conf.conf, conf.rpc_password, Some(wasm_start)) + .await + .unwrap(); + + let activation_result = + enable_z_coin_light(&mm, ARRR, PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, None, None).await; + + let tx_history = z_coin_tx_history(&mm, ARRR, 5, None).await; + println!("History {}", serde_json::to_string(&tx_history).unwrap()); + + let response: RpcV2Response = serde_json::from_value(tx_history).unwrap(); + info!("RESPONSE: {response:?}") +} From 778c92b632445d8aa6d6f2fd4c148ef06981276f Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 01:19:59 +0100 Subject: [PATCH 07/15] try commit From 478ea629a0dd9be6a5767d825aa207ebec2875a4 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 09:30:42 +0100 Subject: [PATCH 08/15] enable zcoin tx history rpc method in WASM --- mm2src/coins/my_tx_history_v2.rs | 1 - mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs | 2 +- mm2src/mm2_main/src/wasm_tests.rs | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/my_tx_history_v2.rs b/mm2src/coins/my_tx_history_v2.rs index 97c5a5ca8f..6158829c66 100644 --- a/mm2src/coins/my_tx_history_v2.rs +++ b/mm2src/coins/my_tx_history_v2.rs @@ -514,7 +514,6 @@ where }) } -#[cfg(not(target_arch = "wasm32"))] pub async fn z_coin_tx_history_rpc( ctx: MmArc, request: MyTxHistoryRequestV2, diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 1307807c13..9af6dc7b4b 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -206,6 +206,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, ibc_chains).await, "ibc_transfer_channels" => handle_mmrpc(ctx, request, ibc_transfer_channels).await, "withdraw_nft" => handle_mmrpc(ctx, request, withdraw_nft).await, + "z_coin_tx_history" => handle_mmrpc(ctx, request, coins::my_tx_history_v2::z_coin_tx_history_rpc).await, #[cfg(not(target_arch = "wasm32"))] native_only_methods => match native_only_methods { #[cfg(all(feature = "enable-solana", not(target_os = "ios"), not(target_os = "android")))] @@ -214,7 +215,6 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, enable_token::).await, - "z_coin_tx_history" => handle_mmrpc(ctx, request, coins::my_tx_history_v2::z_coin_tx_history_rpc).await, _ => MmError::err(DispatcherError::NoSuchMethod), }, #[cfg(target_arch = "wasm32")] diff --git a/mm2src/mm2_main/src/wasm_tests.rs b/mm2src/mm2_main/src/wasm_tests.rs index 2a9a4d7723..73aaa2200e 100644 --- a/mm2src/mm2_main/src/wasm_tests.rs +++ b/mm2src/mm2_main/src/wasm_tests.rs @@ -1,5 +1,4 @@ use crate::mm2::lp_init; -use common::block_on; use common::executor::{spawn, Timer}; use common::log::info; use common::log::wasm_log::register_wasm_log; @@ -12,7 +11,7 @@ use mm2_test_helpers::for_tests::{check_recent_swaps, enable_electrum_json, enab pirate_conf, rick_conf, start_swaps, test_qrc20_history_impl, wait_for_swaps_finish_and_check_status, z_coin_tx_history, MarketMakerIt, Mm2InitPrivKeyPolicy, Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, - PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, RICK, ZOMBIE_TICKER}; + PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, RICK}; use mm2_test_helpers::get_passphrase; use mm2_test_helpers::structs::{EnableCoinBalance, RpcV2Response, ZcoinHistoryRes}; use serde_json::json; @@ -278,7 +277,7 @@ async fn test_z_coin_tx_history() { .await .unwrap(); - let activation_result = + let _activation_result = enable_z_coin_light(&mm, ARRR, PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, None, None).await; let tx_history = z_coin_tx_history(&mm, ARRR, 5, None).await; From 7bc308c04854bd8b7fa48c25f9734b590b255552 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 14:54:44 +0100 Subject: [PATCH 09/15] use correct tx table and indexes --- mm2src/coins/z_coin/z_tx_history.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index c5b7007cc9..4419b078e0 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -69,13 +69,12 @@ pub(crate) async fn fetch_tx_history_from_db( PagingOptionsEnum::FromId(tx_id) => tx_id, }; - // received notes + // transactions notes let txs = tx_table .cursor_builder() .only("ticker", z.ticker())? - .bound("height", 0u32, u32::MAX) .offset(offset as u32) - .open_cursor(WalletDbAccountsTable::TICKER_ACCOUNT_INDEX) + .open_cursor(WalletDbTransactionsTable::TICKER_BLOCK_INDEX) .await? .collect() .await?; @@ -85,7 +84,6 @@ pub(crate) async fn fetch_tx_history_from_db( let received_notes = rn_table .cursor_builder() .only("ticker", z.ticker())? - .bound("height", 0u32, u32::MAX) .open_cursor(WalletDbReceivedNotesTable::TICKER_ACCOUNT_INDEX) .await? .collect() From 53a80affb51ea716512f5d35d0fac4711b6cb6e9 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 15:01:53 +0100 Subject: [PATCH 10/15] fix wasm lint --- mm2src/coins/z_coin/z_tx_history.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index 4419b078e0..b147b84024 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -3,8 +3,7 @@ use common::PagingOptionsEnum; use mm2_err_handle::prelude::MmError; cfg_wasm32!( - use crate::z_coin::storage::wasm::tables::{WalletDbAccountsTable, WalletDbBlocksTable, WalletDbReceivedNotesTable, - WalletDbTransactionsTable}; + use crate::z_coin::storage::wasm::tables::{WalletDbBlocksTable, WalletDbReceivedNotesTable, WalletDbTransactionsTable}; use crate::MarketCoinOps; use mm2_number::BigInt; use num_traits::ToPrimitive; From ab00f22788d3afcd78687409adfc09a35816972b Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 13 Mar 2024 20:42:56 +0100 Subject: [PATCH 11/15] finish impl and cleanups --- mm2src/coins/z_coin/z_tx_history.rs | 31 +++++++++++-------- .../mm2_db/src/indexed_db/indexed_cursor.rs | 8 +++++ mm2src/mm2_main/src/wasm_tests.rs | 20 ------------ 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index b147b84024..2cff3ce3ea 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -52,6 +52,7 @@ pub(crate) struct ZTxHistoryRes { pub(crate) skipped: usize, } +/// Fetch transaction history from the database. #[cfg(target_arch = "wasm32")] pub(crate) async fn fetch_tx_history_from_db( z: &ZCoin, @@ -68,27 +69,29 @@ pub(crate) async fn fetch_tx_history_from_db( PagingOptionsEnum::FromId(tx_id) => tx_id, }; - // transactions notes + // Fetch transactions let txs = tx_table .cursor_builder() .only("ticker", z.ticker())? .offset(offset as u32) - .open_cursor(WalletDbTransactionsTable::TICKER_BLOCK_INDEX) + .limit(limit) + .reverse() + .open_cursor("ticker") .await? .collect() .await?; - // received notes + // Fetch received notes let rn_table = db_transaction.table::().await?; let received_notes = rn_table .cursor_builder() .only("ticker", z.ticker())? - .open_cursor(WalletDbReceivedNotesTable::TICKER_ACCOUNT_INDEX) + .open_cursor("ticker") .await? .collect() .await?; - // detect blocks + // Fetch blocks let blocks_table = db_transaction.table::().await?; let blocks = blocks_table .cursor_builder() @@ -98,35 +101,37 @@ pub(crate) async fn fetch_tx_history_from_db( .collect() .await?; + // Process transactions and construct tx_details let mut tx_details = vec![]; for (tx_id, tx) in txs { - let height = blocks + if let Some((_, WalletDbBlocksTable { height, time, .. })) = blocks .iter() - .find(|(_, block)| tx.block.map(|b| b == block.height).unwrap_or_default()); - if let Some((_, WalletDbBlocksTable { height, time, .. })) = height { + .find(|(_, block)| tx.block.map(|b| b == block.height).unwrap_or_default()) + { let internal_id = tx_id; - let mut tx_hash = tx.txid; let mut received_amount = 0; let mut spent_amount = 0; for (_, note) in &received_notes { if internal_id == note.tx { - received_amount += (note.value.to_u64().ok_or_else(|| { + received_amount += note.value.to_u64().ok_or_else(|| { ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) - })?) as i64; + })? as i64; } // detecting spent amount by "spent" field in received_notes table if let Some(spent) = ¬e.spent { if &BigInt::from(internal_id) == spent { - spent_amount += (note.value.to_u64().ok_or_else(|| { + spent_amount += note.value.to_u64().ok_or_else(|| { ZTxHistoryError::IndexedDbError("Number is too large to fit in a u64".to_string()) - })?) as i64; + })? as i64; } } } + let mut tx_hash = tx.txid; tx_hash.reverse(); + tx_details.push(ZCoinTxHistoryItem { tx_hash, internal_id: internal_id as i64, diff --git a/mm2src/mm2_db/src/indexed_db/indexed_cursor.rs b/mm2src/mm2_db/src/indexed_db/indexed_cursor.rs index 0f1ad8f50e..74b7c3e89b 100644 --- a/mm2src/mm2_db/src/indexed_db/indexed_cursor.rs +++ b/mm2src/mm2_db/src/indexed_db/indexed_cursor.rs @@ -145,11 +145,19 @@ impl<'transaction, 'reference, Table: TableSignature> CursorBuilder<'transaction pub fn where_first(self) -> CursorBuilder<'transaction, 'reference, Table> { self.where_(|_| Ok(true)) } pub fn limit(mut self, limit: usize) -> CursorBuilder<'transaction, 'reference, Table> { + if limit < 1 { + return self; + }; + self.filters_ext.limit = Some(limit); self } pub fn offset(mut self, offset: u32) -> CursorBuilder<'transaction, 'reference, Table> { + if offset < 1 { + return self; + }; + self.filters_ext.offset = Some(offset); self } diff --git a/mm2src/mm2_main/src/wasm_tests.rs b/mm2src/mm2_main/src/wasm_tests.rs index 73aaa2200e..0033653e71 100644 --- a/mm2src/mm2_main/src/wasm_tests.rs +++ b/mm2src/mm2_main/src/wasm_tests.rs @@ -266,23 +266,3 @@ async fn activate_z_coin_light() { }; assert_eq!(balance.balance.spendable, BigDecimal::default()); } - -#[wasm_bindgen_test] -async fn test_z_coin_tx_history() { - register_wasm_log(); - let coins = json!([pirate_conf()]); - - let conf = Mm2TestConf::seednode(PIRATE_TEST_BALANCE_SEED, &coins); - let mm = MarketMakerIt::start_async(conf.conf, conf.rpc_password, Some(wasm_start)) - .await - .unwrap(); - - let _activation_result = - enable_z_coin_light(&mm, ARRR, PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, None, None).await; - - let tx_history = z_coin_tx_history(&mm, ARRR, 5, None).await; - println!("History {}", serde_json::to_string(&tx_history).unwrap()); - - let response: RpcV2Response = serde_json::from_value(tx_history).unwrap(); - info!("RESPONSE: {response:?}") -} From 601324a0bc9c25ba0b73f136b368ba0d70071c1c Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Sat, 16 Mar 2024 00:45:28 +0100 Subject: [PATCH 12/15] code organization --- mm2src/coins/z_coin/z_tx_history.rs | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index 2cff3ce3ea..080eb6569f 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -10,12 +10,12 @@ cfg_wasm32!( ); cfg_native!( + use crate::z_coin::BLOCKS_TABLE; use db_common::sqlite::sql_builder::{name, SqlBuilder, SqlName}; use db_common::sqlite::rusqlite::Error as SqliteError; use db_common::sqlite::rusqlite::Row; use db_common::sqlite::offset_by_id; use common::async_blocking; - use crate::z_coin::{BLOCKS_TABLE}; ); #[cfg(not(target_arch = "wasm32"))] @@ -30,25 +30,9 @@ pub(crate) struct ZCoinTxHistoryItem { pub(crate) spent_amount: i64, } -#[cfg(not(target_arch = "wasm32"))] -impl ZCoinTxHistoryItem { - fn try_from_sql_row(row: &Row<'_>) -> Result { - let mut tx_hash: Vec = row.get(0)?; - tx_hash.reverse(); - Ok(ZCoinTxHistoryItem { - tx_hash, - internal_id: row.get(1)?, - height: row.get(2)?, - timestamp: row.get(3)?, - received_amount: row.get(4)?, - spent_amount: row.get(5)?, - }) - } -} - pub(crate) struct ZTxHistoryRes { - pub(crate) transactions: Vec, pub(crate) total_tx_count: u32, + pub(crate) transactions: Vec, pub(crate) skipped: usize, } @@ -150,6 +134,22 @@ pub(crate) async fn fetch_tx_history_from_db( }) } +#[cfg(not(target_arch = "wasm32"))] +impl ZCoinTxHistoryItem { + fn try_from_sql_row(row: &Row<'_>) -> Result { + let mut tx_hash: Vec = row.get(0)?; + tx_hash.reverse(); + Ok(ZCoinTxHistoryItem { + tx_hash, + internal_id: row.get(1)?, + height: row.get(2)?, + timestamp: row.get(3)?, + received_amount: row.get(4)?, + spent_amount: row.get(5)?, + }) + } +} + #[cfg(not(target_arch = "wasm32"))] pub(crate) async fn fetch_tx_history_from_db( z: &ZCoin, From 8ccd4f9fc17ee0f4b9e546788f15f2e7701c086a Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 26 Mar 2024 12:41:32 +0100 Subject: [PATCH 13/15] simplify impl From for MyTxHistoryErrorV2 --- mm2src/coins/z_coin/z_coin_errors.rs | 31 +++++++++++----------------- mm2src/mm2_main/src/wasm_tests.rs | 11 +++++----- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/mm2src/coins/z_coin/z_coin_errors.rs b/mm2src/coins/z_coin/z_coin_errors.rs index 3ac5d3ce36..2d9116c276 100644 --- a/mm2src/coins/z_coin/z_coin_errors.rs +++ b/mm2src/coins/z_coin/z_coin_errors.rs @@ -20,7 +20,8 @@ use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use zcash_client_backend::data_api::error::ChainInvalid; #[cfg(not(target_arch = "wasm32"))] use zcash_client_sqlite::error::SqliteClientError; -#[cfg(target_arch = "wasm32")] use zcash_extras::NoteId; +#[cfg(target_arch = "wasm32")] +use zcash_extras::NoteId; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::transaction::builder::Error as ZTxBuilderError; @@ -106,10 +107,10 @@ pub enum GenTxError { GetWitnessErr(GetUnspentWitnessErr), FailedToGetMerklePath, #[display( - fmt = "Not enough {} to generate a tx: available {}, required at least {}", - coin, - available, - required + fmt = "Not enough {} to generate a tx: available {}, required at least {}", + coin, + available, + required )] InsufficientBalance { coin: String, @@ -272,6 +273,7 @@ impl From for ZCoinBuildError { fn from(err: ZcoinClientInitError) -> Self { ZCoinBuildError::RpcClientInitErr(err) } } +#[derive(Debug, Display)] pub(crate) enum ZTxHistoryError { #[cfg(not(target_arch = "wasm32"))] Sql(SqliteError), @@ -282,18 +284,7 @@ pub(crate) enum ZTxHistoryError { } impl From for MyTxHistoryErrorV2 { - fn from(err: ZTxHistoryError) -> Self { - match err { - #[cfg(not(target_arch = "wasm32"))] - ZTxHistoryError::Sql(sql) => MyTxHistoryErrorV2::StorageError(sql.to_string()), - #[cfg(not(target_arch = "wasm32"))] - ZTxHistoryError::FromIdDoesNotExist(id) => { - MyTxHistoryErrorV2::StorageError(format!("from_id {} does not exist", id)) - }, - #[cfg(target_arch = "wasm32")] - ZTxHistoryError::IndexedDbError(err) => MyTxHistoryErrorV2::StorageError(err), - } - } + fn from(err: ZTxHistoryError) -> Self { MyTxHistoryErrorV2::StorageError(err.to_string()) } } #[cfg(not(target_arch = "wasm32"))] @@ -332,6 +323,7 @@ pub enum ZCoinBalanceError { impl From for ZCoinBalanceError { fn from(value: ZcoinStorageError) -> Self { ZCoinBalanceError::BalanceError(value.to_string()) } } + /// The `ValidateBlocksError` enum encapsulates different types of errors that may occur /// during the validation and scanning process of zcoin blocks. #[derive(Debug, Display)] @@ -358,6 +350,7 @@ pub enum ValidateBlocksError { impl From for ZcoinStorageError { fn from(value: ValidateBlocksError) -> Self { Self::ValidateBlocksError(value) } } + impl From> for ValidateBlocksError { fn from(value: MmError) -> Self { Self::ZcoinStorageError(value.to_string()) } } @@ -478,11 +471,11 @@ impl From for ZcoinStorageError { match e { DbTransactionError::ErrorSerializingItem(_) | DbTransactionError::ErrorDeserializingItem(_) => { ZcoinStorageError::DecodingError(e.to_string()) - }, + } DbTransactionError::ErrorUploadingItem(_) => ZcoinStorageError::AddToStorageErr(e.to_string()), DbTransactionError::ErrorGettingItems(_) | DbTransactionError::ErrorCountingItems(_) => { ZcoinStorageError::GetFromStorageError(e.to_string()) - }, + } DbTransactionError::ErrorDeletingItems(_) => ZcoinStorageError::RemoveFromStorageErr(e.to_string()), DbTransactionError::NoSuchTable { .. } | DbTransactionError::ErrorCreatingTransaction(_) diff --git a/mm2src/mm2_main/src/wasm_tests.rs b/mm2src/mm2_main/src/wasm_tests.rs index 0033653e71..b9e5e1daf7 100644 --- a/mm2src/mm2_main/src/wasm_tests.rs +++ b/mm2src/mm2_main/src/wasm_tests.rs @@ -1,6 +1,5 @@ use crate::mm2::lp_init; use common::executor::{spawn, Timer}; -use common::log::info; use common::log::wasm_log::register_wasm_log; use crypto::StandardHDCoinAddress; use mm2_core::mm_ctx::MmArc; @@ -9,11 +8,11 @@ use mm2_rpc::data::legacy::OrderbookResponse; use mm2_test_helpers::electrums::{doc_electrums, marty_electrums}; use mm2_test_helpers::for_tests::{check_recent_swaps, enable_electrum_json, enable_z_coin_light, morty_conf, pirate_conf, rick_conf, start_swaps, test_qrc20_history_impl, - wait_for_swaps_finish_and_check_status, z_coin_tx_history, MarketMakerIt, + wait_for_swaps_finish_and_check_status, MarketMakerIt, Mm2InitPrivKeyPolicy, Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, RICK}; use mm2_test_helpers::get_passphrase; -use mm2_test_helpers::structs::{EnableCoinBalance, RpcV2Response, ZcoinHistoryRes}; +use mm2_test_helpers::structs::EnableCoinBalance; use serde_json::json; use wasm_bindgen_test::wasm_bindgen_test; @@ -126,7 +125,7 @@ async fn trade_base_rel_electrum( for (base, rel) in pairs.iter() { log!("Get {}/{} orderbook", base, rel); let rc = mm_bob - .rpc(&json! ({ + .rpc(&json!({ "userpass": mm_bob.userpass, "method": "orderbook", "base": base, @@ -192,7 +191,7 @@ async fn trade_test_rick_and_morty() { 1., 0.0001, ) - .await; + .await; } #[wasm_bindgen_test] @@ -245,7 +244,7 @@ async fn trade_v2_test_rick_and_morty() { 1., 0.0001, ) - .await; + .await; } #[wasm_bindgen_test] From 823b3762e94adf9d055996775703dfca471b3e2b Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 26 Mar 2024 12:54:28 +0100 Subject: [PATCH 14/15] cargo fmt --- mm2src/coins/z_coin/z_coin_errors.rs | 15 +++++++-------- mm2src/mm2_main/src/wasm_tests.rs | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/mm2src/coins/z_coin/z_coin_errors.rs b/mm2src/coins/z_coin/z_coin_errors.rs index 2d9116c276..b20f062616 100644 --- a/mm2src/coins/z_coin/z_coin_errors.rs +++ b/mm2src/coins/z_coin/z_coin_errors.rs @@ -20,8 +20,7 @@ use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use zcash_client_backend::data_api::error::ChainInvalid; #[cfg(not(target_arch = "wasm32"))] use zcash_client_sqlite::error::SqliteClientError; -#[cfg(target_arch = "wasm32")] -use zcash_extras::NoteId; +#[cfg(target_arch = "wasm32")] use zcash_extras::NoteId; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::transaction::builder::Error as ZTxBuilderError; @@ -107,10 +106,10 @@ pub enum GenTxError { GetWitnessErr(GetUnspentWitnessErr), FailedToGetMerklePath, #[display( - fmt = "Not enough {} to generate a tx: available {}, required at least {}", - coin, - available, - required + fmt = "Not enough {} to generate a tx: available {}, required at least {}", + coin, + available, + required )] InsufficientBalance { coin: String, @@ -471,11 +470,11 @@ impl From for ZcoinStorageError { match e { DbTransactionError::ErrorSerializingItem(_) | DbTransactionError::ErrorDeserializingItem(_) => { ZcoinStorageError::DecodingError(e.to_string()) - } + }, DbTransactionError::ErrorUploadingItem(_) => ZcoinStorageError::AddToStorageErr(e.to_string()), DbTransactionError::ErrorGettingItems(_) | DbTransactionError::ErrorCountingItems(_) => { ZcoinStorageError::GetFromStorageError(e.to_string()) - } + }, DbTransactionError::ErrorDeletingItems(_) => ZcoinStorageError::RemoveFromStorageErr(e.to_string()), DbTransactionError::NoSuchTable { .. } | DbTransactionError::ErrorCreatingTransaction(_) diff --git a/mm2src/mm2_main/src/wasm_tests.rs b/mm2src/mm2_main/src/wasm_tests.rs index b9e5e1daf7..f565757b0c 100644 --- a/mm2src/mm2_main/src/wasm_tests.rs +++ b/mm2src/mm2_main/src/wasm_tests.rs @@ -8,9 +8,9 @@ use mm2_rpc::data::legacy::OrderbookResponse; use mm2_test_helpers::electrums::{doc_electrums, marty_electrums}; use mm2_test_helpers::for_tests::{check_recent_swaps, enable_electrum_json, enable_z_coin_light, morty_conf, pirate_conf, rick_conf, start_swaps, test_qrc20_history_impl, - wait_for_swaps_finish_and_check_status, MarketMakerIt, - Mm2InitPrivKeyPolicy, Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, - PIRATE_ELECTRUMS, PIRATE_LIGHTWALLETD_URLS, RICK}; + wait_for_swaps_finish_and_check_status, MarketMakerIt, Mm2InitPrivKeyPolicy, + Mm2TestConf, Mm2TestConfForSwap, ARRR, MORTY, PIRATE_ELECTRUMS, + PIRATE_LIGHTWALLETD_URLS, RICK}; use mm2_test_helpers::get_passphrase; use mm2_test_helpers::structs::EnableCoinBalance; use serde_json::json; @@ -191,7 +191,7 @@ async fn trade_test_rick_and_morty() { 1., 0.0001, ) - .await; + .await; } #[wasm_bindgen_test] @@ -244,7 +244,7 @@ async fn trade_v2_test_rick_and_morty() { 1., 0.0001, ) - .await; + .await; } #[wasm_bindgen_test] From fb4f2e654ba7fb6ad48ed8431f95561b878323df Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 26 Mar 2024 16:12:45 +0100 Subject: [PATCH 15/15] fix PagingOptionsEnum::FromId for wasm --- mm2src/coins/z_coin/z_coin_errors.rs | 1 - mm2src/coins/z_coin/z_tx_history.rs | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/z_coin/z_coin_errors.rs b/mm2src/coins/z_coin/z_coin_errors.rs index b20f062616..5b5992baae 100644 --- a/mm2src/coins/z_coin/z_coin_errors.rs +++ b/mm2src/coins/z_coin/z_coin_errors.rs @@ -278,7 +278,6 @@ pub(crate) enum ZTxHistoryError { Sql(SqliteError), #[cfg(target_arch = "wasm32")] IndexedDbError(String), - #[cfg(not(target_arch = "wasm32"))] FromIdDoesNotExist(i64), } diff --git a/mm2src/coins/z_coin/z_tx_history.rs b/mm2src/coins/z_coin/z_tx_history.rs index 080eb6569f..26b7f9c8ce 100644 --- a/mm2src/coins/z_coin/z_tx_history.rs +++ b/mm2src/coins/z_coin/z_tx_history.rs @@ -50,7 +50,12 @@ pub(crate) async fn fetch_tx_history_from_db( let total_tx_count = tx_table.count_all().await? as u32; let offset = match paging_options { PagingOptionsEnum::PageNumber(page_number) => ((page_number.get() - 1) * limit) as i64, - PagingOptionsEnum::FromId(tx_id) => tx_id, + PagingOptionsEnum::FromId(tx_id) => { + if tx_id > total_tx_count as i64 { + return MmError::err(ZTxHistoryError::FromIdDoesNotExist(tx_id)); + } + (total_tx_count as i64 - tx_id) + 1 + }, }; // Fetch transactions