Skip to content

Commit 6b76092

Browse files
committed
wip
1 parent 9e062a5 commit 6b76092

File tree

1 file changed

+178
-80
lines changed

1 file changed

+178
-80
lines changed

crates/chain/tests/test_tx_graph.rs

Lines changed: 178 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
#[macro_use]
44
mod common;
55
use bdk_chain::tx_graph::TxAncestors;
6-
use bdk_chain::{collections::*, BlockId, CanonicalizationParams, ConfirmationBlockTime};
6+
use bdk_chain::{collections::*, Balance, BlockId, CanonicalizationParams, ConfirmationBlockTime};
77
use bdk_chain::{
88
local_chain::LocalChain,
99
tx_graph::{self, CalculateFeeError},
1010
tx_graph::{ChangeSet, TxGraph},
1111
Anchor, ChainOracle, ChainPosition, Merge,
1212
};
13+
use bdk_testenv::local_chain;
1314
use bdk_testenv::{block_id, hash, utils::new_tx};
1415
use bitcoin::hex::FromHex;
1516
use bitcoin::Witness;
@@ -1550,92 +1551,189 @@ fn test_get_first_seen_of_a_tx() {
15501551

15511552
#[test]
15521553
fn test_list_canonical_txs_topological_order() {
1553-
let txs = vec![new_tx(0), new_tx(1), new_tx(2)];
1554-
let txids: Vec<Txid> = txs.iter().map(Transaction::compute_txid).collect();
1555-
1556-
// graph
1557-
let mut graph = TxGraph::<BlockId>::new(txs);
1558-
1559-
let full_txs: Vec<_> = graph.full_txs().collect();
1560-
assert_eq!(full_txs.len(), 3);
1561-
1562-
let unseen_txs: Vec<_> = graph.txs_with_no_anchor_or_last_seen().collect();
1563-
assert_eq!(unseen_txs.len(), 3);
1564-
15651554
// chain
1566-
let blocks: BTreeMap<u32, BlockHash> = [(0, hash!("g")), (1, hash!("A")), (2, hash!("B"))]
1567-
.into_iter()
1568-
.collect();
1569-
let chain = LocalChain::from_blocks(blocks).unwrap();
1570-
let canonical_txs: Vec<_> = graph
1571-
.list_canonical_txs(
1572-
&chain,
1573-
chain.tip().block_id(),
1574-
CanonicalizationParams::default(),
1575-
)
1576-
.collect();
1577-
assert!(canonical_txs.is_empty());
1578-
drop(canonical_txs);
1579-
1580-
// tx0 with seen_at should be returned by canonical txs
1581-
let _ = graph.insert_seen_at(txids[0], 2);
1582-
let mut canonical_txs = graph.list_canonical_txs(
1583-
&chain,
1584-
chain.tip().block_id(),
1585-
CanonicalizationParams::default(),
1586-
);
1587-
assert_eq!(
1588-
canonical_txs.next().map(|tx| tx.tx_node.txid).unwrap(),
1589-
txids[0]
1555+
let local_chain = local_chain!(
1556+
(0, hash!("A")),
1557+
(1, hash!("B")),
1558+
(2, hash!("C")),
1559+
(3, hash!("D")),
1560+
(4, hash!("E")),
1561+
(5, hash!("F")),
1562+
(6, hash!("G"))
15901563
);
1591-
drop(canonical_txs);
1592-
1593-
// tx1 with anchor should be returned by canonical txs
1594-
let _ = graph.insert_anchor(txids[1], block_id!(2, "B"));
1595-
let canonical_txids: Vec<_> = graph
1596-
.list_canonical_txs(
1597-
&chain,
1598-
chain.tip().block_id(),
1599-
CanonicalizationParams::default(),
1600-
)
1601-
.map(|tx| tx.tx_node.txid)
1602-
.collect();
1603-
1604-
assert!(canonical_txids.contains(&txids[1]));
1605-
assert_eq!(
1606-
graph
1607-
.txs_with_no_anchor_or_last_seen()
1564+
let chain_tip = local_chain.tip().block_id();
1565+
1566+
// scenarios
1567+
let scenarios = [Scenario {
1568+
name: "C spend A, B spend A, and A is in the best chain",
1569+
tx_templates: &[
1570+
TxTemplate {
1571+
tx_name: "A",
1572+
inputs: &[TxInTemplate::Bogus],
1573+
outputs: &[TxOutTemplate::new(10000, Some(0))],
1574+
anchors: &[block_id!(1, "B")],
1575+
last_seen: None,
1576+
assume_canonical: false,
1577+
},
1578+
TxTemplate {
1579+
tx_name: "B",
1580+
inputs: &[TxInTemplate::PrevTx("A", 0), TxInTemplate::Bogus],
1581+
outputs: &[TxOutTemplate::new(5000, Some(0))],
1582+
anchors: &[block_id!(1, "B")],
1583+
last_seen: None,
1584+
assume_canonical: false,
1585+
},
1586+
TxTemplate {
1587+
tx_name: "C",
1588+
inputs: &[TxInTemplate::PrevTx("B", 0), TxInTemplate::Bogus],
1589+
outputs: &[TxOutTemplate::new(2500, Some(0))],
1590+
anchors: &[block_id!(1, "B")],
1591+
last_seen: None,
1592+
assume_canonical: false,
1593+
},
1594+
],
1595+
exp_chain_txs: HashSet::from(["A", "B", "C"]),
1596+
exp_chain_txouts: HashSet::from([("A", 0), ("B", 0), ("C", 0)]),
1597+
exp_unspents: HashSet::from([("C", 0)]),
1598+
exp_balance: Balance {
1599+
immature: Amount::ZERO,
1600+
trusted_pending: Amount::ZERO,
1601+
untrusted_pending: Amount::ZERO,
1602+
confirmed: Amount::from_sat(2500),
1603+
},
1604+
}];
1605+
1606+
for scenario in scenarios {
1607+
let env = init_graph(scenario.tx_templates.iter());
1608+
1609+
let txs = env
1610+
.tx_graph
1611+
.list_canonical_txs(&local_chain, chain_tip, env.canonicalization_params.clone())
1612+
.map(|tx| tx.tx_node.txid)
1613+
.collect::<Vec<_>>();
1614+
println!("{:?}", env.txid_to_name);
1615+
println!("{:?}", txs);
1616+
println!("{:?}", txs);
1617+
let exp_txs: Vec<Txid> = scenario
1618+
.exp_chain_txs
1619+
.iter()
16081620
.collect::<Vec<_>>()
1609-
.len(),
1610-
1
1611-
);
1612-
1613-
// tx2 with seen_at should be returned by canonical txs
1614-
let _ = graph.insert_seen_at(txids[2], 1);
1615-
let canonical_txids: Vec<_> = graph
1616-
.list_canonical_txs(
1617-
&chain,
1618-
chain.tip().block_id(),
1619-
CanonicalizationParams::default(),
1620-
)
1621-
.map(|tx| tx.tx_node.txid)
1622-
.collect();
1623-
1624-
assert!(canonical_txids.contains(&txids[2]));
1625-
assert!(graph.txs_with_no_anchor_or_last_seen().next().is_none());
1626-
1627-
println!("{:?}", canonical_txids);
1628-
for txid in &canonical_txids {
1629-
let tx_node = graph.get_tx_node(*txid);
1630-
println!("{:?}", tx_node);
1621+
.iter()
1622+
.map(|name| *env.txid_to_name.get(*name).expect("txid must exist"))
1623+
.collect();
1624+
assert_eq!(
1625+
txs, exp_txs,
1626+
"\n[{}] 'list_canonical_txs' failed",
1627+
scenario.name
1628+
);
16311629
}
16321630

1633-
let expected_txids = [txids[0], txids[2], txids[1]];
1634-
for (idx, txid) in canonical_txids.iter().enumerate() {
1635-
assert_eq!(expected_txids[idx], *txid);
1636-
}
1631+
// assert
1632+
}
1633+
1634+
struct Scenario<'a> {
1635+
/// Name of the test scenario
1636+
name: &'a str,
1637+
/// Transaction templates
1638+
tx_templates: &'a [TxTemplate<'a, BlockId>],
1639+
/// Names of txs that must exist in the output of `list_canonical_txs`
1640+
exp_chain_txs: HashSet<&'a str>,
1641+
/// Outpoints that must exist in the output of `filter_chain_txouts`
1642+
exp_chain_txouts: HashSet<(&'a str, u32)>,
1643+
/// Outpoints of UTXOs that must exist in the output of `filter_chain_unspents`
1644+
exp_unspents: HashSet<(&'a str, u32)>,
1645+
/// Expected balances
1646+
exp_balance: Balance,
16371647
}
16381648

1649+
// #[test]
1650+
// fn test_list_canonical_txs_topological_order() {
1651+
// let txs = vec![new_tx(0), new_tx(1), new_tx(2)];
1652+
// let txids: Vec<Txid> = txs.iter().map(Transaction::compute_txid).collect();
1653+
1654+
// // graph
1655+
// let mut graph = TxGraph::<BlockId>::new(txs);
1656+
1657+
// let full_txs: Vec<_> = graph.full_txs().collect();
1658+
// assert_eq!(full_txs.len(), 3);
1659+
1660+
// let unseen_txs: Vec<_> = graph.txs_with_no_anchor_or_last_seen().collect();
1661+
// assert_eq!(unseen_txs.len(), 3);
1662+
1663+
// // chain
1664+
// let blocks: BTreeMap<u32, BlockHash> = [(0, hash!("g")), (1, hash!("A")), (2, hash!("B"))]
1665+
// .into_iter()
1666+
// .collect();
1667+
// let chain = LocalChain::from_blocks(blocks).unwrap();
1668+
// let canonical_txs: Vec<_> = graph
1669+
// .list_canonical_txs(
1670+
// &chain,
1671+
// chain.tip().block_id(),
1672+
// CanonicalizationParams::default(),
1673+
// )
1674+
// .collect();
1675+
// assert!(canonical_txs.is_empty());
1676+
// drop(canonical_txs);
1677+
1678+
// // tx0 with seen_at should be returned by canonical txs
1679+
// let _ = graph.insert_seen_at(txids[0], 2);
1680+
// let mut canonical_txs = graph.list_canonical_txs(
1681+
// &chain,
1682+
// chain.tip().block_id(),
1683+
// CanonicalizationParams::default(),
1684+
// );
1685+
// assert_eq!(
1686+
// canonical_txs.next().map(|tx| tx.tx_node.txid).unwrap(),
1687+
// txids[0]
1688+
// );
1689+
// drop(canonical_txs);
1690+
1691+
// // tx1 with anchor should be returned by canonical txs
1692+
// let _ = graph.insert_anchor(txids[1], block_id!(2, "B"));
1693+
// let canonical_txids: Vec<_> = graph
1694+
// .list_canonical_txs(
1695+
// &chain,
1696+
// chain.tip().block_id(),
1697+
// CanonicalizationParams::default(),
1698+
// )
1699+
// .map(|tx| tx.tx_node.txid)
1700+
// .collect();
1701+
1702+
// assert!(canonical_txids.contains(&txids[1]));
1703+
// assert_eq!(
1704+
// graph
1705+
// .txs_with_no_anchor_or_last_seen()
1706+
// .collect::<Vec<_>>()
1707+
// .len(),
1708+
// 1
1709+
// );
1710+
1711+
// // tx2 with seen_at should be returned by canonical txs
1712+
// let _ = graph.insert_seen_at(txids[2], 1);
1713+
// let canonical_txids: Vec<_> = graph
1714+
// .list_canonical_txs(
1715+
// &chain,
1716+
// chain.tip().block_id(),
1717+
// CanonicalizationParams::default(),
1718+
// )
1719+
// .map(|tx| tx.tx_node.txid)
1720+
// .collect();
1721+
1722+
// assert!(canonical_txids.contains(&txids[2]));
1723+
// assert!(graph.txs_with_no_anchor_or_last_seen().next().is_none());
1724+
1725+
// println!("{:?}", canonical_txids);
1726+
// for txid in &canonical_txids {
1727+
// let tx_node = graph.get_tx_node(*txid);
1728+
// println!("{:?}", tx_node);
1729+
// }
1730+
1731+
// let expected_txids = [txids[0], txids[2], txids[1]];
1732+
// for (idx, txid) in canonical_txids.iter().enumerate() {
1733+
// assert_eq!(expected_txids[idx], *txid);
1734+
// }
1735+
// }
1736+
16391737
#[test]
16401738
fn test_canonical_txs_topological_order() {
16411739
let previous_output = OutPoint::new(hash!("op"), 2);

0 commit comments

Comments
 (0)