improve mempool lookup of escrow psbt

This commit is contained in:
fbock
2024-08-06 13:27:21 +02:00
parent deedcd679f
commit 6adcabcb54
8 changed files with 89 additions and 32 deletions

View File

@ -1,7 +1,7 @@
BITCOIN_RPC_ADDRESS_PORT="127.0.0.1:8332" BITCOIN_RPC_ADDRESS_PORT="127.0.0.1:8332"
BITCOIN_RPC_USER="coordinator" BITCOIN_RPC_USER="coordinator"
BITCOIN_RPC_PASSWORD="test1234" 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) BDK_DB_PATH="./dbs/bdk-wallet" # Path to the BDK Sled database (no .db postfix)
WALLET_XPRV="tprv8ZgxMBicQKsPdHuCSjhQuSZP1h6ZTeiRqREYS5guGPdtL7D1uNLpnJmb2oJep99Esq1NbNZKVJBNnD2ZhuXSK7G5eFmmcx73gsoa65e2U32" WALLET_XPRV="tprv8ZgxMBicQKsPdHuCSjhQuSZP1h6ZTeiRqREYS5guGPdtL7D1uNLpnJmb2oJep99Esq1NbNZKVJBNnD2ZhuXSK7G5eFmmcx73gsoa65e2U32"
PUNISHMENT_ENABLED=1 # enable punishment for misbehaving traders PUNISHMENT_ENABLED=1 # enable punishment for misbehaving traders

View File

@ -107,7 +107,7 @@ async fn request_offer_status_maker(
Ok(offer_taken_response) => Ok(Json(offer_taken_response).into_response()), Ok(offer_taken_response) => Ok(Json(offer_taken_response).into_response()),
Err(FetchOffersError::NoOffersAvailable) => Ok(StatusCode::NO_CONTENT.into_response()), Err(FetchOffersError::NoOffersAvailable) => Ok(StatusCode::NO_CONTENT.into_response()),
Err(FetchOffersError::Database(e)) => { 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()) Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response())
} }
} }

View File

