]> Untitled Git - bdk/commitdiff
Test cleanup and added documentation.
authorrajarshimaitra <rajarshi149@gmail.com>
Sat, 29 Apr 2023 11:57:12 +0000 (17:27 +0530)
committerrajarshimaitra <rajarshi149@gmail.com>
Sat, 29 Apr 2023 11:57:12 +0000 (17:27 +0530)
- Explainer doc added for the test.
- Test code simplified.
- One more edge cases added.

crates/chain/tests/test_indexed_tx_graph.rs

index 4e847aec3dcbfafd560f630636a5646355c409c1..78f3c3a6490875b687992495037833e002ced9f2 100644 (file)
@@ -6,6 +6,7 @@ use std::collections::{BTreeMap, BTreeSet};
 use bdk_chain::{
     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph},
     keychain::{Balance, DerivationAdditions, KeychainTxOutIndex},
+    local_chain::LocalChain,
     tx_graph::Additions,
     BlockId, ObservedAs,
 };
@@ -76,36 +77,66 @@ fn insert_relevant_txs() {
 }
 
 #[test]
+/// Ensure consistency IndexedTxGraph list_* and balance methods. These methods lists
+/// relevant txouts and utxos from the information fetched from a ChainOracle (here a LocalChain).
+///
+/// Test Setup:
+///
+/// Local Chain =>  <0> ----- <1> ----- <2> ----- <3> ---- ... ---- <150>
+///
+/// Keychains:
+///
+/// keychain_1: Trusted
+/// keychain_2: Untrusted
+///
+/// Transactions:
+///
+/// tx1: A Coinbase, sending 70000 sats to "trusted" address. [Block 0]
+/// tx2: A external Receive, sending 30000 sats to "untrusted" address. [Block 1]
+/// tx3: Internal Spend. Spends tx2 and returns change of 10000 to "trusted" address. [Block 2]
+/// tx4: Mempool tx, sending 20000 sats to "trusted" address.
+/// tx5: Mempool tx, sending 15000 sats to "untested" address.
+/// tx6: Complete unrelated tx. [Block 3]
+///
+/// Different transactions are added via `insert_relevant_txs`.
+/// `list_owned_txout`, `list_owned_utxos` and `balance` method is asserted
+/// with expected values at Block height 0, 1, and 2.
+///
+/// Finally Add more blocks to local chain until tx1 coinbase maturity hits.
+/// Assert maturity at coinbase maturity inflection height. Block height 98 and 99.
+
 fn test_list_owned_txouts() {
-    let mut local_chain = local_chain![
-        (0, h!("Block 0")),
-        (1, h!("Block 1")),
-        (2, h!("Block 2")),
-        (3, h!("Block 3"))
-    ];
-
-    let desc_1 : &str = "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)";
-    let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), desc_1).unwrap();
-    let desc_2 : &str = "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)";
-    let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), desc_2).unwrap();
+    // Create Local chains
+
+    let local_chain = (0..150)
+        .map(|i| (i as u32, h!("random")))
+        .collect::<BTreeMap<u32, BlockHash>>();
+    let local_chain = LocalChain::from(local_chain);
+
+    // Initiate IndexedTxGraph
+
+    let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)").unwrap();
+    let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)").unwrap();
 
     let mut graph = IndexedTxGraph::<BlockId, KeychainTxOutIndex<String>>::default();
 
     graph.index.add_keychain("keychain_1".into(), desc_1);
     graph.index.add_keychain("keychain_2".into(), desc_2);
-
     graph.index.set_lookahead_for_all(10);
 
+    // Get trusted and untrusted addresses
+
     let mut trusted_spks = Vec::new();
     let mut untrusted_spks = Vec::new();
 
     {
+        // we need to scope here to take immutanble reference of the graph
         for _ in 0..10 {
             let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_1".to_string());
+            // TODO Assert indexes
             trusted_spks.push(script.clone());
         }
     }
