From 6adcabcb543b6b6ed10ed7f928c2e224e670ffb5 Mon Sep 17 00:00:00 2001 From: fbock Date: Tue, 6 Aug 2024 13:27:21 +0200 Subject: [PATCH] improve mempool lookup of escrow psbt --- taptrade-cli-demo/coordinator/.env | 4 +- .../coordinator/src/communication/mod.rs | 2 +- .../coordinator/src/coordinator/mod.rs | 8 +++- .../coordinator/tx_confirmation_monitoring.rs | 47 +++++++++++++++++-- .../coordinator/src/database/mod.rs | 21 +++++---- taptrade-cli-demo/coordinator/src/main.rs | 4 +- .../coordinator/src/wallet/escrow_psbt.rs | 28 +++++++---- .../coordinator/src/wallet/mod.rs | 7 +-- 8 files changed, 89 insertions(+), 32 deletions(-) diff --git a/taptrade-cli-demo/coordinator/.env b/taptrade-cli-demo/coordinator/.env index fcabaf9..d6a0320 100644 --- a/taptrade-cli-demo/coordinator/.env +++ b/taptrade-cli-demo/coordinator/.env @@ -1,9 +1,9 @@ BITCOIN_RPC_ADDRESS_PORT="127.0.0.1:8332" BITCOIN_RPC_USER="coordinator" BITCOIN_RPC_PASSWORD="test1234" -DATABASE_PATH="./dbs/trades.db" # path to the coordinator sqlite database storing the trades +DATABASE_PATH=":memory:" #"./dbs/trades.db" # path to the coordinator sqlite database storing the trades BDK_DB_PATH="./dbs/bdk-wallet" # Path to the BDK Sled database (no .db postfix) WALLET_XPRV="tprv8ZgxMBicQKsPdHuCSjhQuSZP1h6ZTeiRqREYS5guGPdtL7D1uNLpnJmb2oJep99Esq1NbNZKVJBNnD2ZhuXSK7G5eFmmcx73gsoa65e2U32" PUNISHMENT_ENABLED=1 # enable punishment for misbehaving traders PORT=9999 # port for the coordinator to listen on -COORDINATOR_FEERATE=1 # coordinator fee in percent of the trade amount +COORDINATOR_FEERATE=1 # coordinator fee in percent of the trade amount diff --git a/taptrade-cli-demo/coordinator/src/communication/mod.rs b/taptrade-cli-demo/coordinator/src/communication/mod.rs index 0dfab83..ee0f65f 100755 --- a/taptrade-cli-demo/coordinator/src/communication/mod.rs +++ b/taptrade-cli-demo/coordinator/src/communication/mod.rs @@ -107,7 +107,7 @@ async fn request_offer_status_maker( Ok(offer_taken_response) => Ok(Json(offer_taken_response).into_response()), Err(FetchOffersError::NoOffersAvailable) => Ok(StatusCode::NO_CONTENT.into_response()), Err(FetchOffersError::Database(e)) => { - error!("Database error fetching offers: {e}"); + error!("Database error fetching offer status maker: {e}"); Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response()) } } diff --git a/taptrade-cli-demo/coordinator/src/coordinator/mod.rs b/taptrade-cli-demo/coordinator/src/coordinator/mod.rs index 012ebfb..f34e936 100755 --- a/taptrade-cli-demo/coordinator/src/coordinator/mod.rs +++ b/taptrade-cli-demo/coordinator/src/coordinator/mod.rs @@ -4,6 +4,8 @@ pub mod create_taproot; pub mod mempool_monitoring; pub mod tx_confirmation_monitoring; +use axum::routing::trace; + use self::coordinator_utils::*; use super::*; @@ -139,6 +141,10 @@ pub async fn handle_taker_bond( return Err(BondError::CoordinatorError(e.to_string())); } }; + debug!( + "\nEscrow PSBT creation successful: {:?}", + escrow_output_data + ); if let Err(e) = database .add_taker_info_and_move_table(payload, &escrow_output_data) @@ -146,7 +152,7 @@ pub async fn handle_taker_bond( { return Err(BondError::CoordinatorError(e.to_string())); } - + trace!("Taker information added to database and moved table successfully"); Ok(OfferTakenResponse { escrow_psbt_hex: escrow_output_data.escrow_psbt_hex, escrow_output_descriptor: escrow_output_data.escrow_output_descriptor, diff --git a/taptrade-cli-demo/coordinator/src/coordinator/tx_confirmation_monitoring.rs b/taptrade-cli-demo/coordinator/src/coordinator/tx_confirmation_monitoring.rs index 6d5b34a..53e0bfb 100644 --- a/taptrade-cli-demo/coordinator/src/coordinator/tx_confirmation_monitoring.rs +++ b/taptrade-cli-demo/coordinator/src/coordinator/tx_confirmation_monitoring.rs @@ -1,6 +1,12 @@ use std::str::FromStr; -use bdk::{bitcoin::Txid, bitcoincore_rpc::RpcApi}; +use axum::Json; +use bdk::{ + bitcoin::Txid, + bitcoincore_rpc::{ + jsonrpc::error::RpcError, jsonrpc::Error as JsonRpcError, Error as CoreRpcError, RpcApi, + }, +}; use super::*; @@ -11,11 +17,44 @@ fn get_confirmations( let mut now_confirmed_txs = Vec::new(); for txid in unconfirmed_txids { let txid_struct = Txid::from_str(&txid)?; - let tx_info = coordinator + let tx_info = match coordinator .coordinator_wallet .json_rpc_client .as_ref() - .get_raw_transaction_info(&txid_struct, None)?; + .get_raw_transaction_info(&txid_struct, None) + { + Ok(tx_info) => tx_info, + Err(e) => match e { + CoreRpcError::JsonRpc(e) => { + if let JsonRpcError::Rpc(rpc_error) = e { + if rpc_error.code == -5 { + trace!("Escrow transaction {} not yet found in mempool", &txid); + continue; + } else { + return Err(anyhow!( + "Error fetching transaction info for {}: {:?}", + &txid, + rpc_error + )); + } + } else { + return Err(anyhow!( + "Error fetching transaction info for {}: {:?}", + &txid, + e + )); + } + } + _ => { + error!("Error fetching transaction info for {}: {:?}", &txid, e); + return Err(anyhow!( + "Error fetching transaction info for {}: {:?}", + &txid, + e + )); + } + }, + }; if let Some(confirmations) = tx_info.confirmations { debug!( "Transaction {} in now confirmed with {} confirmations", @@ -35,7 +74,7 @@ pub async fn update_transaction_confirmations(coordinator: Arc) { trace!("Checking for transaction confirmations"); let unconfirmed_transactions = match coordinator .coordinator_db - .fetch_unconfirmed_bond_txids() + .fetch_unconfirmed_escrow_txids() .await { Ok(txids) => txids, diff --git a/taptrade-cli-demo/coordinator/src/database/mod.rs b/taptrade-cli-demo/coordinator/src/database/mod.rs index aa42f5b..d02dc53 100644 --- a/taptrade-cli-demo/coordinator/src/database/mod.rs +++ b/taptrade-cli-demo/coordinator/src/database/mod.rs @@ -135,8 +135,8 @@ impl CoordinatorDB { musig_pubkey_compressed_hex_maker TEXT NOT NULL, musig_pub_nonce_hex_taker TEXT NOT NULL, musig_pubkey_compressed_hex_taker TEXT NOT NULL, - escrow_psbt_hex TEXT, - escrow_psbt_txid TEXT, + escrow_psbt_hex TEXT NOT NULL, + escrow_psbt_txid TEXT NOT NULL, escrow_psbt_is_confirmed INTEGER, maker_happy INTEGER, taker_happy INTEGER, @@ -374,10 +374,10 @@ impl CoordinatorDB { sqlx::query( "INSERT OR REPLACE INTO taken_offers (offer_id, robohash_maker, robohash_taker, is_buy_order, amount_sat, bond_ratio, offer_duration_ts, bond_address_maker, bond_address_taker, bond_amount_sat, bond_tx_hex_maker, - bond_tx_hex_taker, payout_address_maker, payout_address_taker, taproot_pubkey_hex_maker, taproot_pubkey_hex_taker, musig_pub_nonce_hex_maker, musig_pubkey_hex_maker, - musig_pub_nonce_hex_taker, musig_pubkey_hex_taker, escrow_psbt_hex, escrow_output_descriptor, escrow_psbt_is_confirmed, escrow_ongoing, + bond_tx_hex_taker, payout_address_maker, payout_address_taker, taproot_xonly_pubkey_hex_maker, taproot_xonly_pubkey_hex_taker, musig_pub_nonce_hex_maker, musig_pubkey_compressed_hex_maker, + musig_pub_nonce_hex_taker, musig_pubkey_compressed_hex_taker, escrow_psbt_hex, escrow_psbt_txid, escrow_output_descriptor, escrow_psbt_is_confirmed, escrow_ongoing, escrow_taproot_pk_coordinator, escrow_amount_maker_sat, escrow_amount_taker_sat, escrow_fee_per_participant) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ) .bind(public_offer.offer_id) .bind(public_offer.robohash_maker) @@ -399,8 +399,9 @@ impl CoordinatorDB { .bind(public_offer.musig_pubkey_hex_maker) .bind(trade_and_taker_info.trade_data.musig_pub_nonce_hex.clone()) .bind(trade_and_taker_info.trade_data.musig_pubkey_hex.clone()) - .bind(&escrow_tx_data.escrow_output_descriptor) .bind(&escrow_tx_data.escrow_psbt_hex) + .bind(&escrow_tx_data.escrow_tx_txid) + .bind(&escrow_tx_data.escrow_output_descriptor) .bind(0) .bind(0) .bind(&escrow_tx_data.coordinator_xonly_escrow_pk) @@ -418,8 +419,8 @@ impl CoordinatorDB { offer_id_hex: &str, ) -> Result> { let offer = sqlx::query( - "SELECT escrow_output_descriptor, escrow_amount_maker_sat, - escrow_amount_taker_sat, escrow_fee_per_participant, escrow_taproot_pk_coordinator + "SELECT escrow_output_descriptor, escrow_amount_maker_sat, + escrow_amount_taker_sat, escrow_fee_per_participant, escrow_taproot_pk_coordinator, escrow_psbt_hex, escrow_psbt_txid FROM taken_offers WHERE offer_id = ?", ) .bind(offer_id_hex) @@ -437,8 +438,10 @@ impl CoordinatorDB { let coordinator_xonly_escrow_pk = offer.try_get::("escrow_taproot_pk_coordinator")?; let escrow_psbt_hex = offer.try_get::("escrow_psbt_hex")?; + let escrow_tx_txid = offer.try_get::("escrow_psbt_txid")?; Ok(Some(EscrowPsbt { + escrow_tx_txid, escrow_psbt_hex, escrow_output_descriptor, coordinator_xonly_escrow_pk, @@ -555,7 +558,7 @@ impl CoordinatorDB { Ok(()) } - pub async fn fetch_unconfirmed_bond_txids(&self) -> Result> { + pub async fn fetch_unconfirmed_escrow_txids(&self) -> Result> { let mut txids = Vec::new(); let mut rows = sqlx::query( "SELECT escrow_psbt_txid FROM taken_offers WHERE escrow_psbt_is_confirmed = 0", diff --git a/taptrade-cli-demo/coordinator/src/main.rs b/taptrade-cli-demo/coordinator/src/main.rs index d24a0ac..90176cd 100755 --- a/taptrade-cli-demo/coordinator/src/main.rs +++ b/taptrade-cli-demo/coordinator/src/main.rs @@ -4,7 +4,7 @@ mod database; mod wallet; use anyhow::{anyhow, Result}; -use bdk::sled; +use bdk::{database::MemoryDatabase, sled}; use communication::{api::*, api_server, communication_utils::*, handler_errors::*}; use coordinator::{ bond_monitoring::*, coordinator_utils::*, @@ -25,7 +25,7 @@ use wallet::{escrow_psbt::*, wallet_utils::*, *}; pub struct Coordinator { pub coordinator_db: Arc, - pub coordinator_wallet: Arc>, + pub coordinator_wallet: Arc>, } // populate .env with values before starting diff --git a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs index dbdcd34..9193d45 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/escrow_psbt.rs @@ -157,15 +157,17 @@ impl CoordinatorWallet { let (escrow_psbt, details) = { // maybe we can generate a address/taproot pk directly from the descriptor without a new wallet? - let temp_wallet = Wallet::new( - &escrow_output_descriptor, - None, - bitcoin::Network::Regtest, - MemoryDatabase::new(), - )?; - let escrow_address = temp_wallet - .get_address(bdk::wallet::AddressIndex::New)? - .address; + // let temp_wallet = Wallet::new( + // &escrow_output_descriptor, + // None, + // bitcoin::Network::Regtest, + // MemoryDatabase::new(), + // )?; + // let escrow_address = temp_wallet + // .get_address(bdk::wallet::AddressIndex::New)? + // .address; + let escrow_address = + Address::from_str(self.get_new_address().await?.as_str())?.assume_checked(); // using absolute fee for now, in production we should come up with a way to determine the tx weight // upfront and substract the fee from the change outputs @@ -177,7 +179,10 @@ impl CoordinatorWallet { - (escrow_amount_taker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); let amount_escrow = escrow_amount_maker_sat + escrow_amount_taker_sat; - let mut builder = temp_wallet.build_tx(); + + let wallet = self.wallet.lock().await; + // let mut builder = temp_wallet.build_tx(); + let mut builder = wallet.build_tx(); builder .manually_selected_only() .add_recipient(escrow_address.script_pubkey(), amount_escrow) @@ -204,7 +209,10 @@ impl CoordinatorWallet { builder.finish()? }; + let escrow_tx_txid: String = details.txid.to_string(); + Ok(EscrowPsbt { + escrow_tx_txid, escrow_psbt_hex: escrow_psbt.to_string(), escrow_output_descriptor, coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(), diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index 5f4b349..924a67f 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -44,6 +44,7 @@ pub struct CoordinatorWallet { #[derive(Debug)] pub struct EscrowPsbt { pub escrow_psbt_hex: String, + pub escrow_tx_txid: String, pub escrow_output_descriptor: String, pub coordinator_xonly_escrow_pk: String, pub escrow_amount_maker_sat: u64, @@ -58,7 +59,7 @@ pub struct BondRequirements { pub min_input_sum_sat: u64, } -pub async fn init_coordinator_wallet() -> Result> { +pub async fn init_coordinator_wallet() -> Result> { let wallet_xprv = ExtendedPrivKey::from_str( &env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?, )?; @@ -87,12 +88,12 @@ pub async fn init_coordinator_wallet() -> Result> let mempool = MempoolHandler::new(json_rpc_client_clone).await; let backend = RpcBlockchain::from_config(&rpc_config)?; // let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000); - let sled_db = sled::open(env::var("BDK_DB_PATH")?)?.open_tree("default_wallet")?; + // let sled_db = sled::open(env::var("BDK_DB_PATH")?)?.open_tree("default_wallet")?; let wallet = Wallet::new( Bip86(wallet_xprv, KeychainKind::External), Some(Bip86(wallet_xprv, KeychainKind::Internal)), bitcoin::Network::Regtest, - sled_db, + MemoryDatabase::new(), )?; wallet