fix(chain): TxDescendants performs a BFS
This commit also changes test_descendants_no_repeat to check the order of the transactions returned
This commit is contained in:
parent
486e0e1437
commit
2f26eca607
@ -1145,7 +1145,7 @@ impl<A> AsRef<TxGraph<A>> for TxGraph<A> {
|
|||||||
pub struct TxDescendants<'g, A, F> {
|
pub struct TxDescendants<'g, A, F> {
|
||||||
graph: &'g TxGraph<A>,
|
graph: &'g TxGraph<A>,
|
||||||
visited: HashSet<Txid>,
|
visited: HashSet<Txid>,
|
||||||
stack: Vec<(usize, Txid)>,
|
queue: VecDeque<(usize, Txid)>,
|
||||||
filter_map: F,
|
filter_map: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1156,7 +1156,7 @@ impl<'g, A, F> TxDescendants<'g, A, F> {
|
|||||||
Self {
|
Self {
|
||||||
graph,
|
graph,
|
||||||
visited: Default::default(),
|
visited: Default::default(),
|
||||||
stack: [(0, txid)].into(),
|
queue: [(0, txid)].into(),
|
||||||
filter_map,
|
filter_map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1166,10 +1166,10 @@ impl<'g, A, F> TxDescendants<'g, A, F> {
|
|||||||
let mut descendants = Self {
|
let mut descendants = Self {
|
||||||
graph,
|
graph,
|
||||||
visited: Default::default(),
|
visited: Default::default(),
|
||||||
stack: Default::default(),
|
queue: Default::default(),
|
||||||
filter_map,
|
filter_map,
|
||||||
};
|
};
|
||||||
descendants.populate_stack(1, txid);
|
descendants.populate_queue(1, txid);
|
||||||
descendants
|
descendants
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,7 +1186,7 @@ impl<'g, A, F> TxDescendants<'g, A, F> {
|
|||||||
Self {
|
Self {
|
||||||
graph,
|
graph,
|
||||||
visited: Default::default(),
|
visited: Default::default(),
|
||||||
stack: txids.into_iter().map(|txid| (0, txid)).collect(),
|
queue: txids.into_iter().map(|txid| (0, txid)).collect(),
|
||||||
filter_map,
|
filter_map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1205,25 +1205,25 @@ impl<'g, A, F> TxDescendants<'g, A, F> {
|
|||||||
let mut descendants = Self {
|
let mut descendants = Self {
|
||||||
graph,
|
graph,
|
||||||
visited: Default::default(),
|
visited: Default::default(),
|
||||||
stack: Default::default(),
|
queue: Default::default(),
|
||||||
filter_map,
|
filter_map,
|
||||||
};
|
};
|
||||||
for txid in txids {
|
for txid in txids {
|
||||||
descendants.populate_stack(1, txid);
|
descendants.populate_queue(1, txid);
|
||||||
}
|
}
|
||||||
descendants
|
descendants
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'g, A, F> TxDescendants<'g, A, F> {
|
impl<'g, A, F> TxDescendants<'g, A, F> {
|
||||||
fn populate_stack(&mut self, depth: usize, txid: Txid) {
|
fn populate_queue(&mut self, depth: usize, txid: Txid) {
|
||||||
let spend_paths = self
|
let spend_paths = self
|
||||||
.graph
|
.graph
|
||||||
.spends
|
.spends
|
||||||
.range(tx_outpoint_range(txid))
|
.range(tx_outpoint_range(txid))
|
||||||
.flat_map(|(_, spends)| spends)
|
.flat_map(|(_, spends)| spends)
|
||||||
.map(|&txid| (depth, txid));
|
.map(|&txid| (depth, txid));
|
||||||
self.stack.extend(spend_paths);
|
self.queue.extend(spend_paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1235,8 +1235,8 @@ where
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let (op_spends, txid, item) = loop {
|
let (op_spends, txid, item) = loop {
|
||||||
// we have exhausted all paths when stack is empty
|
// we have exhausted all paths when queue is empty
|
||||||
let (op_spends, txid) = self.stack.pop()?;
|
let (op_spends, txid) = self.queue.pop_front()?;
|
||||||
// we do not want to visit the same transaction twice
|
// we do not want to visit the same transaction twice
|
||||||
if self.visited.insert(txid) {
|
if self.visited.insert(txid) {
|
||||||
// ignore paths when user filters them out
|
// ignore paths when user filters them out
|
||||||
@ -1246,7 +1246,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.populate_stack(op_spends + 1, txid);
|
self.populate_queue(op_spends + 1, txid);
|
||||||
Some(item)
|
Some(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ fn test_descendants_no_repeat() {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut graph = TxGraph::<()>::default();
|
let mut graph = TxGraph::<()>::default();
|
||||||
let mut expected_txids = BTreeSet::new();
|
let mut expected_txids = Vec::new();
|
||||||
|
|
||||||
// these are NOT descendants of `tx_a`
|
// these are NOT descendants of `tx_a`
|
||||||
for tx in txs_not_connected {
|
for tx in txs_not_connected {
|
||||||
@ -625,19 +625,14 @@ fn test_descendants_no_repeat() {
|
|||||||
.chain(core::iter::once(&tx_e))
|
.chain(core::iter::once(&tx_e))
|
||||||
{
|
{
|
||||||
let _ = graph.insert_tx(tx.clone());
|
let _ = graph.insert_tx(tx.clone());
|
||||||
assert!(expected_txids.insert(tx.txid()));
|
expected_txids.push(tx.txid());
|
||||||
}
|
}
|
||||||
|
|
||||||
let descendants = graph
|
let descendants = graph
|
||||||
.walk_descendants(tx_a.txid(), |_, txid| Some(txid))
|
.walk_descendants(tx_a.txid(), |_, txid| Some(txid))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
assert_eq!(descendants.len(), expected_txids.len());
|
assert_eq!(descendants, expected_txids);
|
||||||
|
|
||||||
for txid in descendants {
|
|
||||||
assert!(expected_txids.remove(&txid));
|
|
||||||
}
|
|
||||||
assert!(expected_txids.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user