]> Untitled Git - bdk/commitdiff
feat(esplora): include previous `TxOut`s for fee calculation
authorWei Chen <wzc110@gmail.com>
Wed, 31 Jan 2024 15:41:42 +0000 (23:41 +0800)
committerWei Chen <wzc110@gmail.com>
Mon, 5 Feb 2024 09:01:11 +0000 (17:01 +0800)
The previous `TxOut` for transactions received from an external
wallet are added as floating `TxOut`s to `TxGraph` to allow for
fee calculation.

crates/esplora/src/async_ext.rs
crates/esplora/src/blocking_ext.rs
crates/esplora/tests/async_ext.rs
crates/esplora/tests/blocking_ext.rs

index 8e697a2a9ae5d4fb25090398d81ad7909d8a7638..4429bb52c07318e8e6c85a5b27ab3026b00a1115 100644 (file)
@@ -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,
@@ -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);
+                        }
                     }
                 }
 
index a7ee290b00c2a2a0c56e643528f8a130d4febc92..4aa11c5819dcf157b0694f5a1b3af6e5a152525a 100644 (file)
@@ -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,
 };
@@ -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);
+                        }
                     }
                 }
 
index 3124bd2d110c753390709bfb600de2c128afdec0..baae1d11b05ee97c1426a830876df2c98fe7e80d 100644 (file)
@@ -109,6 +109,28 @@ 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.
+    for tx in graph_update.full_txs() {
+        // Retrieve the calculated fee from `TxGraph`, which will panic if we do not have the
+        // floating txouts available from the transactions' previous outputs.
+        let fee = graph_update.calculate_fee(tx.tx).expect("Fee must exist");
+
+        // Retrieve the fee in the transaction data from `bitcoind`.
+        let tx_fee = env
+            .bitcoind
+            .client
+            .get_transaction(&tx.txid, None)
+            .expect("Tx must exist")
+            .fee
+            .expect("Fee must exist")
+            .abs()
+            .to_sat() as u64;
+
+        // Check that the calculated fee matches the fee from the transaction data.
+        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];
index b91231d1d18c182a25c9a27c904d83e3600ce5a2..54c367e76c9094a967ca666eeda92f8076985cae 100644 (file)
@@ -136,6 +136,28 @@ 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.
+    for tx in graph_update.full_txs() {
+        // Retrieve the calculated fee from `TxGraph`, which will panic if we do not have the
+        // floating txouts available from the transactions' previous outputs.
+        let fee = graph_update.calculate_fee(tx.tx).expect("Fee must exist");
+
+        // Retrieve the fee in the transaction data from `bitcoind`.
+        let tx_fee = env
+            .bitcoind
+            .client
+            .get_transaction(&tx.txid, None)
+            .expect("Tx must exist")
+            .fee
+            .expect("Fee must exist")
+            .abs()
+            .to_sat() as u64;
+
+        // Check that the calculated fee matches the fee from the transaction data.
+        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];