From 4d1a9fd47ab61e1cba2d01fe1191df8c0064c767 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 4 Sep 2023 00:20:45 -0500 Subject: [PATCH 1/5] test(esplora): add async_ext and blocking_ext integration tests --- crates/esplora/Cargo.toml | 4 + crates/esplora/src/async_ext.rs | 4 +- crates/esplora/tests/async_ext.rs | 117 +++++++++++++++++++++++++++ crates/esplora/tests/blocking_ext.rs | 114 ++++++++++++++++++++++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 crates/esplora/tests/async_ext.rs create mode 100644 crates/esplora/tests/blocking_ext.rs diff --git a/crates/esplora/Cargo.toml b/crates/esplora/Cargo.toml index 33c60104a..49af68a99 100644 --- a/crates/esplora/Cargo.toml +++ b/crates/esplora/Cargo.toml @@ -21,6 +21,10 @@ futures = { version = "0.3.26", optional = true } bitcoin = { version = "0.30.0", optional = true, default-features = false } miniscript = { version = "10.0.0", optional = true, default-features = false } +[dev-dependencies] +electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } + [features] default = ["std", "async-https", "blocking"] std = ["bdk_chain/std"] diff --git a/crates/esplora/src/async_ext.rs b/crates/esplora/src/async_ext.rs index a0c3d9d3b..98c47253f 100644 --- a/crates/esplora/src/async_ext.rs +++ b/crates/esplora/src/async_ext.rs @@ -21,8 +21,8 @@ use crate::{anchor_from_status, ASSUME_FINAL_DEPTH}; pub trait EsploraAsyncExt { /// Prepare an [`LocalChain`] update with blocks fetched from Esplora. /// - /// * `prev_tip` is the previous tip of [`LocalChain::tip`]. - /// * `get_heights` is the block heights that we are interested in fetching from Esplora. + /// * `local_tip` is the previous tip of [`LocalChain::tip`]. + /// * `request_heights` is the block heights that we are interested in fetching from Esplora. /// /// The result of this method can be applied to [`LocalChain::apply_update`]. /// diff --git a/crates/esplora/tests/async_ext.rs b/crates/esplora/tests/async_ext.rs new file mode 100644 index 000000000..3b64d7bee --- /dev/null +++ b/crates/esplora/tests/async_ext.rs @@ -0,0 +1,117 @@ +use bdk_esplora::EsploraAsyncExt; +use electrsd::bitcoind::bitcoincore_rpc::RpcApi; +use electrsd::bitcoind::{self, anyhow, BitcoinD}; +use electrsd::{Conf, ElectrsD}; +use esplora_client::{self, AsyncClient, Builder}; +use std::str::FromStr; +use std::thread::sleep; +use std::time::Duration; + +use bdk_chain::bitcoin::{Address, Amount, BlockHash, Txid}; + +struct TestEnv { + bitcoind: BitcoinD, + #[allow(dead_code)] + electrsd: ElectrsD, + client: AsyncClient, +} + +impl TestEnv { + fn new() -> Result { + let bitcoind_exe = + bitcoind::downloaded_exe_path().expect("bitcoind version feature must be enabled"); + let bitcoind = BitcoinD::new(bitcoind_exe).unwrap(); + + let mut electrs_conf = Conf::default(); + electrs_conf.http_enabled = true; + let electrs_exe = + electrsd::downloaded_exe_path().expect("electrs version feature must be enabled"); + let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &electrs_conf)?; + + let base_url = format!("http://{}", &electrsd.esplora_url.clone().unwrap()); + let client = Builder::new(base_url.as_str()).build_async()?; + + Ok(Self { + bitcoind, + electrsd, + client, + }) + } + + fn mine_blocks( + &self, + count: usize, + address: Option
, + ) -> anyhow::Result> { + let coinbase_address = match address { + Some(address) => address, + None => self + .bitcoind + .client + .get_new_address(None, None)? + .assume_checked(), + }; + let block_hashes = self + .bitcoind + .client + .generate_to_address(count as _, &coinbase_address)?; + Ok(block_hashes) + } +} + +#[tokio::test] +pub async fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> { + let env = TestEnv::new()?; + let receive_address0 = + Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm")?.assume_checked(); + let receive_address1 = + Address::from_str("bcrt1qfjg5lv3dvc9az8patec8fjddrs4aqtauadnagr")?.assume_checked(); + + let misc_spks = [ + receive_address0.script_pubkey(), + receive_address1.script_pubkey(), + ]; + + let _block_hashes = env.mine_blocks(101, None)?; + let txid1 = env.bitcoind.client.send_to_address( + &receive_address1, + Amount::from_sat(10000), + None, + None, + None, + None, + Some(1), + None, + )?; + let txid2 = env.bitcoind.client.send_to_address( + &receive_address0, + Amount::from_sat(20000), + None, + None, + None, + None, + Some(1), + None, + )?; + let _block_hashes = env.mine_blocks(1, None)?; + while env.client.get_height().await.unwrap() < 102 { + sleep(Duration::from_millis(10)) + } + + let graph_update = env + .client + .scan_txs( + misc_spks.into_iter(), + vec![].into_iter(), + vec![].into_iter(), + 1, + ) + .await?; + + let mut graph_update_txids: Vec = graph_update.full_txs().map(|tx| tx.txid).collect(); + graph_update_txids.sort(); + let mut expected_txids = vec![txid1, txid2]; + expected_txids.sort(); + assert_eq!(graph_update_txids, expected_txids); + Ok(()) +} diff --git a/crates/esplora/tests/blocking_ext.rs b/crates/esplora/tests/blocking_ext.rs new file mode 100644 index 000000000..6c319945b --- /dev/null +++ b/crates/esplora/tests/blocking_ext.rs @@ -0,0 +1,114 @@ +use bdk_esplora::EsploraExt; +use electrsd::bitcoind::bitcoincore_rpc::RpcApi; +use electrsd::bitcoind::{self, anyhow, BitcoinD}; +use electrsd::{Conf, ElectrsD}; +use esplora_client::{self, BlockingClient, Builder}; +use std::str::FromStr; +use std::thread::sleep; +use std::time::Duration; + +use bdk_chain::bitcoin::{Address, Amount, BlockHash, Txid}; + +struct TestEnv { + bitcoind: BitcoinD, + #[allow(dead_code)] + electrsd: ElectrsD, + client: BlockingClient, +} + +impl TestEnv { + fn new() -> Result { + let bitcoind_exe = + bitcoind::downloaded_exe_path().expect("bitcoind version feature must be enabled"); + let bitcoind = BitcoinD::new(bitcoind_exe).unwrap(); + + let mut electrs_conf = Conf::default(); + electrs_conf.http_enabled = true; + let electrs_exe = + electrsd::downloaded_exe_path().expect("electrs version feature must be enabled"); + let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &electrs_conf)?; + + let base_url = format!("http://{}", &electrsd.esplora_url.clone().unwrap()); + let client = Builder::new(base_url.as_str()).build_blocking()?; + + Ok(Self { + bitcoind, + electrsd, + client, + }) + } + + fn mine_blocks( + &self, + count: usize, + address: Option
, + ) -> anyhow::Result> { + let coinbase_address = match address { + Some(address) => address, + None => self + .bitcoind + .client + .get_new_address(None, None)? + .assume_checked(), + }; + let block_hashes = self + .bitcoind + .client + .generate_to_address(count as _, &coinbase_address)?; + Ok(block_hashes) + } +} + +#[test] +pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> { + let env = TestEnv::new()?; + let receive_address0 = + Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm")?.assume_checked(); + let receive_address1 = + Address::from_str("bcrt1qfjg5lv3dvc9az8patec8fjddrs4aqtauadnagr")?.assume_checked(); + + let misc_spks = [ + receive_address0.script_pubkey(), + receive_address1.script_pubkey(), + ]; + + let _block_hashes = env.mine_blocks(101, None)?; + let txid1 = env.bitcoind.client.send_to_address( + &receive_address1, + Amount::from_sat(10000), + None, + None, + None, + None, + Some(1), + None, + )?; + let txid2 = env.bitcoind.client.send_to_address( + &receive_address0, + Amount::from_sat(20000), + None, + None, + None, + None, + Some(1), + None, + )?; + let _block_hashes = env.mine_blocks(1, None)?; + while env.client.get_height().unwrap() < 102 { + sleep(Duration::from_millis(10)) + } + + let graph_update = env.client.scan_txs( + misc_spks.into_iter(), + vec![].into_iter(), + vec![].into_iter(), + 1, + )?; + + let mut graph_update_txids: Vec = graph_update.full_txs().map(|tx| tx.txid).collect(); + graph_update_txids.sort(); + let mut expected_txids = vec![txid1, txid2]; + expected_txids.sort(); + assert_eq!(graph_update_txids, expected_txids); + Ok(()) +} From 6a5c9d7a00bfddbdf6bd279d003fefe3958dccc1 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 4 Sep 2023 00:25:38 -0500 Subject: [PATCH 2/5] fix(esplora): use saturating_add in update_tx_graph() This fixes overflow error when calling update_tx_graph() from update_tx_graph_without_keychain(). --- crates/esplora/src/async_ext.rs | 2 +- crates/esplora/src/blocking_ext.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/esplora/src/async_ext.rs b/crates/esplora/src/async_ext.rs index 98c47253f..279c8e962 100644 --- a/crates/esplora/src/async_ext.rs +++ b/crates/esplora/src/async_ext.rs @@ -261,7 +261,7 @@ impl EsploraAsyncExt for esplora_client::AsyncClient { } } - if last_index > last_active_index.map(|i| i + stop_gap as u32) { + if last_index > last_active_index.map(|i| i.saturating_add(stop_gap as u32)) { break; } } diff --git a/crates/esplora/src/blocking_ext.rs b/crates/esplora/src/blocking_ext.rs index 5220cf07f..17c364ca9 100644 --- a/crates/esplora/src/blocking_ext.rs +++ b/crates/esplora/src/blocking_ext.rs @@ -252,7 +252,7 @@ impl EsploraExt for esplora_client::BlockingClient { } } - if last_index > last_active_index.map(|i| i + stop_gap as u32) { + if last_index > last_active_index.map(|i| i.saturating_add(stop_gap as u32)) { break; } } From 31d52e12c93469dc6af9a88eba42ad87315dd63b Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 4 Sep 2023 01:01:04 -0500 Subject: [PATCH 3/5] ci: fix msrv dependency versions for rustls-webpki and zip --- .github/workflows/cont_integration.yml | 4 +++- README.md | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 63b9a0b73..082435794 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -38,7 +38,9 @@ jobs: cargo update -p flate2:1.0.27 --precise "1.0.26" cargo update -p reqwest --precise "0.11.18" cargo update -p h2 --precise "0.3.20" - cargo update -p rustls-webpki --precise "0.100.1" + cargo update -p rustls-webpki:0.100.3 --precise "0.100.1" + cargo update -p rustls-webpki:0.101.5 --precise "0.101.1" + cargo update -p zip:0.6.6 --precise "0.6.2" - name: Build run: cargo build ${{ matrix.features }} - name: Test diff --git a/README.md b/README.md index b54a89d00..3969c8ed0 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,12 @@ cargo update -p flate2:1.0.27 --precise "1.0.26" cargo update -p reqwest --precise "0.11.18" # h2 0.3.21 has MSRV 1.63.0+ cargo update -p h2 --precise "0.3.20" -# rustls-webpki has MSRV 1.60.0+ -cargo update -p rustls-webpki --precise "0.100.1" +# rustls-webpki 0.100.2 has MSRV 1.60.0+ +cargo update -p rustls-webpki:0.100.3 --precise "0.100.1" +# rustls-webpki 0.101.2 has MSRV 1.60.0+ +cargo update -p rustls-webpki:0.101.5 --precise "0.101.1" +# zip 0.6.3 has MSRV 1.59.0+ +cargo update -p zip:0.6.6 --precise "0.6.2" ``` ## License From d35668e76aa3ba429041305e54106c10429a8b1b Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 14 Sep 2023 14:39:20 -0500 Subject: [PATCH 4/5] ci(esplora): fix wasm cargo check by setting workspace resolver to version 2 The resolver version must be set at the workspace level. See: https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#cargos-new-feature-resolver --- Cargo.toml | 1 + crates/esplora/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e818d8996..b20ef222d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "crates/bdk", "crates/chain", diff --git a/crates/esplora/Cargo.toml b/crates/esplora/Cargo.toml index 49af68a99..0fffeda68 100644 --- a/crates/esplora/Cargo.toml +++ b/crates/esplora/Cargo.toml @@ -21,7 +21,7 @@ futures = { version = "0.3.26", optional = true } bitcoin = { version = "0.30.0", optional = true, default-features = false } miniscript = { version = "10.0.0", optional = true, default-features = false } -[dev-dependencies] +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } From bf9a4258496ef91bec4d15126d6e98a2450533ea Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 25 Sep 2023 21:08:52 -0500 Subject: [PATCH 5/5] ci: fix MSRV build by pinning tokio-util to 0.7.8 --- .github/workflows/cont_integration.yml | 3 ++- README.md | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 082435794..e8e47fd63 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -35,11 +35,12 @@ jobs: cargo update -p rustls:0.21.7 --precise "0.21.1" cargo update -p rustls:0.20.9 --precise "0.20.8" cargo update -p tokio:1.32.0 --precise "1.29.1" + cargo update -p tokio-util --precise "0.7.8" cargo update -p flate2:1.0.27 --precise "1.0.26" cargo update -p reqwest --precise "0.11.18" cargo update -p h2 --precise "0.3.20" cargo update -p rustls-webpki:0.100.3 --precise "0.100.1" - cargo update -p rustls-webpki:0.101.5 --precise "0.101.1" + cargo update -p rustls-webpki:0.101.6 --precise "0.101.1" cargo update -p zip:0.6.6 --precise "0.6.2" - name: Build run: cargo build ${{ matrix.features }} diff --git a/README.md b/README.md index 3969c8ed0..d3c56f166 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,8 @@ cargo update -p rustls:0.21.7 --precise "0.21.1" cargo update -p rustls:0.20.9 --precise "0.20.8" # tokio 1.30 has MSRV 1.63.0+ cargo update -p tokio:1.32.0 --precise "1.29.1" +# tokio-util 0.7.9 doesn't build with MSRV 1.57.0 +cargo update -p tokio-util --precise "0.7.8" # flate2 1.0.27 has MSRV 1.63.0+ cargo update -p flate2:1.0.27 --precise "1.0.26" # reqwest 0.11.19 has MSRV 1.63.0+ @@ -84,7 +86,7 @@ cargo update -p h2 --precise "0.3.20" # rustls-webpki 0.100.2 has MSRV 1.60.0+ cargo update -p rustls-webpki:0.100.3 --precise "0.100.1" # rustls-webpki 0.101.2 has MSRV 1.60.0+ -cargo update -p rustls-webpki:0.101.5 --precise "0.101.1" +cargo update -p rustls-webpki:0.101.6 --precise "0.101.1" # zip 0.6.3 has MSRV 1.59.0+ cargo update -p zip:0.6.6 --precise "0.6.2" ```