[bdk_chain_redesign] Add test for insert_relevant_txs
Ensure `insert_relevant_txs` does not require transactions to be in topological order. Other changes: Rm `try_list_owned_txs` as it is useless
This commit is contained in:
parent
f3e7b67bf1
commit
165b874dfe
@ -1,11 +1,11 @@
|
|||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid};
|
use bitcoin::{OutPoint, Script, Transaction, TxOut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
keychain::Balance,
|
keychain::Balance,
|
||||||
tx_graph::{Additions, CanonicalTx, TxGraph},
|
tx_graph::{Additions, TxGraph},
|
||||||
Anchor, Append, BlockId, ChainOracle, FullTxOut, ObservedAs,
|
Anchor, Append, BlockId, ChainOracle, FullTxOut, ObservedAs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,36 +153,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Anchor, I: OwnedIndexer> IndexedTxGraph<A, I> {
|
impl<A: Anchor, I: OwnedIndexer> IndexedTxGraph<A, I> {
|
||||||
pub fn try_list_owned_txs<'a, C: ChainOracle + 'a>(
|
|
||||||
&'a self,
|
|
||||||
chain: &'a C,
|
|
||||||
chain_tip: BlockId,
|
|
||||||
) -> impl Iterator<Item = Result<CanonicalTx<'a, Transaction, A>, 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<Error = Infallible> + 'a>(
|
|
||||||
&'a self,
|
|
||||||
chain: &'a C,
|
|
||||||
chain_tip: BlockId,
|
|
||||||
) -> impl Iterator<Item = CanonicalTx<'a, Transaction, A>> {
|
|
||||||
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>(
|
pub fn try_list_owned_txouts<'a, C: ChainOracle + 'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
chain: &'a C,
|
chain: &'a C,
|
||||||
@ -356,21 +326,3 @@ pub trait OwnedIndexer: Indexer {
|
|||||||
/// Determines whether a given script pubkey (`spk`) is owned.
|
/// Determines whether a given script pubkey (`spk`) is owned.
|
||||||
fn is_spk_owned(&self, spk: &Script) -> bool;
|
fn is_spk_owned(&self, spk: &Script) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tx_alters_owned_utxo_set<A, I>(
|
|
||||||
graph: &TxGraph<A>,
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
69
crates/chain/tests/test_indexed_tx_graph.rs
Normal file
69
crates/chain/tests/test_indexed_tx_graph.rs
Normal file
@ -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::<BlockId, SpkTxOutIndex<u32>>::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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user