Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion mm2src/coins/my_tx_history_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ where
})
}

#[cfg(not(target_arch = "wasm32"))]
pub async fn z_coin_tx_history_rpc(
ctx: MmArc,
request: MyTxHistoryRequestV2<i64>,
Expand Down
178 changes: 36 additions & 142 deletions mm2src/coins/z_coin.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
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,
UtxoRpcResult};
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,
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;
use chain::constants::SEQUENCE_FINAL;
use chain::{Transaction as UtxoTx, TransactionOutput};
use common::calc_total_pages;
use common::executor::{AbortableSystem, AbortedError};
use common::{log, one_thousand_u32};
use crypto::privkey::{key_pair_from_secret, secp_privkey_from_hash};
Expand Down Expand Up @@ -85,15 +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, 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};
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!(
Expand All @@ -105,13 +102,13 @@ cfg_wasm32!(
);

#[allow(unused)] mod z_coin_errors;
use crate::z_coin::storage::{BlockDbImpl, WalletDbShared};
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 {
Expand All @@ -138,7 +135,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";
);
Expand Down Expand Up @@ -184,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!(),
}
}

Expand Down Expand Up @@ -240,39 +238,6 @@ pub struct ZOutput {
pub memo: Option<MemoBytes>,
}

#[cfg(not(target_arch = "wasm32"))]
struct ZCoinSqlTxHistoryItem {
tx_hash: Vec<u8>,
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<Self, SqlError> {
let mut tx_hash: Vec<u8> = 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<ZCoinSqlTxHistoryItem>,
total_tx_count: u32,
skipped: usize,
}

#[derive(Serialize)]
pub struct ZcoinTxDetails {
/// Transaction hash in hexadecimal format
Expand Down Expand Up @@ -531,73 +496,6 @@ impl ZCoin {
Ok(tx)
}

#[cfg(not(target_arch = "wasm32"))]
async fn tx_history_from_sql(
&self,
limit: usize,
paging_options: PagingOptionsEnum<i64>,
) -> Result<SqlTxHistoryRes, MmError<SqlTxHistoryError>> {
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::<Result<Vec<_>, _>>()?;

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,
hashes: HashSet<H256Json>,
Expand All @@ -613,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: ZCoinSqlTxHistoryItem,
tx_item: ZCoinTxHistoryItem,
transactions: &mut HashMap<H256Json, ZTransaction>,
prev_transactions: &HashMap<H256Json, ZTransaction>,
current_block: u64,
) -> Result<ZcoinTxDetails, MmError<NoInfoAboutTx>> {
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());
Expand Down Expand Up @@ -657,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());
}

Expand Down Expand Up @@ -691,35 +588,32 @@ 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<i64>,
) -> Result<MyTxHistoryResponseV2<ZcoinTxDetails, i64>, MmError<MyTxHistoryErrorV2>> {
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()))
Expand All @@ -738,11 +632,11 @@ 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| {
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::<Result<_, _>>()?;

Expand All @@ -754,9 +648,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,
})
}
Expand Down
2 changes: 1 addition & 1 deletion mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ impl<'a> WalletIndexedDb {
Ok(db)
}

async fn lock_db(&self) -> ZcoinStorageRes<WalletDbInnerLocked<'_>> {
pub(crate) async fn lock_db(&self) -> ZcoinStorageRes<WalletDbInnerLocked<'_>> {
self.db
.get_or_initialize()
.await
Expand Down
Loading