diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index f44b78474..60a6c646b 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -1,11 +1,11 @@ use core::convert::Infallible; use alloc::vec::Vec; -use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid}; +use bitcoin::{OutPoint, Script, Transaction, TxOut}; use crate::{ keychain::Balance, - tx_graph::{Additions, CanonicalTx, TxGraph}, + tx_graph::{Additions, TxGraph}, Anchor, Append, BlockId, ChainOracle, FullTxOut, ObservedAs, }; @@ -153,36 +153,6 @@ where } impl IndexedTxGraph { - pub fn try_list_owned_txs<'a, C: ChainOracle + 'a>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - ) -> impl Iterator, C::Error>> { - self.graph - .full_txs() - .filter(|node| tx_alters_owned_utxo_set(&self.graph, &self.index, node.txid, node.tx)) - .filter_map(move |tx_node| { - self.graph - .try_get_chain_position(chain, chain_tip, tx_node.txid) - .map(|v| { - v.map(|observed_as| CanonicalTx { - observed_as, - node: tx_node, - }) - }) - .transpose() - }) - } - - pub fn list_owned_txs<'a, C: ChainOracle + 'a>( - &'a self, - chain: &'a C, - chain_tip: BlockId, - ) -> impl Iterator> { - self.try_list_owned_txs(chain, chain_tip) - .map(|r| r.expect("chain oracle is infallible")) - } - pub fn try_list_owned_txouts<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, @@ -356,21 +326,3 @@ pub trait OwnedIndexer: Indexer { /// Determines whether a given script pubkey (`spk`) is owned. fn is_spk_owned(&self, spk: &Script) -> bool; } - -fn tx_alters_owned_utxo_set( - graph: &TxGraph, - index: &I, - txid: Txid, - tx: &Transaction, -) -> bool -where - A: Anchor, - I: OwnedIndexer, -{ - let prev_spends = (0..tx.input.len() as u32) - .map(|vout| OutPoint { txid, vout }) - .filter_map(|op| graph.get_txout(op)); - prev_spends - .chain(&tx.output) - .any(|txout| index.is_spk_owned(&txout.script_pubkey)) -} diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs new file mode 100644 index 000000000..e85d424e4 --- /dev/null +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -0,0 +1,69 @@ +mod common; + +use bdk_chain::{ + indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, + tx_graph::Additions, + BlockId, SpkTxOutIndex, +}; +use bitcoin::{hashes::hex::FromHex, OutPoint, Script, Transaction, TxIn, TxOut}; + +/// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented +/// in topological order. +/// +/// Given 3 transactions (A, B, C), where A has 2 owned outputs. B and C spends an output each of A. +/// Typically, we would only know whether B and C are relevant if we have indexed A (A's outpoints +/// are associated with owned spks in the index). Ensure insertion and indexing is topological- +/// agnostic. +#[test] +fn insert_relevant_txs() { + let mut graph = IndexedTxGraph::>::default(); + + // insert some spks + let spk_0 = Script::from_hex("0014034f9515cace31713707dff8194b8f550eb6d336").unwrap(); + let spk_1 = Script::from_hex("0014beaa39ab2b4f47995c77107d8c3f481d3bd33941").unwrap(); + graph.index.insert_spk(0, spk_0.clone()); + graph.index.insert_spk(1, spk_1.clone()); + + let tx_a = Transaction { + output: vec![ + TxOut { + value: 10_000, + script_pubkey: spk_0, + }, + TxOut { + value: 20_000, + script_pubkey: spk_1, + }, + ], + ..common::new_tx(0) + }; + + let tx_b = Transaction { + input: vec![TxIn { + previous_output: OutPoint::new(tx_a.txid(), 0), + ..Default::default() + }], + ..common::new_tx(1) + }; + + let tx_c = Transaction { + input: vec![TxIn { + previous_output: OutPoint::new(tx_a.txid(), 1), + ..Default::default() + }], + ..common::new_tx(2) + }; + + let txs = [tx_c, tx_b, tx_a]; + + assert_eq!( + graph.insert_relevant_txs(&txs, None, None), + IndexedAdditions { + graph_additions: Additions { + tx: txs.into(), + ..Default::default() + }, + ..Default::default() + } + ) +}