From: 志宇 Date: Tue, 2 Jul 2024 03:53:54 +0000 (+0000) Subject: feat(esplora): always fetch prevouts X-Git-Tag: v1.0.0-beta.2~10^2~8 X-Git-Url: http://internal-gitweb-vhost/script/%22https:/struct.ScriptPath.html?a=commitdiff_plain;h=c93e6fd3e6289f2c7bc12012eae7231d03cb04cb;p=bdk 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). --- diff --git a/crates/esplora/Cargo.toml b/crates/esplora/Cargo.toml index 149bce9b..9148a0f8 100644 --- a/crates/esplora/Cargo.toml +++ b/crates/esplora/Cargo.toml @@ -16,8 +16,6 @@ bdk_chain = { path = "../chain", version = "0.17.0", default-features = false } esplora-client = { version = "0.9.0", default-features = false } async-trait = { version = "0.1.66", optional = true } futures = { version = "0.3.26", optional = true } - -bitcoin = { version = "0.32.0", optional = true, default-features = false } miniscript = { version = "12.0.0", optional = true, default-features = false } [dev-dependencies] diff --git a/crates/esplora/src/async_ext.rs b/crates/esplora/src/async_ext.rs index 139180b0..fed6dd52 100644 --- a/crates/esplora/src/async_ext.rs +++ b/crates/esplora/src/async_ext.rs @@ -4,16 +4,16 @@ use std::usize; use async_trait::async_trait; use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult}; use bdk_chain::{ - bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, + bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid}, collections::BTreeMap, local_chain::CheckPoint, BlockId, ConfirmationBlockTime, TxGraph, }; use bdk_chain::{Anchor, Indexed}; -use esplora_client::{Amount, Tx, TxStatus}; +use esplora_client::{Tx, TxStatus}; use futures::{stream::FuturesOrdered, TryStreamExt}; -use crate::anchor_from_status; +use crate::{insert_anchor_from_status, insert_prevouts}; /// [`esplora_client::Error`] type Error = Box; @@ -230,27 +230,8 @@ impl EsploraAsyncExt for esplora_client::AsyncClient { } for tx in txs { let _ = tx_graph.insert_tx(tx.to_tx()); - if let Some(anchor) = anchor_from_status(&tx.status) { - let _ = tx_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: Amount::from_sat(prevout.value), - }, - )) - }); - - for (outpoint, txout) in previous_outputs { - let _ = tx_graph.insert_txout(outpoint, txout); - } + insert_anchor_from_status(&mut tx_graph, tx.txid, tx.status); + insert_prevouts(&mut tx_graph, tx.vin); } } @@ -330,15 +311,12 @@ impl EsploraAsyncExt for esplora_client::AsyncClient { for (txid, resp) in handles.try_collect::>().await? { match resp { EsploraResp::TxStatus(status) => { - if let Some(anchor) = anchor_from_status(&status) { - let _ = tx_graph.insert_anchor(txid, anchor); - } + insert_anchor_from_status(&mut tx_graph, txid, status); } EsploraResp::Tx(Some(tx_info)) => { let _ = tx_graph.insert_tx(tx_info.to_tx()); - if let Some(anchor) = anchor_from_status(&tx_info.status) { - let _ = tx_graph.insert_anchor(txid, anchor); - } + insert_anchor_from_status(&mut tx_graph, txid, tx_info.status); + insert_prevouts(&mut tx_graph, tx_info.vin); } _ => continue, } @@ -389,9 +367,7 @@ impl EsploraAsyncExt for esplora_client::AsyncClient { missing_txs.push(spend_txid); } if let Some(spend_status) = op_status.status { - if let Some(spend_anchor) = anchor_from_status(&spend_status) { - let _ = tx_graph.insert_anchor(spend_txid, spend_anchor); - } + insert_anchor_from_status(&mut tx_graph, spend_txid, spend_status); } } } diff --git a/crates/esplora/src/blocking_ext.rs b/crates/esplora/src/blocking_ext.rs index a5bb0cd3..81ce7684 100644 --- a/crates/esplora/src/blocking_ext.rs +++ b/crates/esplora/src/blocking_ext.rs @@ -4,14 +4,14 @@ use std::thread::JoinHandle; use bdk_chain::collections::BTreeMap; use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult}; use bdk_chain::{ - bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, + bitcoin::{BlockHash, OutPoint, ScriptBuf, Txid}, local_chain::CheckPoint, BlockId, ConfirmationBlockTime, TxGraph, }; use bdk_chain::{Anchor, Indexed}; use esplora_client::{OutputStatus, Tx, TxStatus}; -use crate::anchor_from_status; +use crate::{insert_anchor_from_status, insert_prevouts}; /// [`esplora_client::Error`] pub type Error = Box; @@ -210,27 +210,8 @@ impl EsploraExt for esplora_client::BlockingClient { } for tx in txs { let _ = tx_graph.insert_tx(tx.to_tx()); - if let Some(anchor) = anchor_from_status(&tx.status) { - let _ = tx_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: Amount::from_sat(prevout.value), - }, - )) - }); - - for (outpoint, txout) in previous_outputs { - let _ = tx_graph.insert_txout(outpoint, txout); - } + insert_anchor_from_status(&mut tx_graph, tx.txid, tx.status); + insert_prevouts(&mut tx_graph, tx.vin); } } @@ -310,15 +291,12 @@ impl EsploraExt for esplora_client::BlockingClient { let (txid, resp) = handle.join().expect("thread must not panic")?; match resp { EsploraResp::TxStatus(status) => { - if let Some(anchor) = anchor_from_status(&status) { - let _ = tx_graph.insert_anchor(txid, anchor); - } + insert_anchor_from_status(&mut tx_graph, txid, status); } EsploraResp::Tx(Some(tx_info)) => { let _ = tx_graph.insert_tx(tx_info.to_tx()); - if let Some(anchor) = anchor_from_status(&tx_info.status) { - let _ = tx_graph.insert_anchor(txid, anchor); - } + insert_anchor_from_status(&mut tx_graph, txid, tx_info.status); + insert_prevouts(&mut tx_graph, tx_info.vin); } _ => continue, } @@ -373,9 +351,7 @@ impl EsploraExt for esplora_client::BlockingClient { missing_txs.push(spend_txid); } if let Some(spend_status) = op_status.status { - if let Some(spend_anchor) = anchor_from_status(&spend_status) { - let _ = tx_graph.insert_anchor(spend_txid, spend_anchor); - } + insert_anchor_from_status(&mut tx_graph, spend_txid, spend_status); } } } diff --git a/crates/esplora/src/lib.rs b/crates/esplora/src/lib.rs index fab05588..2c0e62b7 100644 --- a/crates/esplora/src/lib.rs +++ b/crates/esplora/src/lib.rs @@ -56,7 +56,8 @@ //! [`ChainOracle`]: bdk_chain::ChainOracle //! [`example_esplora`]: https://github.com/bitcoindevkit/bdk/tree/master/example-crates/example_esplora -use bdk_chain::{BlockId, ConfirmationBlockTime}; +use bdk_chain::bitcoin::{Amount, OutPoint, TxOut, Txid}; +use bdk_chain::{BlockId, ConfirmationBlockTime, TxGraph}; use esplora_client::TxStatus; pub use esplora_client; @@ -71,19 +72,42 @@ mod async_ext; #[cfg(feature = "async")] pub use async_ext::*; -fn anchor_from_status(status: &TxStatus) -> Option { +fn insert_anchor_from_status( + tx_graph: &mut TxGraph, + txid: Txid, + status: TxStatus, +) { if let TxStatus { block_height: Some(height), block_hash: Some(hash), block_time: Some(time), .. - } = status.clone() + } = status { - Some(ConfirmationBlockTime { + let anchor = ConfirmationBlockTime { block_id: BlockId { height, hash }, confirmation_time: time, - }) - } else { - None + }; + let _ = tx_graph.insert_anchor(txid, anchor); + } +} + +/// Inserts floating txouts into `tx_graph` using [`Vin`](esplora_client::api::Vin)s returned by +/// Esplora. +fn insert_prevouts( + tx_graph: &mut TxGraph, + esplora_inputs: impl IntoIterator, +) { + let prevouts = esplora_inputs + .into_iter() + .filter_map(|vin| Some((vin.txid, vin.vout, vin.prevout?))); + for (prev_txid, prev_vout, prev_txout) in prevouts { + let _ = tx_graph.insert_txout( + OutPoint::new(prev_txid, prev_vout), + TxOut { + script_pubkey: prev_txout.scriptpubkey, + value: Amount::from_sat(prev_txout.value), + }, + ); } }