]> Untitled Git - bdk/commitdiff
esplora: also test the gap limit bounds in the async client
authorAntoine Poinsot <darosior@protonmail.com>
Mon, 20 Nov 2023 11:00:50 +0000 (12:00 +0100)
committerAntoine Poinsot <darosior@protonmail.com>
Fri, 24 Nov 2023 11:21:16 +0000 (12:21 +0100)
crates/esplora/tests/async_ext.rs

index 3b64d7beea2c0f9b9cf5ffb0abc26e5c505103ce..38833f588ecc7846c5d55b4a94bfe6e1a4f7cca9 100644 (file)
@@ -3,6 +3,7 @@ use electrsd::bitcoind::bitcoincore_rpc::RpcApi;
 use electrsd::bitcoind::{self, anyhow, BitcoinD};
 use electrsd::{Conf, ElectrsD};
 use esplora_client::{self, AsyncClient, Builder};
+use std::collections::{BTreeMap, HashSet};
 use std::str::FromStr;
 use std::thread::sleep;
 use std::time::Duration;
@@ -115,3 +116,121 @@ pub async fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
     assert_eq!(graph_update_txids, expected_txids);
     Ok(())
 }
+
+/// Test the bounds of the address scan depending on the gap limit.
+#[tokio::test]
+pub async fn test_async_update_tx_graph_gap_limit() -> anyhow::Result<()> {
+    let env = TestEnv::new()?;
+    let _block_hashes = env.mine_blocks(101, None)?;
+
+    // Now let's test the gap limit. First of all get a chain of 10 addresses.
+    let addresses = [
+        "bcrt1qj9f7r8r3p2y0sqf4r3r62qysmkuh0fzep473d2ar7rcz64wqvhssjgf0z4",
+        "bcrt1qmm5t0ch7vh2hryx9ctq3mswexcugqe4atkpkl2tetm8merqkthas3w7q30",
+        "bcrt1qut9p7ej7l7lhyvekj28xknn8gnugtym4d5qvnp5shrsr4nksmfqsmyn87g",
+        "bcrt1qqz0xtn3m235p2k96f5wa2dqukg6shxn9n3txe8arlrhjh5p744hsd957ww",
+        "bcrt1q9c0t62a8l6wfytmf2t9lfj35avadk3mm8g4p3l84tp6rl66m48sqrme7wu",
+        "bcrt1qkmh8yrk2v47cklt8dytk8f3ammcwa4q7dzattedzfhqzvfwwgyzsg59zrh",
+        "bcrt1qvgrsrzy07gjkkfr5luplt0azxtfwmwq5t62gum5jr7zwcvep2acs8hhnp2",
+        "bcrt1qw57edarcg50ansq8mk3guyrk78rk0fwvrds5xvqeupteu848zayq549av8",
+        "bcrt1qvtve5ekf6e5kzs68knvnt2phfw6a0yjqrlgat392m6zt9jsvyxhqfx67ef",
+        "bcrt1qw03ddumfs9z0kcu76ln7jrjfdwam20qtffmkcral3qtza90sp9kqm787uk",
+    ];
+    let addresses: Vec<_> = addresses
+        .into_iter()
+        .map(|s| Address::from_str(s).unwrap().assume_checked())
+        .collect();
+    let spks: Vec<_> = addresses
+        .iter()
+        .enumerate()
+        .map(|(i, addr)| (i as u32, addr.script_pubkey()))
+        .collect();
+    let mut keychains = BTreeMap::new();
+    keychains.insert(0, spks);
+
+    // Then receive coins on the 4th address.
+    let txid_4th_addr = env.bitcoind.client.send_to_address(
+        &addresses[3],
+        Amount::from_sat(10000),
+        None,
+        None,
+        None,
+        None,
+        Some(1),
+        None,
+    )?;
+    let _block_hashes = env.mine_blocks(1, None)?;
+    while env.client.get_height().await.unwrap() < 103 {
+        sleep(Duration::from_millis(10))
+    }
+
+    // A scan with a gap limit of 2 won't find the transaction, but a scan with a gap limit of 3
+    // will.
+    let (graph_update, active_indices) = env
+        .client
+        .scan_txs_with_keychains(
+            keychains.clone(),
+            vec![].into_iter(),
+            vec![].into_iter(),
+            2,
+            1,
+        )
+        .await?;
+    assert!(graph_update.full_txs().next().is_none());
+    assert!(active_indices.is_empty());
+    let (graph_update, active_indices) = env
+        .client
+        .scan_txs_with_keychains(
+            keychains.clone(),
+            vec![].into_iter(),
+            vec![].into_iter(),
+            3,
+            1,
+        )
+        .await?;
+    assert_eq!(graph_update.full_txs().next().unwrap().txid, txid_4th_addr);
+    assert_eq!(active_indices[&0], 3);
+
+    // Now receive a coin on the last address.
+    let txid_last_addr = env.bitcoind.client.send_to_address(
+        &addresses[addresses.len() - 1],
+        Amount::from_sat(10000),
+        None,
+        None,
+        None,
+        None,
+        Some(1),
+        None,
+    )?;
+    let _block_hashes = env.mine_blocks(1, None)?;
+    while env.client.get_height().await.unwrap() < 104 {
+        sleep(Duration::from_millis(10))
+    }
+
+    // A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will.
+    // The last active indice won't be updated in the first case but will in the second one.
+    let (graph_update, active_indices) = env
+        .client
+        .scan_txs_with_keychains(
+            keychains.clone(),
+            vec![].into_iter(),
+            vec![].into_iter(),
+            4,
+            1,
+        )
+        .await?;
+    let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
+    assert_eq!(txs.len(), 1);
+    assert!(txs.contains(&txid_4th_addr));
+    assert_eq!(active_indices[&0], 3);
+    let (graph_update, active_indices) = env
+        .client
+        .scan_txs_with_keychains(keychains, vec![].into_iter(), vec![].into_iter(), 5, 1)
+        .await?;
+    let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
+    assert_eq!(txs.len(), 2);
+    assert!(txs.contains(&txid_4th_addr) && txs.contains(&txid_last_addr));
+    assert_eq!(active_indices[&0], 9);
+
+    Ok(())
+}