//! [`Indexer`] provides utilities for indexing transaction data.
+use alloc::vec::Vec;
use bitcoin::{OutPoint, Transaction, TxOut};
#[cfg(feature = "miniscript")]
pub mod keychain_txout;
pub mod spk_txout;
+/// Type alias for a list of indexed transaction outputs.
+///
+/// Each element is a tuple of `(index, TxOut)` where index is the index of the input or output in
+/// the original [`Transaction`].
+pub type IndexedTxOuts = Vec<(usize, TxOut)>;
+
/// Utilities for indexing transaction data.
///
/// Types which implement this trait can be used to construct an [`IndexedTxGraph`].
spk_client::{FullScanRequestBuilder, SyncRequestBuilder},
spk_iter::BIP32_MAX_INDEX,
spk_txout::SpkTxOutIndex,
- DescriptorExt, DescriptorId, Indexed, Indexer, KeychainIndexed, SpkIterator,
+ DescriptorExt, DescriptorId, Indexed, IndexedTxOuts, Indexer, KeychainIndexed, SpkIterator,
};
use alloc::{borrow::ToOwned, vec::Vec};
use bitcoin::{
&self,
tx: &Transaction,
range: impl RangeBounds<K>,
- ) -> (Vec<TxOut>, Vec<TxOut>) {
+ ) -> (IndexedTxOuts, IndexedTxOuts) {
self.inner
.sent_and_received_txouts(tx, self.map_to_inner_bounds(range))
}
use crate::{
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
- Indexer,
+ IndexedTxOuts, Indexer,
};
use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
///
/// // Display addresses and amounts
/// println!("Sent:");
- /// for txout in sent_txouts {
+ /// for (i, txout) in sent_txouts {
/// let address = Address::from_script(&txout.script_pubkey, Network::Bitcoin)?;
- /// println!(" from {} - {} sats", address, txout.value.to_sat());
+ /// println!("input {}: from {} - {} sats", i, address, txout.value.to_sat());
/// }
///
/// println!("Received:");
- /// for txout in received_txouts {
+ /// for (i, txout) in received_txouts {
/// let address = Address::from_script(&txout.script_pubkey, Network::Bitcoin)?;
- /// println!(" to {} - {} sats", address, txout.value.to_sat());
+ /// println!("output {}: to {} + {} sats", i, address, txout.value.to_sat());
/// }
/// # Ok(())
/// # }
&self,
tx: &Transaction,
range: impl RangeBounds<I>,
- ) -> (Vec<TxOut>, Vec<TxOut>) {
+ ) -> (IndexedTxOuts, IndexedTxOuts) {
let mut sent = Vec::new();
let mut received = Vec::new();
- for txin in &tx.input {
+ for (i, txin) in tx.input.iter().enumerate() {
if let Some((index, txout)) = self.txout(txin.previous_output) {
if range.contains(index) {
- sent.push(txout.clone());
+ sent.push((i, txout.clone()));
}
}
}
- for txout in &tx.output {
+ for (i, txout) in tx.output.iter().enumerate() {
if let Some(index) = self.index_of_spk(txout.script_pubkey.clone()) {
if range.contains(index) {
- received.push(txout.clone());
+ received.push((i, txout.clone()));
}
}
}
pub use indexed_tx_graph::IndexedTxGraph;
pub mod indexer;
pub use indexer::spk_txout;
-pub use indexer::Indexer;
+pub use indexer::{IndexedTxOuts, Indexer};
pub mod local_chain;
mod tx_data_traits;
pub use tx_data_traits::*;
script_pubkey: spk1.clone(),
}],
};
-
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx1, ..);
assert!(sent_txouts.is_empty());
assert_eq!(
received_txouts,
- vec![TxOut {
- value: Amount::from_sat(42_000),
- script_pubkey: spk1.clone(),
- }]
+ vec![(
+ 0,
+ TxOut {
+ value: Amount::from_sat(42_000),
+ script_pubkey: spk1.clone(),
+ }
+ )]
);
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx1, ..1);
assert!(sent_txouts.is_empty());
assert_eq!(
received_txouts,
- vec![TxOut {
- value: Amount::from_sat(42_000),
- script_pubkey: spk1.clone(),
- }]
+ vec![(
+ 0,
+ TxOut {
+ value: Amount::from_sat(42_000),
+ script_pubkey: spk1.clone(),
+ }
+ )]
);
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx1, 1..);
assert!(sent_txouts.is_empty() && received_txouts.is_empty());
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx2, ..);
assert_eq!(
sent_txouts,
- vec![TxOut {
- value: Amount::from_sat(42_000),
- script_pubkey: spk1.clone(),
- }]
+ vec![(
+ 0,
+ TxOut {
+ value: Amount::from_sat(42_000),
+ script_pubkey: spk1.clone(),
+ }
+ )]
);
assert_eq!(
received_txouts,
vec![
- TxOut {
- value: Amount::from_sat(20_000),
- script_pubkey: spk2.clone(),
- },
- TxOut {
- value: Amount::from_sat(30_000),
- script_pubkey: spk1.clone(),
- }
+ (
+ 0,
+ TxOut {
+ value: Amount::from_sat(20_000),
+ script_pubkey: spk2.clone(),
+ }
+ ),
+ (
+ 1,
+ TxOut {
+ value: Amount::from_sat(30_000),
+ script_pubkey: spk1.clone(),
+ }
+ )
]
);
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx2, ..1);
assert_eq!(
sent_txouts,
- vec![TxOut {
- value: Amount::from_sat(42_000),
- script_pubkey: spk1.clone(),
- }]
+ vec![(
+ 0,
+ TxOut {
+ value: Amount::from_sat(42_000),
+ script_pubkey: spk1.clone(),
+ }
+ )]
);
assert_eq!(
received_txouts,
- vec![TxOut {
- value: Amount::from_sat(30_000),
- script_pubkey: spk1.clone(),
- }]
+ vec![(
+ 1,
+ TxOut {
+ value: Amount::from_sat(30_000),
+ script_pubkey: spk1.clone(),
+ }
+ )]
);
let (sent_txouts, received_txouts) = index.sent_and_received_txouts(&tx2, 1..);
assert!(sent_txouts.is_empty());
assert_eq!(
received_txouts,
- vec![TxOut {
- value: Amount::from_sat(20_000),
- script_pubkey: spk2.clone(),
- }]
+ vec![(
+ 0,
+ TxOut {
+ value: Amount::from_sat(20_000),
+ script_pubkey: spk2.clone(),
+ }
+ )]
);
}