Skip to content

Commit

Permalink
feat(esplora): include previous TxOuts for fee calculation
Browse files Browse the repository at this point in the history
The previous `TxOut` for transactions received from an external
wallet are added as floating `TxOut`s to `TxGraph` to allow for
fee calculation.
  • Loading branch information
LagginTimes committed Feb 2, 2024
1 parent f099b42 commit 38c383c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
20 changes: 19 additions & 1 deletion crates/esplora/src/async_ext.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use async_trait::async_trait;
use bdk_chain::collections::btree_map;
use bdk_chain::{
bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid},
bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
collections::BTreeMap,
local_chain::{self, CheckPoint},
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
Expand Down Expand Up @@ -204,6 +204,24 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
if let Some(anchor) = anchor_from_status(&tx.status) {
let _ = graph.insert_anchor(tx.txid, anchor);
}

let previous_outputs = tx.vin.iter().filter_map(|vin| {
let prevout = vin.prevout.as_ref()?;
Some((
OutPoint {
txid: vin.txid,
vout: vin.vout,
},
TxOut {
script_pubkey: prevout.scriptpubkey.clone(),
value: prevout.value,
},
))
});

for (outpoint, txout) in previous_outputs {
let _ = graph.insert_txout(outpoint, txout);
}
}
}

Expand Down
20 changes: 19 additions & 1 deletion crates/esplora/src/blocking_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::thread::JoinHandle;
use bdk_chain::collections::btree_map;
use bdk_chain::collections::BTreeMap;
use bdk_chain::{
bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid},
bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
local_chain::{self, CheckPoint},
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
};
Expand Down Expand Up @@ -194,6 +194,24 @@ impl EsploraExt for esplora_client::BlockingClient {
if let Some(anchor) = anchor_from_status(&tx.status) {
let _ = graph.insert_anchor(tx.txid, anchor);
}

let previous_outputs = tx.vin.iter().filter_map(|vin| {
let prevout = vin.prevout.as_ref()?;
Some((
OutPoint {
txid: vin.txid,
vout: vin.vout,
},
TxOut {
script_pubkey: prevout.scriptpubkey.clone(),
value: prevout.value,
},
))
});

for (outpoint, txout) in previous_outputs {
let _ = graph.insert_txout(outpoint, txout);
}
}
}

Expand Down
21 changes: 21 additions & 0 deletions crates/esplora/tests/async_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ pub async fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
)
.await?;

// Check to see if we have the floating txouts available from our two created transactions'
// previous outputs in order to calculate transaction fees.
graph_update.full_txs().for_each(|tx| {
let calculate_fee_result = graph_update.calculate_fee(tx.tx);
let get_tx_result = env.bitcoind.client.get_transaction(&tx.txid, None);

// Check if fee calculation and transaction retrieval were successful
let tx_fee_exists = get_tx_result.as_ref().map_or(false, |tx| tx.fee.is_some());
assert_eq!(calculate_fee_result.is_ok(), tx_fee_exists);

// Check if the calculated fee value matches the fee from transaction retrieval
if let (Ok(fee), Ok(transaction)) = (calculate_fee_result, get_tx_result) {
let tx_fee = transaction
.fee
.unwrap_or_else(|| panic!("Fee not found for transaction {:?}", tx.txid))
.abs()
.to_sat() as u64;
assert_eq!(fee, tx_fee);
}
});

let mut graph_update_txids: Vec<Txid> = graph_update.full_txs().map(|tx| tx.txid).collect();
graph_update_txids.sort();
let mut expected_txids = vec![txid1, txid2];
Expand Down
26 changes: 26 additions & 0 deletions crates/esplora/tests/blocking_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,32 @@ pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
1,
)?;

// Check to see if we have the floating txouts available from our two created transactions'
// previous outputs in order to calculate transaction fees.
graph_update.full_txs().for_each(|tx| {
let calculate_fee_result = graph_update.calculate_fee(tx.tx);
let get_tx_result = env.bitcoind.client.get_transaction(&tx.txid, None);

// Check if fee calculation and transaction retrieval were successful
let tx_fee_exists = get_tx_result.as_ref().map_or(false, |tx| tx.fee.is_some());
assert_eq!(calculate_fee_result.is_ok(), tx_fee_exists);

// Check if the calculated fee value matches the fee from transaction retrieval
if let (Ok(fee), Ok(transaction)) = (calculate_fee_result, get_tx_result) {
let tx_fee = transaction
.fee
.unwrap_or_else(|| panic!("Fee not found for transaction {:?}", tx.txid))
.abs()
.to_sat() as u64;
assert_eq!(fee, tx_fee);
}
});
// Ensure there are exactly two fee calculations.
// assert_eq!(fee_calculations.len(), 2);

// Ensure that both fee calculations are successful.
// assert!(fee_calculations.iter().all(|&is_ok| is_ok));

let mut graph_update_txids: Vec<Txid> = graph_update.full_txs().map(|tx| tx.txid).collect();
graph_update_txids.sort();
let mut expected_txids = vec![txid1, txid2];
Expand Down

0 comments on commit 38c383c

Please sign in to comment.