Skip to content

Commit 5f6dfe7

Browse files
ValuedMammalLagginTimes
authored andcommitted
feat(chain): add method iter_spks_with_expected_txids
1 parent 3be6c2b commit 5f6dfe7

2 files changed

Lines changed: 90 additions & 4 deletions

File tree

crates/chain/src/indexed_tx_graph.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
//! Contains the [`IndexedTxGraph`] and associated types. Refer to the
22
//! [`IndexedTxGraph`] documentation for more.
3-
use core::fmt::Debug;
3+
4+
use core::fmt;
5+
use core::ops::RangeBounds;
46

57
use alloc::{sync::Arc, vec::Vec};
6-
use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};
8+
use bitcoin::{Block, OutPoint, ScriptBuf, Transaction, TxOut, Txid};
79

810
use crate::{
11+
spk_txout::SpkTxOutIndex,
912
tx_graph::{self, TxGraph},
10-
Anchor, BlockId, Indexer, Merge, TxPosInBlock,
13+
Anchor, BlockId, ChainOracle, Indexer, Merge, TxPosInBlock,
1114
};
1215

1316
/// The [`IndexedTxGraph`] combines a [`TxGraph`] and an [`Indexer`] implementation.
@@ -324,6 +327,43 @@ where
324327
indexer,
325328
}
326329
}
330+
331+
/// Inserts the given `evicted_at` for `txid`.
332+
///
333+
/// The `evicted_at` timestamp represents the last known time when the transaction was observed
334+
/// to be missing from the mempool. If `txid` was previously recorded with an earlier
335+
/// `evicted_at` value, it is updated only if the new value is greater.
336+
pub fn insert_evicted_at(&mut self, txid: Txid, evicted_at: u64) -> ChangeSet<A, I::ChangeSet> {
337+
let tx_graph = self.graph.insert_evicted_at(txid, evicted_at);
338+
ChangeSet {
339+
tx_graph,
340+
..Default::default()
341+
}
342+
}
343+
}
344+
345+
impl<A, I> IndexedTxGraph<A, SpkTxOutIndex<I>>
346+
where
347+
A: Anchor,
348+
I: fmt::Debug + Clone + Ord,
349+
{
350+
/// Returns an iterator over unconfirmed transactions and their associated script pubkeys,
351+
/// filtered within the specified `range`.
352+
///
353+
/// This function delegates the transaction filtering to [`TxGraph::iter_spks_with_expected_txids`],
354+
/// using the [`SpkTxOutIndex`] stored in [`IndexedTxGraph`]. The [`TxGraph`] internally scans
355+
/// for unconfirmed transactions relevant to the indexed outputs.
356+
pub fn iter_spks_with_expected_txids<'a, O>(
357+
&'a self,
358+
chain: &'a O,
359+
range: impl RangeBounds<I> + 'a,
360+
) -> impl Iterator<Item = (Txid, ScriptBuf)> + 'a
361+
where
362+
O: ChainOracle<Error = core::convert::Infallible>,
363+
{
364+
self.graph
365+
.iter_spks_with_expected_txids(chain, &self.index, range)
366+
}
327367
}
328368

329369
impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {

crates/chain/src/tx_graph.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,11 @@
9191
//! [`insert_txout`]: TxGraph::insert_txout
9292
9393
use crate::collections::*;
94+
use crate::spk_txout::SpkTxOutIndex;
9495
use crate::BlockId;
9596
use crate::CanonicalIter;
9697
use crate::CanonicalReason;
98+
use crate::Indexer;
9799
use crate::ObservedIn;
98100
use crate::{Anchor, Balance, ChainOracle, ChainPosition, FullTxOut, Merge};
99101
use alloc::collections::vec_deque::VecDeque;
@@ -105,7 +107,7 @@ use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txi
105107
use core::fmt::{self, Formatter};
106108
use core::{
107109
convert::Infallible,
108-
ops::{Deref, RangeInclusive},
110+
ops::{Deref, RangeBounds, RangeInclusive},
109111
};
110112

111113
impl<A: Ord> From<TxGraph<A>> for TxUpdate<A> {
@@ -1161,6 +1163,50 @@ impl<A: Anchor> TxGraph<A> {
11611163
self.try_balance(chain, chain_tip, outpoints, trust_predicate)
11621164
.expect("oracle is infallible")
11631165
}
1166+
1167+
/// Returns an iterator over unconfirmed transactions and their associated script pubkeys,
1168+
/// filtered within the specified `range`.
1169+
///
1170+
/// This function scans the transaction graph for unconfirmed transactions relevant to the
1171+
/// provided [`SpkTxOutIndex`], determining which transactions should be considered based on
1172+
/// indexed outputs.
1173+
pub fn iter_spks_with_expected_txids<'a, C, I>(
1174+
&'a self,
1175+
chain: &'a C,
1176+
indexer: &'a SpkTxOutIndex<I>,
1177+
range: impl RangeBounds<I> + 'a,
1178+
) -> impl Iterator<Item = (Txid, ScriptBuf)> + 'a
1179+
where
1180+
C: ChainOracle<Error = core::convert::Infallible>,
1181+
I: fmt::Debug + Clone + Ord,
1182+
{
1183+
let chain_tip = chain.get_chain_tip().unwrap();
1184+
1185+
self.list_canonical_txs(chain, chain_tip)
1186+
.filter(|c| !c.chain_position.is_confirmed() && indexer.is_tx_relevant(&c.tx_node))
1187+
.flat_map(move |c| {
1188+
let txid = c.tx_node.txid;
1189+
let spks = c
1190+
.tx_node
1191+
.input
1192+
.iter()
1193+
.map(|txin| txin.previous_output)
1194+
.chain(
1195+
c.tx_node
1196+
.output
1197+
.iter()
1198+
.enumerate()
1199+
.map(move |(vout, _)| OutPoint::new(txid, vout as u32)),
1200+
)
1201+
.flat_map(|op| match indexer.txout(op) {
1202+
Some((i, txo)) if range.contains(i) => Some(txo.script_pubkey.clone()),
1203+
_ => None,
1204+
})
1205+
.collect::<Vec<_>>();
1206+
1207+
core::iter::repeat(txid).zip(spks)
1208+
})
1209+
}
11641210
}
11651211

11661212
/// The [`ChangeSet`] represents changes to a [`TxGraph`].

0 commit comments

Comments
 (0)