diff --git a/src/backend_task/identity/register_identity.rs b/src/backend_task/identity/register_identity.rs index 55d529848..855f08387 100644 --- a/src/backend_task/identity/register_identity.rs +++ b/src/backend_task/identity/register_identity.rs @@ -1,6 +1,6 @@ use crate::backend_task::identity::{IdentityRegistrationInfo, RegisterIdentityFundingMethod}; use crate::backend_task::{BackendTaskSuccessResult, FeeResult}; -use crate::context::AppContext; +use crate::context::{AppContext, get_transaction_info_via_dapi}; use crate::model::fee_estimation::PlatformFeeEstimator; use crate::model::proof_log_item::{ProofLogItem, RequestType}; use crate::model::qualified_identity::{IdentityStatus, IdentityType, QualifiedIdentity}; @@ -53,30 +53,23 @@ impl AppContext { RegisterIdentityFundingMethod::UseAssetLock(address, asset_lock_proof, transaction) => { let tx_id = transaction.txid(); - // eprintln!("UseAssetLock: transaction id for {:#?} is {}", transaction, tx_id); - let wallet = wallet.read().unwrap(); - wallet_id = wallet.seed_hash(); - let private_key = wallet - .private_key_for_address(&address, self.network)? - .ok_or("Asset Lock not valid for wallet")?; + // Scope the read guard so it's dropped before the async DAPI call below + let private_key = { + let wallet = wallet.read().unwrap(); + wallet_id = wallet.seed_hash(); + wallet + .private_key_for_address(&address, self.network)? + .ok_or("Asset Lock not valid for wallet")? + }; let asset_lock_proof = if let AssetLockProof::Instant(instant_asset_lock_proof) = asset_lock_proof.as_ref() { // we need to make sure the instant send asset lock is recent - let raw_transaction_info = self - .core_client - .read() - .expect("Core client lock was poisoned") - .get_raw_transaction_info(&tx_id, None) - .map_err(|e| e.to_string())?; + let tx_info = get_transaction_info_via_dapi(&sdk, &tx_id).await?; - if raw_transaction_info.chainlock - && raw_transaction_info.height.is_some() - && raw_transaction_info.confirmations.is_some() - && raw_transaction_info.confirmations.unwrap() > 8 - { + if tx_info.is_chain_locked && tx_info.height > 0 && tx_info.confirmations > 8 { // Transaction is old enough that instant lock may have expired - let tx_block_height = raw_transaction_info.height.unwrap() as u32; + let tx_block_height = tx_info.height; if tx_block_height <= metadata.core_chain_locked_height { // Platform has verified this Core block, use chain lock proof @@ -488,15 +481,10 @@ impl AppContext { || e.contains("wasn't created recently") { // Try to use chain asset lock proof instead - let raw_transaction_info = self - .core_client - .read() - .expect("Core client lock was poisoned") - .get_raw_transaction_info(&tx_id, None) - .map_err(|e| e.to_string())?; + let tx_info = get_transaction_info_via_dapi(&sdk, &tx_id).await?; - if raw_transaction_info.chainlock && raw_transaction_info.height.is_some() { - let tx_block_height = raw_transaction_info.height.unwrap() as u32; + if tx_info.is_chain_locked && tx_info.height > 0 { + let tx_block_height = tx_info.height; if tx_block_height <= metadata.core_chain_locked_height { // Platform has verified this Core block, use chain lock proof diff --git a/src/backend_task/identity/top_up_identity.rs b/src/backend_task/identity/top_up_identity.rs index 6e068f43b..5a309e89f 100644 --- a/src/backend_task/identity/top_up_identity.rs +++ b/src/backend_task/identity/top_up_identity.rs @@ -1,6 +1,6 @@ use crate::backend_task::identity::{IdentityTopUpInfo, TopUpIdentityFundingMethod}; use crate::backend_task::{BackendTaskSuccessResult, FeeResult}; -use crate::context::AppContext; +use crate::context::{AppContext, get_transaction_info_via_dapi}; use crate::model::fee_estimation::PlatformFeeEstimator; use crate::model::proof_log_item::{ProofLogItem, RequestType}; use dash_sdk::Error; @@ -47,30 +47,26 @@ impl AppContext { ) => { let tx_id = transaction.txid(); - // eprintln!("UseAssetLock: transaction id for {:#?} is {}", transaction, tx_id); - let wallet = wallet.read().unwrap(); - let private_key = wallet - .private_key_for_address(&address, self.network)? - .ok_or("Asset Lock not valid for wallet")?; + // Scope the read guard so it's dropped before the async DAPI call below + let private_key = { + let wallet = wallet.read().unwrap(); + wallet + .private_key_for_address(&address, self.network)? + .ok_or("Asset Lock not valid for wallet")? + }; let asset_lock_proof = if let AssetLockProof::Instant( instant_asset_lock_proof, ) = asset_lock_proof.as_ref() { // we need to make sure the instant send asset lock is recent - let raw_transaction_info = self - .core_client - .read() - .expect("Core client lock was poisoned") - .get_raw_transaction_info(&tx_id, None) - .map_err(|e| e.to_string())?; + let tx_info = get_transaction_info_via_dapi(&sdk, &tx_id).await?; - if raw_transaction_info.chainlock - && raw_transaction_info.height.is_some() - && raw_transaction_info.confirmations.is_some() - && raw_transaction_info.confirmations.unwrap() > 8 + if tx_info.is_chain_locked + && tx_info.height > 0 + && tx_info.confirmations > 8 { // Transaction is old enough that instant lock may have expired - let tx_block_height = raw_transaction_info.height.unwrap() as u32; + let tx_block_height = tx_info.height; if tx_block_height <= metadata.core_chain_locked_height { // Platform has verified this Core block, use chain lock proof @@ -410,15 +406,10 @@ impl AppContext { || error_string.contains("wasn't created recently") { // Try to use chain asset lock proof instead - let raw_transaction_info = self - .core_client - .read() - .expect("Core client lock was poisoned") - .get_raw_transaction_info(&tx_id, None) - .map_err(|e| e.to_string())?; + let tx_info = get_transaction_info_via_dapi(&sdk, &tx_id).await?; - if raw_transaction_info.chainlock && raw_transaction_info.height.is_some() { - let tx_block_height = raw_transaction_info.height.unwrap() as u32; + if tx_info.is_chain_locked && tx_info.height > 0 { + let tx_block_height = tx_info.height; if tx_block_height <= metadata.core_chain_locked_height { // Platform has verified this Core block, use chain lock proof diff --git a/src/backend_task/wallet/fund_platform_address_from_asset_lock.rs b/src/backend_task/wallet/fund_platform_address_from_asset_lock.rs index ea593fa36..5da5ff228 100644 --- a/src/backend_task/wallet/fund_platform_address_from_asset_lock.rs +++ b/src/backend_task/wallet/fund_platform_address_from_asset_lock.rs @@ -46,7 +46,7 @@ impl AppContext { }; // Check if we need to convert an old instant lock proof to a chain lock proof - use dash_sdk::dashcore_rpc::RpcApi; + use crate::context::get_transaction_info_via_dapi; use dash_sdk::dpp::block::extended_epoch_info::ExtendedEpochInfo; use dash_sdk::platform::Fetch; @@ -56,21 +56,12 @@ impl AppContext { // Get the transaction ID from the instant lock proof let tx_id = instant_asset_lock_proof.transaction().txid(); - // Query the core client to check if the transaction has been chain-locked - let raw_transaction_info = self - .core_client - .read() - .expect("Core client lock was poisoned") - .get_raw_transaction_info(&tx_id, None) - .map_err(|e| format!("Failed to get transaction info: {}", e))?; - - if raw_transaction_info.chainlock - && raw_transaction_info.height.is_some() - && raw_transaction_info.confirmations.is_some() - && raw_transaction_info.confirmations.unwrap() > 8 - { + // Query DAPI to check if the transaction has been chain-locked + let tx_info = get_transaction_info_via_dapi(&sdk, &tx_id).await?; + + if tx_info.is_chain_locked && tx_info.height > 0 && tx_info.confirmations > 8 { // Transaction has been chain-locked with sufficient confirmations - let tx_block_height = raw_transaction_info.height.unwrap() as u32; + let tx_block_height = tx_info.height; // Check if the platform has caught up to this block height let (_, metadata) = ExtendedEpochInfo::fetch_with_metadata(&sdk, 0, None) diff --git a/src/context.rs b/src/context.rs index 200ef77fa..4d7be12ff 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1708,6 +1708,39 @@ impl AppContext { } } +pub(crate) struct DapiTransactionInfo { + pub is_chain_locked: bool, + pub height: u32, + pub confirmations: u32, +} + +/// Query transaction info from DAPI. Works in both SPV and RPC modes +/// since DAPI (platform gRPC) is always available via the SDK. +pub(crate) async fn get_transaction_info_via_dapi( + sdk: &Sdk, + tx_id: &Txid, +) -> Result { + use dash_sdk::dapi_client::{DapiRequestExecutor, IntoInner, RequestSettings}; + use dash_sdk::dapi_grpc::core::v0::GetTransactionRequest; + + let response = sdk + .execute( + GetTransactionRequest { + id: tx_id.to_string(), + }, + RequestSettings::default(), + ) + .await + .into_inner() + .map_err(|e| format!("DAPI GetTransaction failed: {}", e))?; + + Ok(DapiTransactionInfo { + is_chain_locked: response.is_chain_locked, + height: response.height, + confirmations: response.confirmations, + }) +} + /// Returns the default platform version for the given network. pub(crate) const fn default_platform_version(network: &Network) -> &'static PlatformVersion { // TODO: Use self.sdk.read().unwrap().version() instead of hardcoding