@ -4,6 +4,8 @@ pub mod create_taproot;
pub mod mempool_monitoring; pub mod mempool_monitoring;
pub mod tx_confirmation_monitoring; pub mod tx_confirmation_monitoring;
use axum::routing::trace;
use self::coordinator_utils::*; use self::coordinator_utils::*;
use super::*; use super::*;
@ -139,6 +141,10 @@ pub async fn handle_taker_bond(
return Err(BondError::CoordinatorError(e.to_string())); return Err(BondError::CoordinatorError(e.to_string()));
} }
}; };
debug!(
"\nEscrow PSBT creation successful: {:?}",
escrow_output_data
);
if let Err(e) = database if let Err(e) = database
.add_taker_info_and_move_table(payload, &escrow_output_data) .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())); return Err(BondError::CoordinatorError(e.to_string()));
} }
trace!("Taker information added to database and moved table successfully");
Ok(OfferTakenResponse { Ok(OfferTakenResponse {
escrow_psbt_hex: escrow_output_data.escrow_psbt_hex, escrow_psbt_hex: escrow_output_data.escrow_psbt_hex,
escrow_output_descriptor: escrow_output_data.escrow_output_descriptor, escrow_output_descriptor: escrow_output_data.escrow_output_descriptor,

View File

@ -1,6 +1,12 @@
use std::str::FromStr; 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::*; use super::*;
@ -11,11 +17,44 @@ fn get_confirmations(
let mut now_confirmed_txs = Vec::new(); let mut now_confirmed_txs = Vec::new();
for txid in unconfirmed_txids { for txid in unconfirmed_txids {
let txid_struct = Txid::from_str(&txid)?; let txid_struct = Txid::from_str(&txid)?;
let tx_info = coordinator let tx_info = match coordinator
.coordinator_wallet .coordinator_wallet
.json_rpc_client .json_rpc_client
.as_ref() .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 { if let Some(confirmations) = tx_info.confirmations {
debug!( debug!(
"Transaction {} in now confirmed with {} confirmations", "Transaction {} in now confirmed with {} confirmations",
@ -35,7 +74,7 @@ pub async fn update_transaction_confirmations(coordinator: Arc<Coordinator>) {
trace!("Checking for transaction confirmations"); trace!("Checking for transaction confirmations");
let unconfirmed_transactions = match coordinator let unconfirmed_transactions = match coordinator
.coordinator_db .coordinator_db
.fetch_unconfirmed_bond_txids() .fetch_unconfirmed_escrow_txids()
.await .await
{ {
Ok(txids) => txids, Ok(txids) => txids,

View File

@ -135,8 +135,8 @@ impl CoordinatorDB {
musig_pubkey_compressed_hex_maker TEXT NOT NULL, musig_pubkey_compressed_hex_maker TEXT NOT NULL,
musig_pub_nonce_hex_taker TEXT NOT NULL, musig_pub_nonce_hex_taker TEXT NOT NULL,
musig_pubkey_compressed_hex_taker TEXT NOT NULL, musig_pubkey_compressed_hex_taker TEXT NOT NULL,
escrow_psbt_hex TEXT, escrow_psbt_hex TEXT NOT NULL,
escrow_psbt_txid TEXT, escrow_psbt_txid TEXT NOT NULL,
escrow_psbt_is_confirmed INTEGER, escrow_psbt_is_confirmed INTEGER,
maker_happy INTEGER, maker_happy INTEGER,
taker_happy INTEGER, taker_happy INTEGER,
@ -374,10 +374,10 @@ impl CoordinatorDB {
sqlx::query( sqlx::query(
"INSERT OR REPLACE INTO taken_offers (offer_id, robohash_maker, robohash_taker, is_buy_order, amount_sat, "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_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, 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_hex_taker, escrow_psbt_hex, escrow_output_descriptor, escrow_psbt_is_confirmed, escrow_ongoing, 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) 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.offer_id)
.bind(public_offer.robohash_maker) .bind(public_offer.robohash_maker)
@ -399,8 +399,9 @@ impl CoordinatorDB {
.bind(public_offer.musig_pubkey_hex_maker) .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_pub_nonce_hex.clone())
.bind(trade_and_taker_info.trade_data.musig_pubkey_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_psbt_hex)
.bind(&escrow_tx_data.escrow_tx_txid)
.bind(&escrow_tx_data.escrow_output_descriptor)
.bind(0) .bind(0)
.bind(0) .bind(0)
.bind(&escrow_tx_data.coordinator_xonly_escrow_pk) .bind(&escrow_tx_data.coordinator_xonly_escrow_pk)
@ -419,7 +420,7 @@ impl CoordinatorDB {
) -> Result<Option<EscrowPsbt>> { ) -> Result<Option<EscrowPsbt>> {
let offer = sqlx::query( let offer = sqlx::query(
"SELECT escrow_output_descriptor, escrow_amount_maker_sat, "SELECT escrow_output_descriptor, escrow_amount_maker_sat,
escrow_amount_taker_sat, escrow_fee_per_participant, escrow_taproot_pk_coordinator escrow_amount_taker_sat, escrow_fee_per_participant, escrow_taproot_pk_coordinator, escrow_psbt_hex, escrow_psbt_txid
FROM taken_offers WHERE offer_id = ?", FROM taken_offers WHERE offer_id = ?",
) )
.bind(offer_id_hex) .bind(offer_id_hex)
@ -437,8 +438,10 @@ impl CoordinatorDB {
let coordinator_xonly_escrow_pk = let coordinator_xonly_escrow_pk =
offer.try_get::<String, _>("escrow_taproot_pk_coordinator")?; offer.try_get::<String, _>("escrow_taproot_pk_coordinator")?;
let escrow_psbt_hex = offer.try_get::<String, _>("escrow_psbt_hex")?; let escrow_psbt_hex = offer.try_get::<String, _>("escrow_psbt_hex")?;
let escrow_tx_txid = offer.try_get::<String, _>("escrow_psbt_txid")?;
Ok(Some(EscrowPsbt { Ok(Some(EscrowPsbt {
escrow_tx_txid,
escrow_psbt_hex, escrow_psbt_hex,
escrow_output_descriptor, escrow_output_descriptor,
coordinator_xonly_escrow_pk, coordinator_xonly_escrow_pk,
@ -555,7 +558,7 @@ impl CoordinatorDB {
Ok(()) Ok(())
} }
pub async fn fetch_unconfirmed_bond_txids(&self) -> Result<Vec<String>> { pub async fn fetch_unconfirmed_escrow_txids(&self) -> Result<Vec<String>> {
let mut txids = Vec::new(); let mut txids = Vec::new();
let mut rows = sqlx::query( let mut rows = sqlx::query(
"SELECT escrow_psbt_txid FROM taken_offers WHERE escrow_psbt_is_confirmed = 0", "SELECT escrow_psbt_txid FROM taken_offers WHERE escrow_psbt_is_confirmed = 0",

View File

@ -4,7 +4,7 @@ mod database;
mod wallet; mod wallet;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use bdk::sled; use bdk::{database::MemoryDatabase, sled};
use communication::{api::*, api_server, communication_utils::*, handler_errors::*}; use communication::{api::*, api_server, communication_utils::*, handler_errors::*};
use coordinator::{ use coordinator::{
bond_monitoring::*, coordinator_utils::*, bond_monitoring::*, coordinator_utils::*,
@ -25,7 +25,7 @@ use wallet::{escrow_psbt::*, wallet_utils::*, *};
pub struct Coordinator { pub struct Coordinator {
pub coordinator_db: Arc<CoordinatorDB>, pub coordinator_db: Arc<CoordinatorDB>,
pub coordinator_wallet: Arc<CoordinatorWallet<sled::Tree>>, pub coordinator_wallet: Arc<CoordinatorWallet<MemoryDatabase>>,
} }
// populate .env with values before starting // populate .env with values before starting

View File

@ -157,15 +157,17 @@ impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
let (escrow_psbt, details) = { let (escrow_psbt, details) = {
// maybe we can generate a address/taproot pk directly from the descriptor without a new wallet? // maybe we can generate a address/taproot pk directly from the descriptor without a new wallet?
let temp_wallet = Wallet::new( // let temp_wallet = Wallet::new(
&escrow_output_descriptor, // &escrow_output_descriptor,
None, // None,
bitcoin::Network::Regtest, // bitcoin::Network::Regtest,
MemoryDatabase::new(), // MemoryDatabase::new(),
)?; // )?;
let escrow_address = temp_wallet // let escrow_address = temp_wallet
.get_address(bdk::wallet::AddressIndex::New)? // .get_address(bdk::wallet::AddressIndex::New)?
.address; // .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 // 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 // upfront and substract the fee from the change outputs
@ -177,7 +179,10 @@ impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
- (escrow_amount_taker_sat + escrow_fee_sat_per_participant + tx_fee_abs / 2); - (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 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 builder
.manually_selected_only() .manually_selected_only()
.add_recipient(escrow_address.script_pubkey(), amount_escrow) .add_recipient(escrow_address.script_pubkey(), amount_escrow)
@ -204,7 +209,10 @@ impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
builder.finish()? builder.finish()?
}; };
let escrow_tx_txid: String = details.txid.to_string();
Ok(EscrowPsbt { Ok(EscrowPsbt {
escrow_tx_txid,
escrow_psbt_hex: escrow_psbt.to_string(), escrow_psbt_hex: escrow_psbt.to_string(),
escrow_output_descriptor, escrow_output_descriptor,
coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(), coordinator_xonly_escrow_pk: coordinator_escrow_pk.to_string(),

View File

@ -44,6 +44,7 @@ pub struct CoordinatorWallet<D: bdk::database::BatchDatabase> {
#[derive(Debug)] #[derive(Debug)]
pub struct EscrowPsbt { pub struct EscrowPsbt {
pub escrow_psbt_hex: String, pub escrow_psbt_hex: String,
pub escrow_tx_txid: String,
pub escrow_output_descriptor: String, pub escrow_output_descriptor: String,
pub coordinator_xonly_escrow_pk: String, pub coordinator_xonly_escrow_pk: String,
pub escrow_amount_maker_sat: u64, pub escrow_amount_maker_sat: u64,
@ -58,7 +59,7 @@ pub struct BondRequirements {
pub min_input_sum_sat: u64, pub min_input_sum_sat: u64,
} }
pub async fn init_coordinator_wallet() -> Result<CoordinatorWallet<sled::Tree>> { pub async fn init_coordinator_wallet() -> Result<CoordinatorWallet<MemoryDatabase>> {
let wallet_xprv = ExtendedPrivKey::from_str( let wallet_xprv = ExtendedPrivKey::from_str(
&env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?, &env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?,
)?; )?;
@ -87,12 +88,12 @@ pub async fn init_coordinator_wallet() -> Result<CoordinatorWallet<sled::Tree>>
let mempool = MempoolHandler::new(json_rpc_client_clone).await; let mempool = MempoolHandler::new(json_rpc_client_clone).await;
let backend = RpcBlockchain::from_config(&rpc_config)?; let backend = RpcBlockchain::from_config(&rpc_config)?;
// let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000); // 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( let wallet = Wallet::new(
Bip86(wallet_xprv, KeychainKind::External), Bip86(wallet_xprv, KeychainKind::External),
Some(Bip86(wallet_xprv, KeychainKind::Internal)), Some(Bip86(wallet_xprv, KeychainKind::Internal)),
bitcoin::Network::Regtest, bitcoin::Network::Regtest,
sled_db, MemoryDatabase::new(),
)?; )?;
wallet wallet