Skip to content

Commit f981105

Browse files
committed
feat(esplora): always fetch prevouts
Prevouts are needed to calculate fees for transactions. They are introduced as floating txouts in the update `TxGraph`. A helper method `insert_prevouts` is added to insert the floating txouts using the `Vin`s returned from Esplora. Also replaced `anchor_from_status` with `insert_anchor_from_status` as we always insert the anchor into the update `TxGraph` after getting it. Also removed `bitcoin` dependency as `bdk_chain` already depends on `bitcoin` (and it's re-exported).
1 parent f284e9c commit f981105

File tree

4 files changed

+48
-74
lines changed

4 files changed

+48
-74
lines changed

crates/esplora/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ bdk_chain = { path = "../chain", version = "0.16.0", default-features = false }
1616
esplora-client = { version = "0.9.0", default-features = false }
1717
async-trait = { version = "0.1.66", optional = true }
1818
futures = { version = "0.3.26", optional = true }
19-
20-
bitcoin = { version = "0.32.0", optional = true, default-features = false }
2119
miniscript = { version = "12.0.0", optional = true, default-features = false }
2220

2321
[dev-dependencies]

crates/esplora/src/async_ext.rs

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ use std::usize;
44
use async_trait::async_trait;
55
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
66
use bdk_chain::{
7-
bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
7+
bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid},
88
collections::BTreeMap,
99
local_chain::CheckPoint,
1010
BlockId, ConfirmationBlockTime, TxGraph,
1111
};
1212
use bdk_chain::{Anchor, Indexed};
13-
use esplora_client::{Amount, Tx, TxStatus};
13+
use esplora_client::{Tx, TxStatus};
1414
use futures::{stream::FuturesOrdered, TryStreamExt};
1515

16-
use crate::anchor_from_status;
16+
use crate::{insert_anchor_from_status, insert_prevouts};
1717

1818
/// [`esplora_client::Error`]
1919
type Error = Box<esplora_client::Error>;
@@ -230,27 +230,8 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
230230
}
231231
for tx in txs {
232232
let _ = tx_graph.insert_tx(tx.to_tx());
233-
if let Some(anchor) = anchor_from_status(&tx.status) {
234-
let _ = tx_graph.insert_anchor(tx.txid, anchor);
235-
}
236-
237-
let previous_outputs = tx.vin.iter().filter_map(|vin| {
238-
let prevout = vin.prevout.as_ref()?;
239-
Some((
240-
OutPoint {
241-
txid: vin.txid,
242-
vout: vin.vout,
243-
},
244-
TxOut {
245-
script_pubkey: prevout.scriptpubkey.clone(),
246-
value: Amount::from_sat(prevout.value),
247-
},
248-
))
249-
});
250-
251-
for (outpoint, txout) in previous_outputs {
252-
let _ = tx_graph.insert_txout(outpoint, txout);
253-
}
233+
insert_anchor_from_status(&mut tx_graph, tx.txid, tx.status);
234+
insert_prevouts(&mut tx_graph, tx.vin);
254235
}
255236
}
256237

@@ -330,15 +311,12 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
330311
for (txid, resp) in handles.try_collect::<Vec<_>>().await? {
331312
match resp {
332313
EsploraResp::TxStatus(status) => {
333-
if let Some(anchor) = anchor_from_status(&status) {
334-
let _ = tx_graph.insert_anchor(txid, anchor);
335-
}
314+
insert_anchor_from_status(&mut tx_graph, txid, status);
336315
}
337316
EsploraResp::Tx(Some(tx_info)) => {
338317
let _ = tx_graph.insert_tx(tx_info.to_tx());
339-
if let Some(anchor) = anchor_from_status(&tx_info.status) {
340-
let _ = tx_graph.insert_anchor(txid, anchor);
341-
}
318+
insert_anchor_from_status(&mut tx_graph, txid, tx_info.status);
319+
insert_prevouts(&mut tx_graph, tx_info.vin);
342320
}
343321
_ => continue,
344322
}
@@ -389,9 +367,7 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
389367
missing_txs.push(spend_txid);
390368
}
391369
if let Some(spend_status) = op_status.status {
392-
if let Some(spend_anchor) = anchor_from_status(&spend_status) {
393-
let _ = tx_graph.insert_anchor(spend_txid, spend_anchor);
394-
}
370+
insert_anchor_from_status(&mut tx_graph, spend_txid, spend_status);
395371
}
396372
}
397373
}

crates/esplora/src/blocking_ext.rs

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ use std::thread::JoinHandle;
44
use bdk_chain::collections::BTreeMap;
55
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
66
use bdk_chain::{
7-
bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
7+
bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid},
88
local_chain::CheckPoint,
99
BlockId, ConfirmationBlockTime, TxGraph,
1010
};
1111
use bdk_chain::{Anchor, Indexed};
1212
use esplora_client::{OutputStatus, Tx, TxStatus};
1313

14-
use crate::anchor_from_status;
14+
use crate::{insert_anchor_from_status, insert_prevouts};
1515

