fix: TxGraph::missing_blocks logic

Added additional tests for unnecessary duplicate heights
This commit is contained in:
志宇
2023-07-22 22:41:33 +08:00
parent db15e03bdc
commit bea8e5aff4
5 changed files with 191 additions and 16 deletions

View File

@@ -4,7 +4,7 @@ use bdk_chain::{
collections::*,
local_chain::LocalChain,
tx_graph::{Additions, TxGraph},
Append, BlockId, ChainPosition, ConfirmationHeightAnchor,
Anchor, Append, BlockId, ChainPosition, ConfirmationHeightAnchor,
};
use bitcoin::{
hashes::Hash, BlockHash, OutPoint, PackedLockTime, Script, Transaction, TxIn, TxOut, Txid,
@@ -822,3 +822,136 @@ fn test_additions_last_seen_append() {
);
}
}
#[test]
fn test_missing_blocks() {
/// An anchor implementation for testing, made up of `(the_anchor_block, random_data)`.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, core::hash::Hash)]
struct TestAnchor(BlockId);
impl Anchor for TestAnchor {
fn anchor_block(&self) -> BlockId {
self.0
}
}
struct Scenario<'a> {
name: &'a str,
graph: TxGraph<TestAnchor>,
chain: LocalChain,
exp_heights: &'a [u32],
}
const fn new_anchor(height: u32, hash: BlockHash) -> TestAnchor {
TestAnchor(BlockId { height, hash })
}
fn new_scenario<'a>(
name: &'a str,
graph_anchors: &'a [(Txid, TestAnchor)],
chain: &'a [(u32, BlockHash)],
exp_heights: &'a [u32],
) -> Scenario<'a> {
Scenario {
name,
graph: {
let mut g = TxGraph::default();
for (txid, anchor) in graph_anchors {
let _ = g.insert_anchor(*txid, anchor.clone());
}
g
},
chain: {
let mut c = LocalChain::default();
for (height, hash) in chain {
let _ = c.insert_block(BlockId {
height: *height,
hash: *hash,
});
}
c
},
exp_heights,
}
}
fn run(scenarios: &[Scenario]) {
for scenario in scenarios {
let Scenario {
name,
graph,
chain,
exp_heights,
} = scenario;
let heights = graph.missing_heights(chain).collect::<Vec<_>>();
assert_eq!(&heights, exp_heights, "scenario: {}", name);
}
}
run(&[
new_scenario(
"2 txs with the same anchor (2:B) which is missing from chain",
&[
(h!("tx_1"), new_anchor(2, h!("B"))),
(h!("tx_2"), new_anchor(2, h!("B"))),
],
&[(1, h!("A")), (3, h!("C"))],
&[2],
),
new_scenario(
"2 txs with different anchors at the same height, one of the anchors is missing",
&[
(h!("tx_1"), new_anchor(2, h!("B1"))),
(h!("tx_2"), new_anchor(2, h!("B2"))),
],
&[(1, h!("A")), (2, h!("B1"))],
&[],
),
new_scenario(
"tx with 2 anchors of same height which are missing from the chain",
&[
(h!("tx"), new_anchor(3, h!("C1"))),
(h!("tx"), new_anchor(3, h!("C2"))),
],
&[(1, h!("A")), (4, h!("D"))],
&[3],
),
new_scenario(
"tx with 2 anchors at the same height, chain has this height but does not match either anchor",
&[
(h!("tx"), new_anchor(4, h!("D1"))),
(h!("tx"), new_anchor(4, h!("D2"))),
],
&[(4, h!("D3")), (5, h!("E"))],
&[],
),
new_scenario(
"tx with 2 anchors at different heights, one anchor exists in chain, should return nothing",
&[
(h!("tx"), new_anchor(3, h!("C"))),
(h!("tx"), new_anchor(4, h!("D"))),
],
&[(4, h!("D")), (5, h!("E"))],
&[],
),
new_scenario(
"tx with 2 anchors at different heights, first height is already in chain with different hash, iterator should only return 2nd height",
&[
(h!("tx"), new_anchor(5, h!("E1"))),
(h!("tx"), new_anchor(6, h!("F1"))),
],
&[(4, h!("D")), (5, h!("E")), (7, h!("G"))],
&[6],
),
new_scenario(
"tx with 2 anchors at different heights, neither height is in chain, both heights should be returned",
&[
(h!("tx"), new_anchor(3, h!("C"))),
(h!("tx"), new_anchor(4, h!("D"))),
],
&[(1, h!("A")), (2, h!("B"))],
&[3, 4],
),
]);
}