From 0536bd59ca54c513f1aca2f7a22b24f67f65b531 Mon Sep 17 00:00:00 2001 From: remix Date: Mon, 15 May 2023 11:43:16 +0200 Subject: [PATCH 1/3] Adds test inserting anchor without tx Test inserting anchors without the corresponding transaction and testing the recoverability of the transaction graph Partially fixes "More tests for IndexedTxGraph and TxGraph #958" https://github.com/bitcoindevkit/bdk/issues/958 --- crates/chain/tests/common/mod.rs | 2 +- crates/chain/tests/test_tx_graph.rs | 92 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/crates/chain/tests/common/mod.rs b/crates/chain/tests/common/mod.rs index 7d7288bdf..560f66fee 100644 --- a/crates/chain/tests/common/mod.rs +++ b/crates/chain/tests/common/mod.rs @@ -1,6 +1,6 @@ #[allow(unused_macros)] macro_rules! h { - ($index:literal) => {{ + ($index:expr) => {{ bitcoin::hashes::Hash::hash($index.as_bytes()) }}; } diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 2b8456119..07f522715 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -822,3 +822,95 @@ fn test_additions_last_seen_append() { ); } } + +/// Inserting anchors without the corresponding transaction +/// and testing the recoverability of the transaction graph +#[test] +fn test_inserting_anchor_without_tx() { + let mut graph = TxGraph::::default(); + let mut graph_recovered = graph.clone(); + let txs = (0..5).map(common::new_tx).collect::>(); + let chain: LocalChain = (0..5) + .map(|i| (i, h!(i.to_string()))) + .collect::>() + .into(); + let anchors = (0..5) + .map(|i| ConfirmationHeightAnchor { + anchor_block: BlockId { + height: i, + hash: *chain.blocks().get(&i).unwrap(), + }, + confirmation_height: 0, + }) + .collect::>(); + + let mut anchor_additions = Additions::default(); + for i in 0..3 { + let additions = graph.insert_anchor(txs[i].txid(), anchors[i]); + anchor_additions.append(additions); + } + + // Additions should only include the Anchor for the Tx-Block 0, 1 and 2 + assert_eq!( + anchor_additions, + Additions { + tx: Default::default(), + txout: Default::default(), + anchors: BTreeSet::from([ + (anchors[0], txs[0].txid()), + (anchors[1], txs[1].txid()), + (anchors[2], txs[2].txid()), + ]), + last_seen: Default::default(), + } + ); + + // graph should be recoverable from additions + graph_recovered.apply_additions(anchor_additions); + assert_eq!(graph, graph_recovered); + + // Check whether Anchors are part of TxGraph + for i in 0..3 { + assert!(graph.all_anchors().contains(&(anchors[i], txs[i].txid()))); + } + + let mut tx_additions = Additions::default(); + for tx in &txs[1..] { + let additions = graph.insert_tx(tx.clone()); + assert_eq!( + additions, + Additions { + tx: BTreeSet::from([tx.clone()]), + txout: Default::default(), + anchors: BTreeSet::default(), + last_seen: Default::default(), + } + ); + tx_additions.append(additions); + } + + // graph should be recoverable from additions + graph_recovered.apply_additions(tx_additions); + assert_eq!(graph, graph_recovered); + + // Transactions 0, 1 and 3 should have an Anchor + for i in 0..3 { + assert_eq!( + graph + .get_chain_position(&chain, chain.tip().unwrap(), txs[i].txid()) + .unwrap(), + ObservedAs::Confirmed(&anchors[i]) + ); + } + + // Transactions 4 and 5 should not have an Anchor + for tx in txs.iter().take(5).skip(4) { + assert_eq!( + graph + .try_get_chain_position(&chain, chain.tip().unwrap(), tx.txid()) + .unwrap() + .unwrap(), + ObservedAs::Unconfirmed(0) + ); + } +} From 3cbf3d469deb2d68caa1e9c160bf0c7acd572413 Mon Sep 17 00:00:00 2001 From: remix Date: Tue, 23 May 2023 17:41:58 +0200 Subject: [PATCH 2/3] Simplify the test. Remove LocalChain --- crates/chain/tests/test_tx_graph.rs | 79 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 07f522715..e1bf21e7e 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -3,7 +3,7 @@ mod common; use bdk_chain::{ collections::*, local_chain::LocalChain, - tx_graph::{Additions, TxGraph}, + tx_graph::{Additions, TxGraph, TxNode}, Append, BlockId, ConfirmationHeightAnchor, ObservedAs, }; use bitcoin::{ @@ -830,23 +830,28 @@ fn test_inserting_anchor_without_tx() { let mut graph = TxGraph::::default(); let mut graph_recovered = graph.clone(); let txs = (0..5).map(common::new_tx).collect::>(); - let chain: LocalChain = (0..5) - .map(|i| (i, h!(i.to_string()))) - .collect::>() - .into(); let anchors = (0..5) .map(|i| ConfirmationHeightAnchor { anchor_block: BlockId { height: i, - hash: *chain.blocks().get(&i).unwrap(), + hash: BlockHash::from_hash(h!(&i.to_string())), }, - confirmation_height: 0, + confirmation_height: i, }) .collect::>(); + let anchors_with_txs = BTreeSet::from([ + (anchors[0], txs[0].clone()), + (anchors[1], txs[1].clone()), + (anchors[2], txs[2].clone()), + ]); + let anchors_with_txids = &anchors_with_txs + .iter() + .map(|(anchor, tx)| (anchor.clone(), tx.txid())) + .collect::>(); let mut anchor_additions = Additions::default(); - for i in 0..3 { - let additions = graph.insert_anchor(txs[i].txid(), anchors[i]); + for (anchor, tx) in &anchors_with_txs { + let additions = graph.insert_anchor(tx.txid(), anchor.clone()); anchor_additions.append(additions); } @@ -854,63 +859,53 @@ fn test_inserting_anchor_without_tx() { assert_eq!( anchor_additions, Additions { - tx: Default::default(), - txout: Default::default(), - anchors: BTreeSet::from([ - (anchors[0], txs[0].txid()), - (anchors[1], txs[1].txid()), - (anchors[2], txs[2].txid()), - ]), - last_seen: Default::default(), + anchors: anchors_with_txids.clone(), + ..Default::default() } ); - // graph should be recoverable from additions + // Graph should be recoverable from additions graph_recovered.apply_additions(anchor_additions); assert_eq!(graph, graph_recovered); - // Check whether Anchors are part of TxGraph - for i in 0..3 { - assert!(graph.all_anchors().contains(&(anchors[i], txs[i].txid()))); - } + // Check whether Anchors 0, 1 and 2 are part of TxGraph + assert_eq!(graph.all_anchors(), anchors_with_txids); + // Insert transactions into graph and check the returned addition let mut tx_additions = Additions::default(); - for tx in &txs[1..] { + for tx in &txs { let additions = graph.insert_tx(tx.clone()); assert_eq!( additions, Additions { tx: BTreeSet::from([tx.clone()]), - txout: Default::default(), - anchors: BTreeSet::default(), - last_seen: Default::default(), + ..Default::default() } ); tx_additions.append(additions); } - // graph should be recoverable from additions + // Graph should be recoverable from additions graph_recovered.apply_additions(tx_additions); assert_eq!(graph, graph_recovered); - // Transactions 0, 1 and 3 should have an Anchor - for i in 0..3 { + // Transactions 0, 1 and 2 should have an Anchor + for (anchor, tx) in &anchors_with_txs { assert_eq!( - graph - .get_chain_position(&chain, chain.tip().unwrap(), txs[i].txid()) - .unwrap(), - ObservedAs::Confirmed(&anchors[i]) + graph.get_tx_node(tx.txid()).unwrap(), + TxNode { + txid: tx.txid(), + tx: tx, + anchors: &BTreeSet::from([anchor.clone()]), + last_seen_unconfirmed: 0 + } ); } - // Transactions 4 and 5 should not have an Anchor - for tx in txs.iter().take(5).skip(4) { - assert_eq!( - graph - .try_get_chain_position(&chain, chain.tip().unwrap(), tx.txid()) - .unwrap() - .unwrap(), - ObservedAs::Unconfirmed(0) - ); + // Transactions 3 and 4 should not have an Anchor + for tx in txs.iter().take(5).skip(3) { + assert!(graph.get_tx_node(tx.txid()).unwrap().anchors.is_empty()); } + + assert!(false) } From f47b2f7d98f3b680026bb84c7228aab6e87686c1 Mon Sep 17 00:00:00 2001 From: remix Date: Mon, 5 Jun 2023 14:55:34 +0200 Subject: [PATCH 3/3] Fix assert!(false) and clippy warnings --- crates/chain/tests/test_tx_graph.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index e1bf21e7e..128bd66e4 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -846,12 +846,12 @@ fn test_inserting_anchor_without_tx() { ]); let anchors_with_txids = &anchors_with_txs .iter() - .map(|(anchor, tx)| (anchor.clone(), tx.txid())) + .map(|(anchor, tx)| (*anchor, tx.txid())) .collect::>(); let mut anchor_additions = Additions::default(); for (anchor, tx) in &anchors_with_txs { - let additions = graph.insert_anchor(tx.txid(), anchor.clone()); + let additions = graph.insert_anchor(tx.txid(), *anchor); anchor_additions.append(additions); } @@ -895,8 +895,8 @@ fn test_inserting_anchor_without_tx() { graph.get_tx_node(tx.txid()).unwrap(), TxNode { txid: tx.txid(), - tx: tx, - anchors: &BTreeSet::from([anchor.clone()]), + tx, + anchors: &BTreeSet::from([*anchor]), last_seen_unconfirmed: 0 } ); @@ -906,6 +906,4 @@ fn test_inserting_anchor_without_tx() { for tx in txs.iter().take(5).skip(3) { assert!(graph.get_tx_node(tx.txid()).unwrap().anchors.is_empty()); } - - assert!(false) }