1616
/// [`esplora_client::Error`]
1717
pub type Error = Box<esplora_client::Error>;
@@ -210,27 +210,8 @@ impl EsploraExt for esplora_client::BlockingClient {
210210
}
211211
for tx in txs {
212212
let _ = tx_graph.insert_tx(tx.to_tx());
213-
if let Some(anchor) = anchor_from_status(&tx.status) {
214-
let _ = tx_graph.insert_anchor(tx.txid, anchor);
215-
}
216-
217-
let previous_outputs = tx.vin.iter().filter_map(|vin| {
218-
let prevout = vin.prevout.as_ref()?;
219-
Some((
220-
OutPoint {
221-
txid: vin.txid,
222-
vout: vin.vout,
223-
},
224-
TxOut {
225-
script_pubkey: prevout.scriptpubkey.clone(),
226-
value: Amount::from_sat(prevout.value),
227-
},
228-
))
229-
});
230-
231-
for (outpoint, txout) in previous_outputs {
232-
let _ = tx_graph.insert_txout(outpoint, txout);
233-
}
213+
insert_anchor_from_status(&mut tx_graph, tx.txid, tx.status);
214+
insert_prevouts(&mut tx_graph, tx.vin);
234215
}
235216
}
236217

@@ -310,15 +291,12 @@ impl EsploraExt for esplora_client::BlockingClient {
310291
let (txid, resp) = handle.join().expect("thread must not panic")?;
311292
match resp {
312293
EsploraResp::TxStatus(status) => {
313-
if let Some(anchor) = anchor_from_status(&status) {
314-
let _ = tx_graph.insert_anchor(txid, anchor);
315-
}
294+
insert_anchor_from_status(&mut tx_graph, txid, status);
316295
}
317296
EsploraResp::Tx(Some(tx_info)) => {
318297
let _ = tx_graph.insert_tx(tx_info.to_tx());
319-
if let Some(anchor) = anchor_from_status(&tx_info.status) {
320-
let _ = tx_graph.insert_anchor(txid, anchor);
321-
}
298+
insert_anchor_from_status(&mut tx_graph, txid, tx_info.status);
299+
insert_prevouts(&mut tx_graph, tx_info.vin);
322300
}
323301
_ => continue,
324302
}
@@ -373,9 +351,7 @@ impl EsploraExt for esplora_client::BlockingClient {
373351
missing_txs.push(spend_txid);
374352
}
375353
if let Some(spend_status) = op_status.status {
376-
if let Some(spend_anchor) = anchor_from_status(&spend_status) {
377-
let _ = tx_graph.insert_anchor(spend_txid, spend_anchor);
378-
}
354+
insert_anchor_from_status(&mut tx_graph, spend_txid, spend_status);
379355
}
380356
}
381357
}

crates/esplora/src/lib.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656
//! [`ChainOracle`]: bdk_chain::ChainOracle
5757
//! [`example_esplora`]: https://github.com/bitcoindevkit/bdk/tree/master/example-crates/example_esplora
5858
59-
use bdk_chain::{BlockId, ConfirmationBlockTime};
59+
use bdk_chain::bitcoin::{Amount, OutPoint, TxOut, Txid};
60+
use bdk_chain::{BlockId, ConfirmationBlockTime, TxGraph};
6061
use esplora_client::TxStatus;
6162

6263
pub use esplora_client;
@@ -71,19 +72,42 @@ mod async_ext;
7172
#[cfg(feature = "async")]
7273
pub use async_ext::*;
7374

74-
fn anchor_from_status(status: &TxStatus) -> Option<ConfirmationBlockTime> {
75+
fn insert_anchor_from_status(
76+
tx_graph: &mut TxGraph<ConfirmationBlockTime>,
77+
txid: Txid,
78+
status: TxStatus,
79+
) {
7580
if let TxStatus {
7681
block_height: Some(height),
7782
block_hash: Some(hash),
7883
block_time: Some(time),
7984
..
80-
} = status.clone()
85+
} = status
8186
{
82-
Some(ConfirmationBlockTime {
87+
let anchor = ConfirmationBlockTime {
8388
block_id: BlockId { height, hash },
8489
confirmation_time: time,
85-
})
86-
} else {
87-
None
90+
};
91+
let _ = tx_graph.insert_anchor(txid, anchor);
92+
}
93+
}
94+
95+
/// Inserts floating txouts into `tx_graph` using [`Vin`](esplora_client::api::Vin)s returned by
96+
/// Esplora.
97+
fn insert_prevouts(
98+
tx_graph: &mut TxGraph<ConfirmationBlockTime>,
99+
esplora_inputs: impl IntoIterator<Item = esplora_client::api::Vin>,
100+
) {
101+
let prevouts = esplora_inputs
102+
.into_iter()
103+
.filter_map(|vin| Some((vin.txid, vin.vout, vin.prevout?)));
104+
for (prev_txid, prev_vout, prev_txout) in prevouts {
105+
let _ = tx_graph.insert_txout(
106+
OutPoint::new(prev_txid, prev_vout),
107+
TxOut {
108+
script_pubkey: prev_txout.scriptpubkey,
109+
value: Amount::from_sat(prev_txout.value),
110+
},
111+
);
88112
}
89113
}

0 commit comments

Comments
 (0)