-
     {
         for _ in 0..10 {
             let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_2".to_string());
@@ -113,9 +144,9 @@ fn test_list_owned_txouts() {
         }
     }
 
-    let trust_predicate = |spk: &Script| trusted_spks.contains(spk);
+    // Create test transactions
 
-    // tx1 is coinbase transaction received at trusted keychain at block 0.
+    // tx1 is the genesis coinbase
     let tx1 = Transaction {
         input: vec![TxIn {
             previous_output: OutPoint::null(),
@@ -171,6 +202,9 @@ fn test_list_owned_txouts() {
     // tx6 is an unrelated transaction confirmed at 3.
     let tx6 = common::new_tx(0);
 
+    // Insert transactions into graph with respective anchors
+    // For unconfirmed txs we pass in `None`.
+
     let _ = graph.insert_relevant_txs(
         [&tx1, &tx2, &tx3, &tx6]
             .iter()
@@ -181,22 +215,25 @@ fn test_list_owned_txouts() {
 
     let _ = graph.insert_relevant_txs([&tx4, &tx5].iter().map(|tx| (*tx, None)), Some(100));
 
-    // AT Block 0
-    {
+    // A helper lambda to extract and filter data from the graph.
+    let fetch = |ht: u32, graph: &IndexedTxGraph<BlockId, KeychainTxOutIndex<String>>| {
         let txouts = graph
-            .list_owned_txouts(&local_chain, local_chain.get_block(0).unwrap())
+            .list_owned_txouts(&local_chain, local_chain.get_block(ht).unwrap())
             .collect::<Vec<_>>();
 
         let utxos = graph
-            .list_owned_unspents(&local_chain, local_chain.get_block(0).unwrap())
+            .list_owned_unspents(&local_chain, local_chain.get_block(ht).unwrap())
             .collect::<Vec<_>>();
 
         let balance = graph.balance(
             &local_chain,
-            local_chain.get_block(0).unwrap(),
-            trust_predicate,
+            local_chain.get_block(ht).unwrap(),
+            |spk: &Script| trusted_spks.contains(spk),
         );
 
+        assert_eq!(txouts.len(), 5);
+        assert_eq!(utxos.len(), 4);
+
         let confirmed_txouts_txid = txouts
             .iter()
             .filter_map(|full_txout| {
@@ -208,7 +245,7 @@ fn test_list_owned_txouts() {
             })
             .collect::<BTreeSet<_>>();
 
-        let unconfirmed_txout_txid = txouts
+        let unconfirmed_txouts_txid = txouts
             .iter()
             .filter_map(|full_txout| {
                 if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
@@ -241,12 +278,30 @@ fn test_list_owned_txouts() {
             })
             .collect::<BTreeSet<_>>();
 
-        assert_eq!(txouts.len(), 5);
-        assert_eq!(utxos.len(), 4);
+        (
+            confirmed_txouts_txid,
+            unconfirmed_txouts_txid,
+            confirmed_utxos_txid,
+            unconfirmed_utxos_txid,
+            balance,
+        )
+    };
+
+    // ----- TEST BLOCK -----
+
+    // AT Block 0
+    {
+        let (
+            confirmed_txouts_txid,
+            unconfirmed_txouts_txid,
+            confirmed_utxos_txid,
+            unconfirmed_utxos_txid,
+            balance,
+        ) = fetch(0, &graph);
 
         assert_eq!(confirmed_txouts_txid, [tx1.txid()].into());
         assert_eq!(
-            unconfirmed_txout_txid,
+            unconfirmed_txouts_txid,
             [tx2.txid(), tx3.txid(), tx4.txid(), tx5.txid()].into()
         );
 
@@ -269,71 +324,18 @@ fn test_list_owned_txouts() {
 
     // AT Block 1
     {
-        let txouts = graph
-            .list_owned_txouts(&local_chain, local_chain.get_block(1).unwrap())
-            .collect::<Vec<_>>();
-
-        let utxos = graph
-            .list_owned_unspents(&local_chain, local_chain.get_block(1).unwrap())
-            .collect::<Vec<_>>();
-
-        let balance = graph.balance(
-            &local_chain,
-            local_chain.get_block(1).unwrap(),
-            trust_predicate,
-        );
-
-        let confirmed_txouts_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_txout_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let confirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        assert_eq!(txouts.len(), 5);
-        assert_eq!(utxos.len(), 4);
+        let (
+            confirmed_txouts_txid,
+            unconfirmed_txouts_txid,
+            confirmed_utxos_txid,
+            unconfirmed_utxos_txid,
+            balance,
+        ) = fetch(1, &graph);
 
         // tx2 gets into confirmed txout set
         assert_eq!(confirmed_txouts_txid, [tx1.txid(), tx2.txid()].into());
         assert_eq!(
-            unconfirmed_txout_txid,
+            unconfirmed_txouts_txid,
             [tx3.txid(), tx4.txid(), tx5.txid()].into()
         );
 
@@ -344,7 +346,6 @@ fn test_list_owned_txouts() {
             [tx3.txid(), tx4.txid(), tx5.txid()].into()
         );
 
-        // Balance breakup remains same
         assert_eq!(
             balance,
             Balance {
@@ -358,73 +359,20 @@ fn test_list_owned_txouts() {
 
     // AT Block 2
     {
-        let txouts = graph
-            .list_owned_txouts(&local_chain, local_chain.get_block(2).unwrap())
-            .collect::<Vec<_>>();
-
-        let utxos = graph
-            .list_owned_unspents(&local_chain, local_chain.get_block(2).unwrap())
-            .collect::<Vec<_>>();
-
-        let balance = graph.balance(
-            &local_chain,
-            local_chain.get_block(2).unwrap(),
-            trust_predicate,
-        );
-
-        let confirmed_txouts_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_txout_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let confirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        assert_eq!(txouts.len(), 5);
-        assert_eq!(utxos.len(), 4);
+        let (
+            confirmed_txouts_txid,
+            unconfirmed_txouts_txid,
+            confirmed_utxos_txid,
+            unconfirmed_utxos_txid,
+            balance,
+        ) = fetch(2, &graph);
 
         // tx3 now gets into the confirmed txout set
         assert_eq!(
             confirmed_txouts_txid,
             [tx1.txid(), tx2.txid(), tx3.txid()].into()
         );
-        assert_eq!(unconfirmed_txout_txid, [tx4.txid(), tx5.txid()].into());
+        assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into());
 
         // tx3 also gets into confirmed utxo set
         assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into());
@@ -441,99 +389,49 @@ fn test_list_owned_txouts() {
         );
     }
 
-    // AT Block 110
+    // AT Block 98
     {
-        let mut local_chain_extension = (4..150)
-            .map(|i| (i as u32, h!("random")))
-            .collect::<BTreeMap<u32, BlockHash>>();
-
-        local_chain_extension.insert(3, h!("Block 3"));
-
-        local_chain
-            .apply_update(local_chain_extension.into())
-            .unwrap();
-
-        let txouts = graph
-            .list_owned_txouts(&local_chain, local_chain.get_block(110).unwrap())
-            .collect::<Vec<_>>();
-
-        let utxos = graph
-            .list_owned_unspents(&local_chain, local_chain.get_block(110).unwrap())
-            .collect::<Vec<_>>();
-
-        let balance = graph.balance(
-            &local_chain,
-            local_chain.get_block(110).unwrap(),
-            trust_predicate,
-        );
-
-        let confirmed_txouts_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_txout_txid = txouts
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let confirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Confirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        let unconfirmed_utxos_txid = utxos
-            .iter()
-            .filter_map(|full_txout| {
-                if matches!(full_txout.chain_position, ObservedAs::Unconfirmed(_)) {
-                    Some(full_txout.outpoint.txid)
-                } else {
-                    None
-                }
-            })
-            .collect::<BTreeSet<_>>();
-
-        println!("TxOuts : {:#?}", txouts);
-        println!("UTXOS {:#?}", utxos);
-        println!("{:#?}", balance);
-
-        assert_eq!(txouts.len(), 5);
-        assert_eq!(utxos.len(), 4);
+        let (
+            confirmed_txouts_txid,
+            unconfirmed_txouts_txid,
+            confirmed_utxos_txid,
+            unconfirmed_utxos_txid,
+            balance,
+        ) = fetch(98, &graph);
 
         assert_eq!(
             confirmed_txouts_txid,
             [tx1.txid(), tx2.txid(), tx3.txid()].into()
         );
-        assert_eq!(unconfirmed_txout_txid, [tx4.txid(), tx5.txid()].into());
+        assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into());
 
         assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into());
         assert_eq!(unconfirmed_utxos_txid, [tx4.txid(), tx5.txid()].into());
 
+        // Coinbase is still immature
+        assert_eq!(
+            balance,
+            Balance {
+                immature: 70000,          // immature coinbase
+                trusted_pending: 15000,   // tx5
+                untrusted_pending: 20000, // tx4
+                confirmed: 10000          // tx1 got matured
+            }
+        );
+    }
+
+    // AT Block 99
+    {
+        let (_, _, _, _, balance) = fetch(100, &graph);
+
+        // Coinbase maturity hits
         assert_eq!(
             balance,
             Balance {
-                immature: 0,              // immature coinbase
+                immature: 0,              // coinbase matured
                 trusted_pending: 15000,   // tx5
                 untrusted_pending: 20000, // tx4
-                confirmed: 80000          // tx1 got matured
+                confirmed: 80000          // tx1 + tx3
             }
         );
     }