From 0c5ad08d2c49fab7fab8e3b42b20e32b1ff8575f Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:04:51 -0300 Subject: [PATCH 01/31] fix(cli): quote TRAP triggered command Fix the trap command in the `cli/justfile` by quoting the "just stop" command. This ensures the entire command is passed as a string to the trap, preventing it from being split into separate arguments which could cause the trap to malfunction when signals are received. --- cli/justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/justfile b/cli/justfile index c51a1b7..907ea74 100644 --- a/cli/justfile +++ b/cli/justfile @@ -180,7 +180,7 @@ start STATE="persistent": short_date=$(/bin/date +%m%d%y) exec {BASH_XTRACEFD}>>"$DEBUG_PREFIX.$short_date".log set -euxo pipefail - trap just stop SIGHUP SIGINT SIGQUIT SIGTERM + trap "just stop" SIGHUP SIGINT SIGQUIT SIGTERM just startcontainer ENVDIR="/root/env" From aa8accd53535131d4311a49c15142774aa1b2a07 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:05:28 -0300 Subject: [PATCH 02/31] fix(cli): pass empty bitcoin.conf to bitcoin-cli for instance isolation Pass an empty configuration file to bitcoin-cli to prevent it from automatically loading any system-wide bitcoin.conf file. This ensures that multiple bitcoind instances running on the same system remain isolated from each other, avoiding configuration conflicts. The commit also explicitly specifies connection parameters (-rpcconnect and -rpcport) to ensure proper connection to the intended regtest instance. --- cli/justfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/justfile b/cli/justfile index 907ea74..8e625b7 100644 --- a/cli/justfile +++ b/cli/justfile @@ -274,7 +274,8 @@ cli COMMAND *ARGS: short_date=$(/bin/date +%m%d%y) exec {BASH_XTRACEFD}>>"$DEBUG_PREFIX.$short_date".log set -euxo pipefail - bitcoin-cli --chain=regtest --rpcuser=__cookie__ --rpcpassword=$(just cookie) {{COMMAND}} {{ARGS}} + touch /tmp/empty.conf + bitcoin-cli --conf=/tmp/empty.conf -rpcconnect=127.0.0.1 -rpcport=18443 --chain=regtest --rpcuser=__cookie__ --rpcpassword=$(just cookie) {{COMMAND}} {{ARGS}} [group("Logs")] [doc("Print all logs to console.")] From 7b81c8dcf439595b5a7a2c7aeb8ba4f4df7b2310 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:47:19 -0300 Subject: [PATCH 03/31] refactor(cli): update transaction parameters with DrainWeights Update the CLI to use the new SelectorParams API with DrainWeights. This replaces the previous ChangeDescriptor::Manual approach with separate parameters for change script and weight information, providing a more flexible and explicit way to define transaction parameters for coin selection. --- cli/v2/src/main.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 79be51f..d8238d5 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -3,6 +3,7 @@ use bdk_bitcoind_rpc::{ bitcoincore_rpc::{Auth, Client, RpcApi}, Emitter, NO_EXPECTED_MEMPOOL_TXIDS, }; +use bdk_coin_select::DrainWeights; use bdk_file_store::Store; use bdk_sp::{ bitcoin::{ @@ -607,11 +608,22 @@ async fn main() -> anyhow::Result<()> { SelectorParams::new( FeeRate::from_sat_per_vb_unchecked(fee_rate), outputs, - bdk_tx::ChangeDescriptor::Manual { - script_pubkey: wallet.get_change_address().get_placeholder_p2tr_spk(), - max_weight_to_satisfy_wu: SpWallet::DEFAULT_SPENDING_WEIGHT, - }, + bdk_tx::ScriptSource::from_script( + wallet.get_change_address().get_placeholder_p2tr_spk(), + ), bdk_tx::ChangePolicyType::NoDustAndLeastWaste { longterm_feerate }, + DrainWeights { + output_weight: TxOut { + script_pubkey: wallet + .get_change_address() + .get_placeholder_p2tr_spk(), + value: Amount::ZERO, + } + .weight() + .to_wu(), + spend_weight: SpWallet::DEFAULT_SPENDING_WEIGHT, + n_outputs: 1, + }, ), )?; From 4bd6c133e092529c8a56b399f89038aa7ed98475 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:01:41 +0200 Subject: [PATCH 04/31] fix(indexer): apply filter to all transactions in apply_block_with_filter The commit fixes a logic issue in the `apply_block_with_filter` function where the filter was only applied to transactions that had partial secrets. This bug ruled out the indexing of changeless transactions spending silent payment outputs owned by the wallet, but sending funds to non taproot addresses. Those transacions have available inputs for shared secret derivation according to BIP 352 (the silent payment output spend by this transactions is a valid P2TR key path spend), but there aren't any P2TR outputs on them, so any implementation using tweaks as proxy to decide which transactions to scan, are going to miss these transactions. Now the filter is applied to all transactions regardless of whether they have partial secrets, ensuring that all transactions meeting the filter criteria are properly indexed in the graph. --- indexer/src/v2/mod.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/indexer/src/v2/mod.rs b/indexer/src/v2/mod.rs index f4e21a7..aead6f6 100644 --- a/indexer/src/v2/mod.rs +++ b/indexer/src/v2/mod.rs @@ -333,20 +333,22 @@ where let mut changeset = ChangeSet::::default(); for (tx_pos, tx) in block.txdata.iter().enumerate().skip(1) { let txid = tx.compute_txid(); + if let Some(partial_secret) = partial_secrets.get(&txid) { changeset.merge(self.index_tx(tx, partial_secret)); - if filter(self, tx) { - let anchor = TxPosInBlock { - block, - block_id, - tx_pos, - } - .into(); - changeset.graph.merge(self.graph.insert_tx(tx.clone())); - changeset - .graph - .merge(self.graph.insert_anchor(txid, anchor)); + } + + if filter(self, tx) { + let anchor = TxPosInBlock { + block, + block_id, + tx_pos, } + .into(); + changeset.graph.merge(self.graph.insert_tx(tx.clone())); + changeset + .graph + .merge(self.graph.insert_anchor(txid, anchor)); } } changeset From e17d1f81e4bd3756b4d3038f6beece459162459d Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:03:24 +0200 Subject: [PATCH 05/31] feat(wallet): add method to retrieve the unspent script pubkeys This functionality is needed to allow sp wallets to identify which indexed script public keys have not been spent in transactions, enabling better tracking and management of wallet transaction history. --- wallet/src/lib.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 932b9bd..9fdba1d 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -6,7 +6,7 @@ //! transaction building, and [`indexer`] for blockchain data management. use bdk_sp::{ bitcoin::{ - Block, Transaction, Txid, + Block, ScriptBuf, Transaction, Txid, absolute::{self, Height, LockTime, Time}, secp256k1, }, @@ -212,6 +212,36 @@ impl SpWallet { }) } + pub fn unspent_spks(&self) -> Vec<[u8; 34]> { + let mut unspent_spks = Vec::::new(); + for (_, txout) in self + .graph() + .try_filter_chain_unspents( + self.chain(), + self.chain().tip().block_id(), + CanonicalizationParams::default(), + self.indexer() + .index() + .by_xonly() + .map(|(xonly, outpoint)| (xonly, *outpoint)), + ) + .unwrap() + { + unspent_spks.push(txout.txout.script_pubkey); + } + + let spk_bytes: Vec<[u8; 34]> = unspent_spks + .into_iter() + .map(|spk| { + spk.into_bytes() + .try_into() + .expect("all spks should be p2tr scripts which have 34 bytes") + }) + .collect(); + + spk_bytes + } + /// Returns an iterator over the canonical transactions in the wallet. /// /// Canonical transactions are those that are confirmed or those unconfirmed thad doesn't From c8238330f2185d3acd149a3be68c73353026d52c Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:20:01 +0200 Subject: [PATCH 06/31] fix(oracles): match against unspent script pubkeys in BlindbitSubscriber Updates the BlindbitSubscriber to accept unspent script pubkeys and includes them in the filter matching process. This ensures the subscriber can properly detect matches against unspent outputs, not just all script pubkeys. Previously, the code was only checking against the script pubkeys extracted from a collection, potentially missing relevant matches from unspent outputs in the wallet. --- cli/v2/src/main.rs | 1 + oracles/src/tweaks/blindbit.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index d8238d5..5d83626 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -349,6 +349,7 @@ async fn main() -> anyhow::Result<()> { } = client; let (mut blindbit_subscriber, db_buffer) = BlindbitSubscriber::new( + wallet.unspent_spks(), wallet.indexer().clone(), tweak_server_url, wallet.network(), diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index 4052c1c..791cafb 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -125,6 +125,7 @@ pub enum TweakEvent { pub struct BlindbitSubscriber { db: Arc>, + unspent_script_pubkeys: Vec<[u8; 34]>, indexer: SpIndexer, client: BlindbitClient, requests: UnboundedReceiver, @@ -133,6 +134,7 @@ pub struct BlindbitSubscriber { impl BlindbitSubscriber { pub fn new( + unspent_script_pubkeys: Vec<[u8; 34]>, indexer: SpIndexer, host_url: String, network: Network, @@ -146,6 +148,7 @@ impl BlindbitSubscriber { Ok(( Self { db, + unspent_script_pubkeys, indexer, client: BlindbitClient::new(host_url, network)?, requests, @@ -211,7 +214,8 @@ impl BlindbitSubscriber { }) .collect::>(); - let only_spks: Vec<[u8; 34]> = all_spks.clone().into_keys().collect(); + let mut only_spks: Vec<[u8; 34]> = all_spks.clone().into_keys().collect(); + only_spks.extend_from_slice(&self.unspent_script_pubkeys); if !all_spks.is_empty() && filter.match_any(&hash, only_spks.into_iter()).unwrap() { tracing::info!("Match found for block {hash} at height {height}"); From 257d78f29048a18962f6ccb27ba9e7f7804f5b5a Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:37:57 +0200 Subject: [PATCH 07/31] feat(cli): add height optional parameter for scan-cbf command Adds an optional `height` parameter to the `scan-cbf` command that allows specifying a custom height for the scan operation. When provided, this value is used directly as the sync height. When not provided, the sync height defaults to either the chain tip height or the wallet birthday height, maintaining the previous behavior. This change enables users to scan at specific blockchain heights on demand. --- cli/v2/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 5d83626..e225f5f 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -154,6 +154,7 @@ pub enum Commands { }, ScanCbf { tweak_server_url: String, + height: Option, }, Create { /// Network @@ -284,7 +285,10 @@ async fn main() -> anyhow::Result<()> { println!("{}", serde_json::to_string_pretty(&obj)?); } } - Commands::ScanCbf { tweak_server_url } => { + Commands::ScanCbf { + tweak_server_url, + height: maybe_height, + } => { async fn trace( mut log_rx: kyoto::Receiver, mut info_rx: kyoto::Receiver, @@ -313,7 +317,9 @@ async fn main() -> anyhow::Result<()> { tracing::info!("Wallet main SP address: {}", wallet.get_address()); - let sync_height = if wallet.birthday <= wallet.chain().tip().height() { + let sync_height = if let Some(height) = maybe_height { + height + } else if wallet.birthday <= wallet.chain().tip().height() { wallet.chain().tip().height() } else { wallet.birthday From 3a1a925eefe1a5ac5c39d6ce02154a185f1edf17 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:22:17 +0200 Subject: [PATCH 08/31] build(cli): update Cargo.lock for cli This lockfile ensures consistent and reproducible builds for the sp-cli2 tool. --- Cargo.lock | 3136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3136 insertions(+) create mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2699a70 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3136 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "afl" +version = "0.12.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c32f2f36624ffe2a8f65f9d76c224846b3a3d7242485bb5927c1127ee6c715" +dependencies = [ + "clap", + "fs_extra", + "home", + "libc", + "rustc_version", + "tempfile", + "xdg", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.0", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bdk_bitcoind_rpc" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f96e987f8736f34c1628743684f66b31faeda72f3bc86b60314197f2d8cb9731" +dependencies = [ + "bdk_core 0.4.1", + "bitcoin", + "bitcoincore-rpc", +] + +[[package]] +name = "bdk_bitcoind_rpc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21c422408ac8720da9d9a3048a32f4a3fdd18e6c82b0fa3b620d92b1ef73df52" +dependencies = [ + "bdk_core 0.6.2", + "bitcoin", + "bitcoincore-rpc", +] + +[[package]] +name = "bdk_chain" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4955734f97b2baed3f36d16ae7c203fdde31ae85391ac44ee3cbcaf0886db5ce" +dependencies = [ + "bdk_core 0.4.1", + "bitcoin", + "miniscript", +] + +[[package]] +name = "bdk_chain" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5d691fd092aacec7e05046b7d04897d58d6d65ed3152cb6cf65dababcfabed" +dependencies = [ + "bdk_core 0.6.2", + "bitcoin", + "miniscript", + "serde", +] + +[[package]] +name = "bdk_coin_select" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43064fa3dd1d3a8b24079cfcb5ede6b785857edc782277f17a1736511ccc1916" + +[[package]] +name = "bdk_core" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b545aea1efc090e4f71f1dd5468090d9f54c3de48002064c04895ef811fbe0b2" +dependencies = [ + "bitcoin", +] + +[[package]] +name = "bdk_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dbbe4aad0c898bfeb5253c222be3ea3dccfb380a07e72c87e3e4ed6664a6753" +dependencies = [ + "bitcoin", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "bdk_file_store" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446f02da319941ea78454a479fca72707f3355a62db3bb1c2c13b94e7f963ce0" +dependencies = [ + "bdk_core 0.6.2", + "bincode", + "serde", +] + +[[package]] +name = "bdk_sp" +version = "0.1.0" +dependencies = [ + "anyhow", + "bdk_sp", + "bdk_testenv", + "bitcoin", + "miniscript", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "bdk_sp_cli_v1" +version = "0.1.0" +dependencies = [ + "anyhow", + "bdk_bitcoind_rpc 0.20.0", + "bdk_chain 0.23.2", + "bdk_coin_select", + "bdk_file_store", + "bdk_sp", + "bitcoin", + "clap", + "indexer", + "miniscript", + "rand 0.9.2", + "serde", + "serde_json", +] + +[[package]] +name = "bdk_sp_cli_v2" +version = "0.1.0" +dependencies = [ + "anyhow", + "bdk_bitcoind_rpc 0.20.0", + "bdk_coin_select", + "bdk_file_store", + "bdk_sp", + "bdk_sp_oracles", + "bdk_sp_wallet", + "clap", + "indexer", + "miniscript", + "rand 0.9.2", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "bdk_sp_oracles" +version = "0.1.0" +dependencies = [ + "bitcoin", + "futures", + "indexer", + "kyoto-cbf", + "rayon", + "redb", + "reqwest", + "serde", + "serde_json", + "tracing", + "url", +] + +[[package]] +name = "bdk_sp_wallet" +version = "0.1.0" +dependencies = [ + "bdk_sp", + "bdk_tx", + "indexer", + "serde", +] + +[[package]] +name = "bdk_testenv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29317cb8181a5ea2ba73c0276a3122d9af0c839a57102f95ba27bd472daed9b5" +dependencies = [ + "bdk_chain 0.21.1", + "electrsd", +] + +[[package]] +name = "bdk_tx" +version = "0.1.0" +source = "git+https://github.com/nymius/bdk-tx?branch=feat/add-ChangeDescriptor-enum#bcb018f61ff2f38e0b48aa1e19810b47831130a1" +dependencies = [ + "bdk_coin_select", + "miniscript", +] + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bip324" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53157fcb2d6ec2851c7602d0690536d0b79209e393972cb2b36bd5d72dbd1879" +dependencies = [ + "bitcoin", + "bitcoin_hashes 0.15.0", + "chacha20-poly1305", + "rand 0.8.5", + "tokio", +] + +[[package]] +name = "bitcoin" +version = "0.32.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" +dependencies = [ + "base58ck", + "base64 0.21.7", + "bech32", + "bitcoin-internals 0.3.0", + "bitcoin-io 0.1.3", + "bitcoin-units", + "bitcoin_hashes 0.14.0", + "hex-conservative 0.2.1", + "hex_lit", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b854212e29b96c8f0fe04cab11d57586c8f3257de0d146c76cb3b42b3eb9118" + +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26792cd2bf245069a1c5acb06aa7ad7abe1de69b507c90b490bca81e0665d0ee" +dependencies = [ + "bitcoin-internals 0.4.0", +] + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io 0.1.3", + "hex-conservative 0.2.1", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0982261c82a50d89d1a411602afee0498b3e0debe3d36693f0c661352809639" +dependencies = [ + "bitcoin-io 0.2.0", + "hex-conservative 0.3.0", +] + +[[package]] +name = "bitcoincore-rpc" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee" +dependencies = [ + "bitcoincore-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoind" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce6620b7c942dbe28cc49c21d95e792feb9ffd95a093205e7875ccfa69c2925" +dependencies = [ + "anyhow", + "bitcoin_hashes 0.14.0", + "bitcoincore-rpc", + "flate2", + "log", + "minreq", + "tar", + "tempfile", + "which", + "zip", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20-poly1305" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4b0fc281743d80256607bd65e8beedc42cb0787ea119c85b81b4c0eab85e5f" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[package]] +name = "deranged" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dleq" +version = "0.1.0" +dependencies = [ + "bitcoin", + "csv", + "dleq", + "once_cell", + "serde", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "electrsd" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c3c57645202a05a47206ed81cc179cf32bf4c3ca5a9e60c06c49d0222d5844" +dependencies = [ + "bitcoin_hashes 0.14.0", + "bitcoind", + "electrum-client", + "log", + "minreq", + "nix", + "which", + "zip", +] + +[[package]] +name = "electrum-client" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7b1f8783238bb18e6e137875b0a66f3dffe6c7ea84066e05d033cf180b150f" +dependencies = [ + "bitcoin", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-conservative" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "honggfuzz" +version = "0.5.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc563d4f41b17364d5c48ded509f2bcf1c3f6ae9c7f203055b4a5c325072d57e" +dependencies = [ + "lazy_static", + "memmap2", + "rustc_version", + "semver", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls 0.23.31", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.2", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexer" +version = "0.1.0" +dependencies = [ + "bdk_bitcoind_rpc 0.18.0", + "bdk_chain 0.23.2", + "bdk_sp", + "bitcoin", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" +dependencies = [ + "equivalent", + "hashbrown 0.15.5", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf" +dependencies = [ + "base64 0.13.1", + "minreq", + "serde", + "serde_json", +] + +[[package]] +name = "kyoto-cbf" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805f16bcf1d4738529f230404e7d0ab6e9ecf9e265920c212d446a291a93297e" +dependencies = [ + "bip324", + "bitcoin", + "rusqlite", + "tokio", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniscript" +version = "12.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" +dependencies = [ + "bech32", + "bitcoin", + "serde", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "minreq" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" +dependencies = [ + "rustls 0.21.12", + "rustls-webpki 0.101.7", + "serde", + "serde_json", + "webpki-roots 0.25.4", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.31", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls 0.23.31", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redb" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eca1e9d98d5a7e9002d0013e18d5a9b000aee942eb134883a82f06ebffb6c01" +dependencies = [ + "libc", +] + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.31", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusqlite" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" +dependencies = [ + "bitflags 2.9.4", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.6", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "sp_fuzz" +version = "0.1.0" +dependencies = [ + "afl", + "bdk_sp", + "honggfuzz", + "libfuzzer-sys", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.61.0", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.31", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.4", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link 0.1.3", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "xattr" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" +dependencies = [ + "libc", + "rustix 1.1.2", +] + +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] From 6d5eb0557d5b8e78f92486fea8426201b283bdb5 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 4 Sep 2025 10:11:31 -0300 Subject: [PATCH 09/31] build: add --workspace flag to build recipe Add the `--workspace` flag to the build recipe in the justfile to ensure all packages in the workspace are built when running `just build`. This makes the build command more consistent with the intended behavior, which is to build the entire project workspace except for the excluded `sp_fuzz` package. --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index b27fb38..0386765 100644 --- a/justfile +++ b/justfile @@ -10,7 +10,7 @@ default: [doc("Build the project")] build: - cargo build --exclude sp_fuzz + cargo build --workspace --exclude sp_fuzz [doc("Check code: formatting, compilation, linting, and commit signature")] check: From 9d2ffa6866a25ec1e92cb3507c7079756851b18c Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:19:54 -0300 Subject: [PATCH 10/31] refactor(cli): read DB_PATH from environment if possible Allow setting the database path through the DB_PATH environment variable. If the variable is not set, the application falls back to the default path ".bdk_example_silentpayments.db". This change makes the database location configurable without requiring code changes allowing the use of multiple database paths for different sp-cli2 wallets. --- cli/v2/src/main.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index e225f5f..9fdfe81 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -50,6 +50,7 @@ use rand::RngCore; use serde_json::json; use std::{ collections::{HashMap, HashSet}, + env, net::{IpAddr, Ipv4Addr}, str::FromStr, sync::Mutex, @@ -57,7 +58,6 @@ use std::{ }; const DB_MAGIC: &[u8] = b"bdk_example_silentpayments"; -const DB_PATH: &str = ".bdk_example_silentpayments.db"; /// Delay for printing status to stdout. const STDOUT_PRINT_DELAY: Duration = Duration::from_secs(6); @@ -208,11 +208,17 @@ async fn main() -> anyhow::Result<()> { let subscriber = tracing_subscriber::FmtSubscriber::new(); tracing::subscriber::set_global_default(subscriber).unwrap(); + let db_path = if let Ok(db_path) = env::var("DB_PATH") { + db_path + } else { + ".bdk_example_silentpayments.db".to_string() + }; + let Init { args, mut wallet, db, - } = match init_or_load(DB_MAGIC, DB_PATH)? { + } = match init_or_load(DB_MAGIC, &db_path)? { Some(init) => init, None => return Ok(()), }; @@ -732,7 +738,7 @@ pub fn init_or_load(db_magic: &[u8], db_path: &str) -> anyhow::Result::create(DB_MAGIC, DB_PATH)?; + let mut db = Store::::create(db_magic, db_path)?; if let Some(stage) = wallet.staged() { db.append(stage).unwrap(); } From 6bda0a59277a42819645435baafdf4bf27f0a1f1 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:40:35 +0200 Subject: [PATCH 11/31] fix(oracles): do not error on bad blindbit requests Modify the BlindbitSubscriber to continue processing when a request for tweaks fails, instead of crashing with an unwrap(). This ensures that temporary failures in tweak requests don't halt the entire subscriber process. --- oracles/src/tweaks/blindbit.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index 791cafb..6af04fe 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -188,15 +188,18 @@ impl BlindbitSubscriber { .map(move |(height, hash)| { let client = client.clone(); async move { - let tweaks = client.tweaks(height, Amount::from_sat(1000)).await.unwrap(); - (height, hash, tweaks) + if let Ok(tweaks) = client.tweaks(height, Amount::from_sat(1000)).await { + Some((height, hash, tweaks)) + } else { + None + } } }) .buffer_unordered(200); let read = self.db.lock().unwrap().begin_read().unwrap(); let table = read.open_table(TABLE_DEF).unwrap(); - while let Some((height, hash, tweaks)) = stream.next().await { + while let Some((height, hash, tweaks)) = stream.next().await.flatten() { tracing::info!("Tweaks {progress}/{base}"); progress += 1; From 8ea3fcfe1b4b02e5b66d63847b5015fc76c2f3b6 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:50:36 +0200 Subject: [PATCH 12/31] feat(cli): add scan-cbf for regtest environment Add support for regtest environment in scan-cbf CLI command by implementing network-specific peer configuration. This enables testing and development in regtest environments where local Bitcoin nodes are used instead of remote peers. --- cli/v2/src/main.rs | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 9fdfe81..524f28f 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -336,19 +336,38 @@ async fn main() -> anyhow::Result<()> { // Set up the light client let checkpoint = HeaderCheckpoint::closest_checkpoint_below_height(sync_height, wallet.network()); - let peer_1 = IpAddr::V4(Ipv4Addr::new(95, 217, 198, 121)); - let peer_2 = TrustedPeer::new( - AddrV2::Ipv4(Ipv4Addr::new(23, 137, 57, 100)), - None, - ServiceFlags::P2P_V2, - ); - let builder = NodeBuilder::new(wallet.network()); - let (node, client) = builder - .after_checkpoint(checkpoint) - .add_peers(vec![(peer_1, None).into(), peer_2]) - .required_peers(2) - .build() - .unwrap(); + let (node, client) = match wallet.network() { + Network::Regtest => { + let peer = TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)), + None, + ServiceFlags::P2P_V2, + ); + let builder = NodeBuilder::new(wallet.network()); + builder + .after_checkpoint(checkpoint) + .add_peer(peer) + .required_peers(1) + .build() + .unwrap() + } + Network::Signet => { + let peer_1 = IpAddr::V4(Ipv4Addr::new(95, 217, 198, 121)); + let peer_2 = TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::new(23, 137, 57, 100)), + None, + ServiceFlags::P2P_V2, + ); + let builder = NodeBuilder::new(wallet.network()); + builder + .after_checkpoint(checkpoint) + .add_peers(vec![(peer_1, None).into(), peer_2]) + .required_peers(2) + .build() + .unwrap() + } + _ => unimplemented!("Not mainnet nor testnet environments"), + }; let (changes_tx, changes_rx) = tokio::sync::mpsc::unbounded_channel::(); let (matches_tx, mut matches_rx) = tokio::sync::mpsc::unbounded_channel::(); From 92665dd8d52a5175fbb3993540e33122c52004cf Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Wed, 17 Sep 2025 09:49:05 +0200 Subject: [PATCH 13/31] fix(oracles): remove network parametrization from BlindbitClient Removes the network parameter from BlindbitClient's constructor and its usage in the URL path construction. This simplifies the client implementation by removing unnecessary network-specific URL path modification, as the service endpoint should handle network differentiation on its own rather than through URL paths. --- cli/v2/src/main.rs | 1 - oracles/src/tweaks/blindbit.rs | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 524f28f..18839e7 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -383,7 +383,6 @@ async fn main() -> anyhow::Result<()> { wallet.unspent_spks(), wallet.indexer().clone(), tweak_server_url, - wallet.network(), changes_rx, matches_tx, ) diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index 6af04fe..8d8cd2c 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -64,7 +64,7 @@ pub struct BlindbitClient { } impl BlindbitClient { - pub fn new(host_url: String, network: Network) -> Result { + pub fn new(host_url: String) -> Result { let mut host_url = Url::parse(&host_url)?; let client = Client::new(); @@ -73,8 +73,6 @@ impl BlindbitClient { host_url.set_path(&format!("{}/", host_url.path())); } - host_url.set_path(&format!("{}{}/", host_url.path(), network)); - tracing::info!("Subscribing to tweak server {}", host_url); Ok(BlindbitClient { host_url, client }) @@ -137,7 +135,6 @@ impl BlindbitSubscriber { unspent_script_pubkeys: Vec<[u8; 34]>, indexer: SpIndexer, host_url: String, - network: Network, requests: UnboundedReceiver, sender: UnboundedSender, ) -> Result<(Self, DatabaseBuffer), BlindbitError> { @@ -150,7 +147,7 @@ impl BlindbitSubscriber { db, unspent_script_pubkeys, indexer, - client: BlindbitClient::new(host_url, network)?, + client: BlindbitClient::new(host_url)?, requests, sender, }, From 93b1f3b8105757b1e750c85b750084bddf5fe236 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:43:47 +0200 Subject: [PATCH 14/31] fix(cli): apply blocks even with empty partial secrets in scan-cbf Ensures blocks are indexed even when no partial secrets are found (i.e., when the block contains no p2tr outputs). Previously, blocks without partial secrets were skipped, potentially missing relevant transactions. This change ensures that all relevant blocks are properly processed regardless of the presence of partial secrets. This is similar to the bug that 4bd6c133e092529c8a56b399f89038aa7ed98475 fixed. That bug ruled out the indexing of changeless transactions spending silent payment outputs owned by the wallet, but sending funds to non taproot addresses. Those transacions have available inputs for shared secret derivation according to BIP 352 (the silent payment output spend by this transactions is a valid P2TR key path spend), but there aren't any P2TR outputs on them, so if the tweak server is skipping transactions not containing P2TR output, any implementation using tweaks as proxy to decide which transactions to scan, are going to miss these transactions. --- cli/v2/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 18839e7..8d4afff 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -441,10 +441,10 @@ async fn main() -> anyhow::Result<()> { } } - if !partial_secrets.is_empty() { - tracing::info!("Block {hash} is relevant, indexing."); - wallet.apply_block_relevant(block, partial_secrets, height); - } + tracing::info!("Block {hash} is relevant, indexing."); + // if all outputs in transactions in the block are not p2tr + // outputs, partial secrets is going to be empty + wallet.apply_block_relevant(block, partial_secrets, height); } } } From 6ea475f7eb8ad95175d570ada75d5ff759be694d Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:44:38 +0200 Subject: [PATCH 15/31] fix(oracles): return empty tweaks if call to client errors Modified the BlindbitSubscriber to handle errors from client.tweaks() by returning an empty vector of tweaks instead of None. This ensures the stream continues processing even when API calls fail, preventing the stream from terminating early when encountering network errors during tweak retrieval. --- oracles/src/tweaks/blindbit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index 8d8cd2c..91c7804 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -186,9 +186,9 @@ impl BlindbitSubscriber { let client = client.clone(); async move { if let Ok(tweaks) = client.tweaks(height, Amount::from_sat(1000)).await { - Some((height, hash, tweaks)) + (height, hash, tweaks) } else { - None + (height, hash, vec![]) } } }) @@ -196,7 +196,7 @@ impl BlindbitSubscriber { let read = self.db.lock().unwrap().begin_read().unwrap(); let table = read.open_table(TABLE_DEF).unwrap(); - while let Some((height, hash, tweaks)) = stream.next().await.flatten() { + while let Some((height, hash, tweaks)) = stream.next().await { tracing::info!("Tweaks {progress}/{base}"); progress += 1; From 5a941bd343bfec144bfd781df9d5162b5323f637 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:45:44 +0200 Subject: [PATCH 16/31] doc(oracles): add comment explaining why unspent scripts are scanned The commit adds a clarifying comment in the BlindbitSubscriber implementation explaining why unspent script pubkeys are only included when scanning for tweaks. These unspent script pubkeys must be checked alongside other script pubkeys because they must be used for shared secret derivation, so can only exist in blocks containing tweaks. --- oracles/src/tweaks/blindbit.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index 91c7804..f489857 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -215,6 +215,8 @@ impl BlindbitSubscriber { .collect::>(); let mut only_spks: Vec<[u8; 34]> = all_spks.clone().into_keys().collect(); + // unspent script pubkeys can only be present in blocks with tweaks, because they are + // by themselves inputs available for shared secret derivation only_spks.extend_from_slice(&self.unspent_script_pubkeys); if !all_spks.is_empty() && filter.match_any(&hash, only_spks.into_iter()).unwrap() { From c101f467264f125332f9d3b23dcb447de83e2dc3 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Fri, 17 Oct 2025 21:07:39 -0500 Subject: [PATCH 17/31] refactor(wallet): store BlockId as wallet birthday instead of chain height This provides more precise tracking of the synchronization point by storing both the height and the hash of the block. Changes include: - Updated SpWallet struct to use BlockId for birthday - Modified CLI commands to accept both height and hash parameters - Adapted ScanCbf command to work with the new birthday structure - Updated wallet creation to construct a BlockId from height and hash --- cli/v2/src/main.rs | 53 ++++++++++++++++++++++++++++++++++------------ wallet/src/lib.rs | 10 ++++----- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 8d4afff..7bf0144 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -154,15 +154,21 @@ pub enum Commands { }, ScanCbf { tweak_server_url: String, + #[clap(long, short, default_value = "height")] height: Option, + #[clap(long, short, default_value = "hash")] + hash: Option, }, Create { /// Network #[clap(long, short, default_value = "signet")] network: Network, /// The block height at which to begin scanning outputs for this wallet - #[clap(long, short, default_value = "signet")] - birthday: u32, + #[clap(long, short, default_value = "height")] + birthday_height: u32, + /// The block hash at which to begin scanning outputs for this wallet + #[clap(long, short, default_value = "hash")] + birthday_hash: BlockHash, /// Genesis Hash genesis_hash: Option, }, @@ -293,7 +299,8 @@ async fn main() -> anyhow::Result<()> { } Commands::ScanCbf { tweak_server_url, - height: maybe_height, + height, + hash, } => { async fn trace( mut log_rx: kyoto::Receiver, @@ -323,19 +330,33 @@ async fn main() -> anyhow::Result<()> { tracing::info!("Wallet main SP address: {}", wallet.get_address()); - let sync_height = if let Some(height) = maybe_height { - height - } else if wallet.birthday <= wallet.chain().tip().height() { - wallet.chain().tip().height() + let sync_point = if let (Some(height), Some(hash)) = (height, hash) { + BlockId { height, hash } + } else if wallet.birthday.height <= wallet.chain().tip().height() { + let height = wallet.chain().tip().height(); + let hash = wallet.chain().tip().hash(); + BlockId { height, hash } } else { - wallet.birthday + let checkpoint = wallet + .chain() + .get(wallet.birthday.height) + .expect("should be something"); + let height = checkpoint.height(); + let hash = checkpoint.hash(); + BlockId { height, hash } }; - tracing::info!("Synchronizing from block {sync_height}"); + tracing::info!( + "Synchronizing from block {}:{}", + sync_point.hash, + sync_point.height + ); // Set up the light client - let checkpoint = - HeaderCheckpoint::closest_checkpoint_below_height(sync_height, wallet.network()); + let checkpoint = HeaderCheckpoint::closest_checkpoint_below_height( + sync_point.height, + wallet.network(), + ); let (node, client) = match wallet.network() { Network::Regtest => { let peer = TrustedPeer::new( @@ -389,7 +410,7 @@ async fn main() -> anyhow::Result<()> { .unwrap(); let mut filter_subscriber = - FilterSubscriber::new(db_buffer, event_rx, changes_tx, sync_height); + FilterSubscriber::new(db_buffer, event_rx, changes_tx, sync_point.height); tracing::info!("Starting the node..."); tokio::task::spawn(async move { @@ -732,7 +753,8 @@ pub fn init_or_load(db_magic: &[u8], db_path: &str) -> anyhow::Result { let secp = Secp256k1::new(); @@ -755,6 +777,11 @@ pub fn init_or_load(db_magic: &[u8], db_path: &str) -> anyhow::Result::create(db_magic, db_path)?; if let Some(stage) = wallet.staged() { diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 9fdba1d..4e24154 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -23,8 +23,8 @@ use bdk_tx::{ }; use indexer::{ bdk_chain::{ - Anchor, Balance, CanonicalizationParams, ChainPosition, CheckPoint, ConfirmationBlockTime, - TxGraph, + Anchor, Balance, BlockId, CanonicalizationParams, ChainPosition, CheckPoint, + ConfirmationBlockTime, TxGraph, bdk_core::Merge, bitcoin::{BlockHash, Network, bip32::DerivationPath, key::Secp256k1}, local_chain::{self, LocalChain}, @@ -51,7 +51,7 @@ pub mod signers; #[must_use] pub struct ChangeSet { /// The starting block height at which this wallet started to operate on. - birthday: u32, + birthday: BlockId, /// The Bitcoin network the wallet operates on. network: Option, /// Changes related to the local blockchain data. @@ -100,7 +100,7 @@ impl Merge for ChangeSet { /// and interaction with a blockchain indexer. pub struct SpWallet { /// The birthday of the wallet, representing the starting block height for scanning. - pub birthday: u32, + pub birthday: BlockId, network: Network, chain: LocalChain, indexer: SpIndexer, @@ -149,7 +149,7 @@ impl SpWallet { /// * [`SpWalletError::NonTaprootDescriptor`] if the provided descriptor is not a Taproot descriptor. /// * [`SpWalletError::PrivateDataNotAvailable`] if the descriptor cannot provide private key data. pub fn new( - birthday: u32, + birthday: BlockId, genesis_hash: BlockHash, tr_xprv: &str, network: Network, From 0b62ebc4075b88cb867c26d64a13480355a4c619 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Fri, 17 Oct 2025 21:31:33 -0500 Subject: [PATCH 18/31] refactor(oracles): update kyoto-cbf to bip157 new name Updates the codebase to use the renamed `bip157` crate which replaces the `kyoto-cbf` crate. The change includes: - Replacing the `kyoto-cbf` dependency with `bip157` in Cargo.toml - Updating module imports from `kyoto` to `bip157` - Adapting function calls and types to match the new API - Updating client initialization code and event handling --- Cargo.lock | 87 +++++++++------------------------- cli/v2/src/main.rs | 62 ++++++++++++------------ oracles/Cargo.toml | 2 +- oracles/src/filters/kyoto.rs | 8 ++-- oracles/src/lib.rs | 2 +- oracles/src/tweaks/blindbit.rs | 2 +- 6 files changed, 61 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2699a70..0fa8f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -324,10 +324,10 @@ dependencies = [ name = "bdk_sp_oracles" version = "0.1.0" dependencies = [ + "bip157", "bitcoin", "futures", "indexer", - "kyoto-cbf", "rayon", "redb", "reqwest", @@ -381,6 +381,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bip157" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee00924860370b262cf436f4b04b31af4d8f057ff905b95ce00f5129628d4c3" +dependencies = [ + "bip324", + "bitcoin", + "bitcoin-address-book", + "tokio", +] + [[package]] name = "bip324" version = "0.7.0" @@ -413,6 +425,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin-address-book" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d55a2ccdaa0271ea60355a01fc82e37f33a340df80599d344f9d6e97d46e48" +dependencies = [ + "bitcoin", +] + [[package]] name = "bitcoin-internals" version = "0.3.0" @@ -842,18 +863,6 @@ dependencies = [ "windows-sys 0.61.0", ] -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - [[package]] name = "fastrand" version = "2.3.0" @@ -1076,15 +1085,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "heck" version = "0.5.0" @@ -1456,18 +1456,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "kyoto-cbf" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805f16bcf1d4738529f230404e7d0ab6e9ecf9e265920c212d446a291a93297e" -dependencies = [ - "bip324", - "bitcoin", - "rusqlite", - "tokio", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1501,17 +1489,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "libsqlite3-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1968,20 +1945,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rusqlite" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" -dependencies = [ - "bitflags 2.9.4", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - [[package]] name = "rustc-demangle" version = "0.1.26" @@ -2613,12 +2576,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 7bf0144..9785277 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -27,13 +27,13 @@ use bdk_sp::{ }, }; use bdk_sp_oracles::{ - filters::kyoto::{FilterEvent, FilterSubscriber}, - kyoto::{ + bip157::{ self, tokio::{self, select}, - AddrV2, Client as KyotoClient, HeaderCheckpoint, IndexedBlock, Info, NodeBuilder, - ServiceFlags, TrustedPeer, UnboundedReceiver, Warning, + AddrV2, Builder, Client as KyotoClient, HeaderCheckpoint, IndexedBlock, Info, ServiceFlags, + TrustedPeer, UnboundedReceiver, Warning, }, + filters::kyoto::{FilterEvent, FilterSubscriber}, tweaks::blindbit::{BlindbitSubscriber, TweakEvent}, }; use bdk_sp_wallet::{ @@ -51,7 +51,7 @@ use serde_json::json; use std::{ collections::{HashMap, HashSet}, env, - net::{IpAddr, Ipv4Addr}, + net::Ipv4Addr, str::FromStr, sync::Mutex, time::{Duration, Instant}, @@ -303,17 +303,11 @@ async fn main() -> anyhow::Result<()> { hash, } => { async fn trace( - mut log_rx: kyoto::Receiver, - mut info_rx: kyoto::Receiver, + mut info_rx: bip157::Receiver, mut warn_rx: UnboundedReceiver, ) { loop { select! { - log = log_rx.recv() => { - if let Some(log) = log { - tracing::info!("{log}"); - } - } info = info_rx.recv() => { if let Some(info) = info { tracing::info!("{info}"); @@ -331,11 +325,11 @@ async fn main() -> anyhow::Result<()> { tracing::info!("Wallet main SP address: {}", wallet.get_address()); let sync_point = if let (Some(height), Some(hash)) = (height, hash) { - BlockId { height, hash } + HeaderCheckpoint::new(height, hash) } else if wallet.birthday.height <= wallet.chain().tip().height() { let height = wallet.chain().tip().height(); let hash = wallet.chain().tip().hash(); - BlockId { height, hash } + HeaderCheckpoint::new(height, hash) } else { let checkpoint = wallet .chain() @@ -343,7 +337,7 @@ async fn main() -> anyhow::Result<()> { .expect("should be something"); let height = checkpoint.height(); let hash = checkpoint.hash(); - BlockId { height, hash } + HeaderCheckpoint::new(height, hash) }; tracing::info!( @@ -353,10 +347,12 @@ async fn main() -> anyhow::Result<()> { ); // Set up the light client - let checkpoint = HeaderCheckpoint::closest_checkpoint_below_height( - sync_point.height, - wallet.network(), - ); + let checkpoint = if wallet.network() == Network::Bitcoin { + HeaderCheckpoint::taproot_activation() + } else { + HeaderCheckpoint::from_genesis(wallet.network()) + }; + let (node, client) = match wallet.network() { Network::Regtest => { let peer = TrustedPeer::new( @@ -364,28 +360,35 @@ async fn main() -> anyhow::Result<()> { None, ServiceFlags::P2P_V2, ); - let builder = NodeBuilder::new(wallet.network()); + let builder = Builder::new(wallet.network()); builder - .after_checkpoint(checkpoint) + .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) .add_peer(peer) .required_peers(1) .build() - .unwrap() } Network::Signet => { - let peer_1 = IpAddr::V4(Ipv4Addr::new(95, 217, 198, 121)); + let peer_1 = TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::new(135, 181, 182, 162)), + None, + ServiceFlags::P2P_V2, + ); let peer_2 = TrustedPeer::new( - AddrV2::Ipv4(Ipv4Addr::new(23, 137, 57, 100)), + AddrV2::Ipv4(Ipv4Addr::new(172, 105, 179, 233)), + None, + ServiceFlags::P2P_V2, + ); + let peer_3 = TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::new(37, 254, 97, 224)), None, ServiceFlags::P2P_V2, ); - let builder = NodeBuilder::new(wallet.network()); + let builder = Builder::new(wallet.network()); builder - .after_checkpoint(checkpoint) - .add_peers(vec![(peer_1, None).into(), peer_2]) + .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) + .add_peers(vec![peer_1, peer_2, peer_3]) .required_peers(2) .build() - .unwrap() } _ => unimplemented!("Not mainnet nor testnet environments"), }; @@ -394,7 +397,6 @@ async fn main() -> anyhow::Result<()> { let KyotoClient { requester, - log_rx, info_rx, warn_rx, event_rx, @@ -424,7 +426,7 @@ async fn main() -> anyhow::Result<()> { tokio::task::spawn(async move { blindbit_subscriber.run().await }); tracing::info!("Initializing log loop..."); - tokio::task::spawn(async move { trace(log_rx, info_rx, warn_rx).await }); + tokio::task::spawn(async move { trace(info_rx, warn_rx).await }); tracing::info!("Starting filter subscriber..."); tokio::task::spawn(async move { filter_subscriber.run().await }); diff --git a/oracles/Cargo.toml b/oracles/Cargo.toml index c941fb6..3d4710f 100644 --- a/oracles/Cargo.toml +++ b/oracles/Cargo.toml @@ -8,7 +8,7 @@ authors.workspace = true bitcoin = "0.32.7" futures = "0.3" indexer = { version = "0.1.0", path = "../indexer", features = ["serde"]} -kyoto-cbf = { version = "0.13.2", features = ["rusqlite", "filter-control"], default-features = false } +bip157 = "0.2.0" redb = "2.4.0" rayon = "1.11.0" reqwest = { version = "0.12.23", features = ["json", "rustls-tls", "http2", "charset"], default-features = false } diff --git a/oracles/src/filters/kyoto.rs b/oracles/src/filters/kyoto.rs index 4ffa9bb..46e6596 100644 --- a/oracles/src/filters/kyoto.rs +++ b/oracles/src/filters/kyoto.rs @@ -1,8 +1,8 @@ -use indexer::bdk_chain::BlockId; -use kyoto::{ +use bip157::{ BlockHash, Event, IndexedFilter, SyncUpdate, UnboundedReceiver, tokio::sync::mpsc::UnboundedSender, }; +use indexer::bdk_chain::BlockId; use redb::{Database, TableDefinition}; use std::{ collections::{BTreeMap, BTreeSet}, @@ -37,7 +37,7 @@ impl DatabaseBuffer { { let mut table = write.open_table(TABLE_DEF).unwrap(); for indexed_filter in core::mem::take(&mut self.queue) { - writes.insert(indexed_filter.height(), *indexed_filter.block_hash()); + writes.insert(indexed_filter.height(), indexed_filter.block_hash()); table .insert(indexed_filter.height(), indexed_filter.into_contents()) .unwrap(); @@ -87,7 +87,7 @@ impl FilterSubscriber { pub async fn run(&mut self) -> Result<(), UpdateError> { while let Some(message) = self.receiver.recv().await { match message { - Event::Synced(SyncUpdate { tip, .. }) => { + Event::FiltersSynced(SyncUpdate { tip, .. }) => { tracing::info!("Sending new changes to tweak subscriber"); let changes = self.db_buffer.write_queue(); if self.sender.send(FilterEvent::Changes(changes)).is_err() { diff --git a/oracles/src/lib.rs b/oracles/src/lib.rs index 8d15293..1d5a6a9 100644 --- a/oracles/src/lib.rs +++ b/oracles/src/lib.rs @@ -1,3 +1,3 @@ pub mod filters; pub mod tweaks; -pub use kyoto; +pub use bip157; diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index f489857..ed8f541 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -1,4 +1,5 @@ use crate::filters::kyoto::{DatabaseBuffer, FilterEvent, TABLE_DEF, WriteRange}; +use bip157::{BlockFilter, BlockHash, UnboundedReceiver, tokio::sync::mpsc::UnboundedSender}; use bitcoin::{ Amount, Network, absolute::Height, hashes::serde::Deserialize, secp256k1::PublicKey, }; @@ -7,7 +8,6 @@ use indexer::{ bdk_chain::{BlockId, ConfirmationBlockTime}, v2::SpIndexerV2 as SpIndexer, }; -use kyoto::{BlockFilter, BlockHash, UnboundedReceiver, tokio::sync::mpsc::UnboundedSender}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use redb::Database; use reqwest::{Client, Url}; From 6726076be54ba32085258890ba53897e1d74db7c Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:05:36 +0200 Subject: [PATCH 19/31] fix(cli): remove default from height/hash parameters in ScanCbf and Create Removes default values from the height and hash parameters in the ScanCbf and Create commands. --- cli/v2/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 9785277..94f7fd7 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -154,9 +154,9 @@ pub enum Commands { }, ScanCbf { tweak_server_url: String, - #[clap(long, short, default_value = "height")] + #[clap(long)] height: Option, - #[clap(long, short, default_value = "hash")] + #[clap(long)] hash: Option, }, Create { @@ -164,10 +164,10 @@ pub enum Commands { #[clap(long, short, default_value = "signet")] network: Network, /// The block height at which to begin scanning outputs for this wallet - #[clap(long, short, default_value = "height")] + #[clap(long)] birthday_height: u32, /// The block hash at which to begin scanning outputs for this wallet - #[clap(long, short, default_value = "hash")] + #[clap(long)] birthday_hash: BlockHash, /// Genesis Hash genesis_hash: Option, From d69e7cd362123597bb00c8a0489b42b2aa06643b Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:20:02 +0200 Subject: [PATCH 20/31] feat(cli): add Birthday command to sp-cli2 Adds a new Birthday command to the sp-cli2 tool that displays the wallet's birthday block height and hash in JSON format. This information is useful for wallet recovery and synchronization as it represents the earliest block that needs to be scanned for wallet transactions. --- cli/v2/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index 94f7fd7..c292e09 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -207,6 +207,7 @@ pub enum Commands { descriptor: Option, }, Balance, + Birthday, } #[tokio::main] @@ -726,6 +727,13 @@ async fn main() -> anyhow::Result<()> { ); println!("{}", serde_json::to_string_pretty(&obj)?); } + Commands::Birthday => { + let BlockId { height, hash } = wallet.birthday; + let mut obj = serde_json::Map::new(); + obj.insert("height".to_string(), json!(height)); + obj.insert("hash".to_string(), json!(hash)); + println!("{}", serde_json::to_string_pretty(&obj)?); + } Commands::Create { .. } => { unreachable!("already handled by init_or_load") } From b9904bbcacdd06a706eb3de4b67901b28135b55a Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Tue, 7 Oct 2025 12:19:01 +0200 Subject: [PATCH 21/31] refactor(cli): keep only last known peer serving filters Reduce the number of trusted peers for signet network from 3 to 1. This change also updates the required_peers value from 2 to 1 to allow faster synchronization. --- cli/v2/src/main.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index c292e09..acf37ae 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -369,26 +369,16 @@ async fn main() -> anyhow::Result<()> { .build() } Network::Signet => { - let peer_1 = TrustedPeer::new( - AddrV2::Ipv4(Ipv4Addr::new(135, 181, 182, 162)), - None, - ServiceFlags::P2P_V2, - ); - let peer_2 = TrustedPeer::new( - AddrV2::Ipv4(Ipv4Addr::new(172, 105, 179, 233)), - None, - ServiceFlags::P2P_V2, - ); - let peer_3 = TrustedPeer::new( - AddrV2::Ipv4(Ipv4Addr::new(37, 254, 97, 224)), + let peer = TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::new(170, 75, 162, 231)), None, ServiceFlags::P2P_V2, ); let builder = Builder::new(wallet.network()); builder .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) - .add_peers(vec![peer_1, peer_2, peer_3]) - .required_peers(2) + .add_peers(vec![peer]) + .required_peers(1) .build() } _ => unimplemented!("Not mainnet nor testnet environments"), From 3f6f01a4622e45a82e27ae1b4a319e9a6a1d07df Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Tue, 7 Oct 2025 14:41:56 +0200 Subject: [PATCH 22/31] feat(cli): add optional extra_peer parameter to ScanCbf command Add support for specifying an additional peer when using the ScanCbf command via the new --extra_peer option. This allows users to connect to a custom peer beyond the default peers configured for regtest and signet networks. --- cli/v2/src/main.rs | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/cli/v2/src/main.rs b/cli/v2/src/main.rs index acf37ae..efa05af 100644 --- a/cli/v2/src/main.rs +++ b/cli/v2/src/main.rs @@ -155,6 +155,8 @@ pub enum Commands { ScanCbf { tweak_server_url: String, #[clap(long)] + extra_peer: Option, + #[clap(long)] height: Option, #[clap(long)] hash: Option, @@ -300,6 +302,7 @@ async fn main() -> anyhow::Result<()> { } Commands::ScanCbf { tweak_server_url, + extra_peer: maybe_extra_peer, height, hash, } => { @@ -354,35 +357,41 @@ async fn main() -> anyhow::Result<()> { HeaderCheckpoint::from_genesis(wallet.network()) }; - let (node, client) = match wallet.network() { + let mut peers = vec![]; + match wallet.network() { Network::Regtest => { - let peer = TrustedPeer::new( + peers.push(TrustedPeer::new( AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)), None, ServiceFlags::P2P_V2, - ); - let builder = Builder::new(wallet.network()); - builder - .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) - .add_peer(peer) - .required_peers(1) - .build() + )); } Network::Signet => { - let peer = TrustedPeer::new( + peers.push(TrustedPeer::new( AddrV2::Ipv4(Ipv4Addr::new(170, 75, 162, 231)), None, ServiceFlags::P2P_V2, - ); - let builder = Builder::new(wallet.network()); - builder - .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) - .add_peers(vec![peer]) - .required_peers(1) - .build() + )); } _ => unimplemented!("Not mainnet nor testnet environments"), }; + + if let Some(extra_peer) = maybe_extra_peer { + peers.push(TrustedPeer::new( + AddrV2::Ipv4(Ipv4Addr::from_str(&extra_peer)?), + None, + ServiceFlags::P2P_V2, + )); + }; + + let (node, client) = { + let builder = Builder::new(wallet.network()); + builder + .chain_state(bip157::chain::ChainState::Checkpoint(checkpoint)) + .add_peers(peers) + .required_peers(1) + .build() + }; let (changes_tx, changes_rx) = tokio::sync::mpsc::unbounded_channel::(); let (matches_tx, mut matches_rx) = tokio::sync::mpsc::unbounded_channel::(); From fce6860ed64b929874233b20d37ae31f67a168c7 Mon Sep 17 00:00:00 2001 From: macgyver13 <4712150+macgyver13@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:51:43 +0200 Subject: [PATCH 23/31] build(workspace): unify Cargo resolver edition on all crates --- dleq/Cargo.toml | 2 +- fuzz/Cargo.toml | 2 +- indexer/Cargo.toml | 2 +- oracles/Cargo.toml | 2 +- wallet/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dleq/Cargo.toml b/dleq/Cargo.toml index 5e803e0..0c7db6d 100644 --- a/dleq/Cargo.toml +++ b/dleq/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dleq" version = "0.1.0" -edition = "2024" +edition = "2021" authors.workspace = true [dependencies] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 3c98875..e8afc4f 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp_fuzz" version = "0.1.0" -edition = "2024" +edition = "2021" publish = false authors.workspace = true diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 3dbf434..8e5cb42 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "indexer" version = "0.1.0" -edition = "2024" +edition = "2021" authors.workspace = true [dependencies] diff --git a/oracles/Cargo.toml b/oracles/Cargo.toml index 3d4710f..2313138 100644 --- a/oracles/Cargo.toml +++ b/oracles/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bdk_sp_oracles" version = "0.1.0" -edition = "2024" +edition = "2021" authors.workspace = true [dependencies] diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 0a86be0..7aa0760 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bdk_sp_wallet" version = "0.1.0" -edition = "2024" +edition = "2021" authors.workspace = true [dependencies] From 8458734cb785b13a2cb350f85bf930df39ca7db6 Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Sat, 18 Oct 2025 14:15:21 -0500 Subject: [PATCH 24/31] style(workspace): apply cargo fmt changes --- dleq/src/lib.rs | 2 +- .../functional_tests/dleq_generate_proofs.rs | 2 +- dleq/tests/functional_tests/dleq_verify_proofs.rs | 2 +- dleq/tests/functional_tests/serialization.rs | 2 +- indexer/src/lib.rs | 6 +++--- indexer/src/v2/indexes.rs | 6 +++--- indexer/src/v2/mod.rs | 4 ++-- oracles/src/filters/kyoto.rs | 4 ++-- oracles/src/tweaks/blindbit.rs | 6 +++--- wallet/src/lib.rs | 15 +++++++-------- wallet/src/signers.rs | 4 ++-- 11 files changed, 26 insertions(+), 27 deletions(-) diff --git a/dleq/src/lib.rs b/dleq/src/lib.rs index bfe7e8d..4d7b617 100644 --- a/dleq/src/lib.rs +++ b/dleq/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_snake_case)] -use bitcoin::hashes::{Hash, HashEngine, sha256t_hash_newtype}; +use bitcoin::hashes::{sha256t_hash_newtype, Hash, HashEngine}; use bitcoin::key::Secp256k1; use bitcoin::secp256k1::{PublicKey, Scalar, SecretKey}; diff --git a/dleq/tests/functional_tests/dleq_generate_proofs.rs b/dleq/tests/functional_tests/dleq_generate_proofs.rs index ec4de72..c34b85c 100644 --- a/dleq/tests/functional_tests/dleq_generate_proofs.rs +++ b/dleq/tests/functional_tests/dleq_generate_proofs.rs @@ -2,7 +2,7 @@ use dleq::dleq_generate_proof; -use crate::serialization::{GENERATE_PROOF_VECTORS, GenerateTestCase}; +use crate::serialization::{GenerateTestCase, GENERATE_PROOF_VECTORS}; fn check_generated_proof(test_case: &GenerateTestCase) { let GenerateTestCase { diff --git a/dleq/tests/functional_tests/dleq_verify_proofs.rs b/dleq/tests/functional_tests/dleq_verify_proofs.rs index 164e9d6..2e09dd0 100644 --- a/dleq/tests/functional_tests/dleq_verify_proofs.rs +++ b/dleq/tests/functional_tests/dleq_verify_proofs.rs @@ -1,4 +1,4 @@ -use crate::serialization::{VERIFY_PROOF_VECTORS, VerifyTestCase}; +use crate::serialization::{VerifyTestCase, VERIFY_PROOF_VECTORS}; use dleq::dleq_verify_proof; fn check_generated_proof(test_case: &VerifyTestCase) { diff --git a/dleq/tests/functional_tests/serialization.rs b/dleq/tests/functional_tests/serialization.rs index dfe1f57..de3df37 100644 --- a/dleq/tests/functional_tests/serialization.rs +++ b/dleq/tests/functional_tests/serialization.rs @@ -5,7 +5,7 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use once_cell::sync::Lazy; use csv::ReaderBuilder; -use serde::{self, Deserialize, de::Error}; +use serde::{self, de::Error, Deserialize}; #[derive(Debug, Deserialize)] pub struct VerifyTestCase { diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 00dbd2d..85d735e 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -1,13 +1,13 @@ use bdk_bitcoind_rpc::bitcoincore_rpc::{Client, RpcApi}; -use bdk_chain::{Merge, TxGraph, tx_graph}; +use bdk_chain::{tx_graph, Merge, TxGraph}; use bdk_sp::{ bitcoin::{ - OutPoint, ScriptBuf, Transaction, TxOut, Txid, key::Secp256k1, secp256k1::{PublicKey, Scalar, SecretKey}, + OutPoint, ScriptBuf, Transaction, TxOut, Txid, }, encoding::SilentPaymentCode, - receive::{SpOut, SpReceiveError, scan::Scanner}, + receive::{scan::Scanner, SpOut, SpReceiveError}, }; use std::{ collections::{BTreeMap, BTreeSet}, diff --git a/indexer/src/v2/indexes.rs b/indexer/src/v2/indexes.rs index cbbcd2e..e6c4c8d 100644 --- a/indexer/src/v2/indexes.rs +++ b/indexer/src/v2/indexes.rs @@ -1,15 +1,15 @@ use bdk_sp::{ bitcoin::{ - OutPoint, ScriptBuf, TxOut, Txid, XOnlyPublicKey, secp256k1::{PublicKey, Scalar, SecretKey}, + OutPoint, ScriptBuf, TxOut, Txid, XOnlyPublicKey, }, receive::{SpMeta, SpOut}, }; #[cfg(feature = "serde")] use serde::{ - Deserialize, Serialize, de::{self, Deserializer, SeqAccess, Visitor}, ser::{SerializeTuple, Serializer}, + Deserialize, Serialize, }; use std::{ collections::{BTreeMap, HashMap, HashSet}, @@ -124,7 +124,7 @@ mod scalar_serde { use super::Scalar; use core::fmt; use serde::de::Visitor; - use serde::{Deserializer, Serializer, de}; + use serde::{de, Deserializer, Serializer}; pub fn serialize(s: &Scalar, ser: S) -> Result where diff --git a/indexer/src/v2/mod.rs b/indexer/src/v2/mod.rs index aead6f6..46681a6 100644 --- a/indexer/src/v2/mod.rs +++ b/indexer/src/v2/mod.rs @@ -1,10 +1,10 @@ use self::indexes::{Label, SpIndex}; -use bdk_chain::{Anchor, BlockId, Merge, TxGraph, TxPosInBlock, tx_graph}; +use bdk_chain::{tx_graph, Anchor, BlockId, Merge, TxGraph, TxPosInBlock}; use bdk_sp::{ bitcoin::{ - Block, Network, OutPoint, ScriptBuf, Transaction, Txid, key::Secp256k1, secp256k1::{PublicKey, SecretKey}, + Block, Network, OutPoint, ScriptBuf, Transaction, Txid, }, compute_shared_secret, encoding::SilentPaymentCode, diff --git a/oracles/src/filters/kyoto.rs b/oracles/src/filters/kyoto.rs index 46e6596..f48ff40 100644 --- a/oracles/src/filters/kyoto.rs +++ b/oracles/src/filters/kyoto.rs @@ -1,6 +1,6 @@ use bip157::{ - BlockHash, Event, IndexedFilter, SyncUpdate, UnboundedReceiver, - tokio::sync::mpsc::UnboundedSender, + tokio::sync::mpsc::UnboundedSender, BlockHash, Event, IndexedFilter, SyncUpdate, + UnboundedReceiver, }; use indexer::bdk_chain::BlockId; use redb::{Database, TableDefinition}; diff --git a/oracles/src/tweaks/blindbit.rs b/oracles/src/tweaks/blindbit.rs index ed8f541..0b77150 100644 --- a/oracles/src/tweaks/blindbit.rs +++ b/oracles/src/tweaks/blindbit.rs @@ -1,7 +1,7 @@ -use crate::filters::kyoto::{DatabaseBuffer, FilterEvent, TABLE_DEF, WriteRange}; -use bip157::{BlockFilter, BlockHash, UnboundedReceiver, tokio::sync::mpsc::UnboundedSender}; +use crate::filters::kyoto::{DatabaseBuffer, FilterEvent, WriteRange, TABLE_DEF}; +use bip157::{tokio::sync::mpsc::UnboundedSender, BlockFilter, BlockHash, UnboundedReceiver}; use bitcoin::{ - Amount, Network, absolute::Height, hashes::serde::Deserialize, secp256k1::PublicKey, + absolute::Height, hashes::serde::Deserialize, secp256k1::PublicKey, Amount, Network, }; use futures::StreamExt; use indexer::{ diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 4e24154..5235102 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -6,32 +6,31 @@ //! transaction building, and [`indexer`] for blockchain data management. use bdk_sp::{ bitcoin::{ - Block, ScriptBuf, Transaction, Txid, absolute::{self, Height, LockTime, Time}, - secp256k1, + secp256k1, Block, ScriptBuf, Transaction, Txid, }, encoding::SilentPaymentCode, }; use bdk_tx::{ - CanonicalUnspents, InputCandidates, TxStatus, TxWithStatus, bitcoin::XOnlyPublicKey, miniscript::{ - DescriptorPublicKey, descriptor::{SinglePub, SinglePubKey}, plan::{Assets, Plan}, + DescriptorPublicKey, }, + CanonicalUnspents, InputCandidates, TxStatus, TxWithStatus, }; use indexer::{ bdk_chain::{ - Anchor, Balance, BlockId, CanonicalizationParams, ChainPosition, CheckPoint, - ConfirmationBlockTime, TxGraph, bdk_core::Merge, - bitcoin::{BlockHash, Network, bip32::DerivationPath, key::Secp256k1}, + bitcoin::{bip32::DerivationPath, key::Secp256k1, BlockHash, Network}, local_chain::{self, LocalChain}, miniscript::{ - Descriptor, descriptor::{DescriptorSecretKey, DescriptorType}, + Descriptor, }, + Anchor, Balance, BlockId, CanonicalizationParams, ChainPosition, CheckPoint, + ConfirmationBlockTime, TxGraph, }, v2::SpIndexerV2 as SpIndexer, }; diff --git a/wallet/src/signers.rs b/wallet/src/signers.rs index a6f6e0c..16aef06 100644 --- a/wallet/src/signers.rs +++ b/wallet/src/signers.rs @@ -1,10 +1,10 @@ use bdk_sp::bitcoin::{ - Network, PrivateKey, XOnlyPublicKey, bip32::DerivationPath, key::Secp256k1, secp256k1::{Scalar, SecretKey}, + Network, PrivateKey, XOnlyPublicKey, }; -use bdk_tx::miniscript::{Descriptor, descriptor::DescriptorSecretKey}; +use bdk_tx::miniscript::{descriptor::DescriptorSecretKey, Descriptor}; use indexer::v2::indexes::SpIndex; use std::{collections::HashMap, str::FromStr}; From 20316adc3379b64421d1d83942bfafd6a9c3990f Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:29:09 -0300 Subject: [PATCH 25/31] build: add nix flake to build sp-cli2 This commit introduces a Nix flake configuration to build the sp-cli2 application. The flake sets up a reproducible build environment using the stable Rust toolchain, configures package metadata, and defines both a development shell and a default package for sp-cli2. --- flake.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bb8d928 --- /dev/null +++ b/flake.lock @@ -0,0 +1,82 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1758767687, + "narHash": "sha256-znUulOqcL/Kkdr7CkyIi8Z1pTGXpi54Xg2FmlyJmv4A=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "b8bcc09d4f627f4e325408f6e7a85c3ac31f0eeb", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..6a50af6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,82 @@ +{ + description = "Dev environment for bdk_sp workspace"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; + }; + nixConfig = { + extra-substituters = ["https://sptabconf7.cachix.org"]; + extra-trusted-public-keys = ["sptabconf7.cachix.org-1:ulR9Y3dF4M6zKXnRRT4+r1Yp52EBMk6yVPKEp1EmdJk="]; + }; + outputs = { + self, + nixpkgs, + flake-utils, + rust-overlay, + }: + flake-utils.lib.eachDefaultSystem ( + system: let + overlays = [(import rust-overlay)]; + pkgs = import nixpkgs { + inherit system overlays; + }; + # Define the Rust version we want to use + rustVersion = pkgs.rust-bin.stable.latest.default; + in { + formatter = pkgs.alejandra; + + packages = { + sp-cli2 = + (pkgs.makeRustPlatform { + cargo = rustVersion; + rustc = rustVersion; + }) + .buildRustPackage { + pname = "sp-cli2"; + version = "0.1.0"; + + # Disable cargo-auditable which doesn't support edition 2024 + auditable = false; + src = ./.; + cargoLock = { + lockFile = ./Cargo.lock; + outputHashes = { + "bdk_tx-0.1.0" = "sha256-kND3yQ80ld8bQskf1Y+aDgJnZegTEviVV9d2zc7wwuQ="; + }; + }; + + buildAndTestSubdir = "cli/v2"; + meta = with pkgs.lib; { + description = "A lightweight command line bitcoin silent payment wallet powered by BDK"; + homepage = "https://bitcoindevkit.org"; + license = with licenses; [mit]; + mainProgram = "sp-cli2"; + }; + }; + }; + + defaultPackage = self.packages.${system}.sp-cli2; + + apps = { + sp-cli2 = flake-utils.lib.mkApp { + drv = self.defaultPackage; + name = "sp-cli2"; + }; + }; + + devShells.default = pkgs.mkShell { + buildInputs = [ + pkgs.rustc + pkgs.cargo + pkgs.rust-analyzer + self.packages.${system}.sp-cli2 + ]; + }; + } + ); +} From 91a2ffe1f6d526fe392a13efc01f80fdf1b0977d Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:38:47 -0300 Subject: [PATCH 26/31] build(tabconf7): add nix flake environment for workshop The flake sets up a reproducible development environment with all necessary tools including Bitcoin Core, bdk-cli, sp-cli2, and supporting utilities. It configures two development shells: a default workshop shell that initializes a Bitcoin signet node with required directories and environment variables, and a debug shell for troubleshooting. The environment simplifies workshop participation by ensuring all participants have identical tooling regardless of their operating system. --- doc/tabconf7/flake.lock | 240 ++++++++++++++++++++++++++++++++++++++++ doc/tabconf7/flake.nix | 203 +++++++++++++++++++++++++++++++++ 2 files changed, 443 insertions(+) create mode 100644 doc/tabconf7/flake.lock create mode 100644 doc/tabconf7/flake.nix diff --git a/doc/tabconf7/flake.lock b/doc/tabconf7/flake.lock new file mode 100644 index 0000000..984a33d --- /dev/null +++ b/doc/tabconf7/flake.lock @@ -0,0 +1,240 @@ +{ + "nodes": { + "bdk-cli": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1756673831, + "narHash": "sha256-Hg4CjE67rT7Twd5nC3Al9e9Cg2oZHuSvvx//Zc6ZnUA=", + "owner": "nymius", + "repo": "bdk-cli", + "rev": "ccde9f0c12ef3d0cce169f3895b5466c742e7aea", + "type": "github" + }, + "original": { + "owner": "nymius", + "ref": "feat/nix-env", + "repo": "bdk-cli", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1756386758, + "narHash": "sha256-1wxxznpW2CKvI9VdniaUnTT2Os6rdRJcRUf65ZK9OtE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dfb2f12e899db4876308eba6d93455ab7da304cd", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1760284886, + "narHash": "sha256-TK9Kr0BYBQ/1P5kAsnNQhmWWKgmZXwUQr4ZMjCzWf2c=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cf3f5c4def3c7b5f1fc012b3d839575dbe552d43", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1760524057, + "narHash": "sha256-EVAqOteLBFmd7pKkb0+FIUyzTF61VKi7YmvP1tw4nEw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "544961dfcce86422ba200ed9a0b00dd4b1486ec5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "bdk-cli": "bdk-cli", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2", + "sp-cli2": "sp-cli2" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "bdk-cli", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1756521112, + "narHash": "sha256-/YW9DI+vZ2lbTvYAek6BsudUXdpWr0FybTDod4P42L4=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "2243e3f251ea18486f83133cf8e325d2b9b71e89", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { + "inputs": { + "nixpkgs": [ + "sp-cli2", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760754684, + "narHash": "sha256-B4+gmoRuvjZGKvDQtMjYkqyA89gZLjrXObZrXFrcKOk=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "16c233757f1b200936f1b39961c901733936c616", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sp-cli2": { + "inputs": { + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_3", + "rust-overlay": "rust-overlay_2" + }, + "locked": { + "path": "../..", + "type": "path" + }, + "original": { + "path": "../..", + "type": "path" + }, + "parent": [] + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/doc/tabconf7/flake.nix b/doc/tabconf7/flake.nix new file mode 100644 index 0000000..3985d2b --- /dev/null +++ b/doc/tabconf7/flake.nix @@ -0,0 +1,203 @@ +{ + description = "BDK Silent Payments Workshop Environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + sp-cli2.url = "../.."; + bdk-cli.url = "github:nymius/bdk-cli/feat/nix-env"; + }; + nixConfig = { + extra-substituters = ["https://sptabconf7.cachix.org"]; + extra-trusted-public-keys = ["sptabconf7.cachix.org-1:ulR9Y3dF4M6zKXnRRT4+r1Yp52EBMk6yVPKEp1EmdJk="]; + }; + outputs = { + self, + nixpkgs, + flake-utils, + sp-cli2, + bdk-cli, + }: + flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs {inherit system;}; + + bitcoind = pkgs.stdenv.mkDerivation rec { + pname = "bitcoin"; + version = "29.0"; # Update to latest version as needed + + src = pkgs.fetchurl { + url = "https://bitcoincore.org/bin/bitcoin-core-${version}/bitcoin-${version}-${ + if pkgs.stdenv.isDarwin + then + if pkgs.stdenv.isAarch64 + then "arm64-apple-darwin" + else "x86_64-apple-darwin" + else "x86_64-linux-gnu" + }.tar.gz"; + sha256 = + if pkgs.stdenv.isDarwin + then + if pkgs.stdenv.isAarch64 + then "sha256-jvA498EVtaSB4ccC86n90BKWng0k3Q9wb0j60VWDdxc=" + else "sha256-NEMcWCoDmd1C4Sdth9JTBsvd4CF/Z0S9VaKUWYZkXdo=" + else "sha256-poHk9s5STDOKEF8hRhNgW6xsM9WMMdxRNbvAK8RYu2w="; + }; + + installPhase = '' + mkdir -p $out/bin + cp bin/* $out/bin/ + ''; + + meta = { + description = "Bitcoin Core daemon"; + homepage = "https://bitcoincore.org/"; + }; + }; + workshopEnv = pkgs.buildEnv { + name = "bdk-sp-workshop-env"; + paths = with pkgs; + [ + jq + podman + qrencode + xclip + rust-script + just + python311Packages.weasyprint + presenterm + bitcoind + bdk-cli.packages.${system}.bdk-cli + sp-cli2.packages.${system}.sp-cli2 + ] + ++ lib.optionals (system != "aarch64-darwin") [ + virtiofsd + ]; + }; + in { + formatter = pkgs.alejandra; + + packages = { + default = workshopEnv; + workshop-env = workshopEnv; + }; + + devShells = { + debug = pkgs.mkShell { + packages = [workshopEnv]; + shellHook = '' + export PS1="$ " + export EXTRA_SCRIPTS="$PWD/.bin" + export BITCOIN_DATA_DIR="$PWD/.bitcoin" + export BDK_DATA_DIR="$PWD/.bdk" + export PATH="$EXTRA_SCRIPTS:$PATH" + export RPC_USER="__cookie__" + export RPC_PASS=$(cat $BITCOIN_DATA_DIR/signet/.cookie | cut -d ':' -f2) + export RPC_URL="http://127.0.0.1:38332/" + export TR_XPRV=$(cat ".tr_xprv") + export EXT_DESCRIPTOR=$(cat "$BDK_DATA_DIR/.external_descriptor") + export INT_DESCRIPTOR=$(cat "$BDK_DATA_DIR/.internal_descriptor") + export EXTRA_PEER=$(bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet getpeerinfo | jq -r 'map(select(.servicesnames[] | contains ("COMPACT"))) | .[0].addr' | cut -sd ":" -f1) + ''; + }; + workshop = pkgs.mkShell { + packages = [workshopEnv]; + shellHook = '' + export PS1="$ " + + export BITCOIN_DATA_DIR="$PWD/.bitcoin" + mkdir -p "$BITCOIN_DATA_DIR" + + export BDK_DATA_DIR="$PWD/.bdk" + mkdir -p "$BDK_DATA_DIR" + + bitcoind -daemonwait -signet -datadir=$BITCOIN_DATA_DIR -daemonwait -txindex -blockfilterindex -peerblockfilters + + export EXTRA_SCRIPTS="$PWD/.bin" + mkdir -p $EXTRA_SCRIPTS + + cat > "$EXTRA_SCRIPTS/signet-cli" <<'EOF' + #!/usr/bin/env bash + bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet $@ + EOF + + chmod +x "$EXTRA_SCRIPTS/signet-cli" + + cat > "$EXTRA_SCRIPTS/signet-bdk" <<'EOF' + #!/usr/bin/env bash + bdk-cli --datadir "$BDK_DATA_DIR" --network signet wallet -w signet -e "$EXT_DESCRIPTOR" -i "$INT_DESCRIPTOR" -c rpc -u http://localhost:38332/ "$BITCOIN_DATA_DIR/signet/.cookie" -d sqlite "$@" + EOF + + chmod +x "$EXTRA_SCRIPTS/signet-bdk" + + cat > "$EXTRA_SCRIPTS/signet-sp" <<'EOF' + #!/usr/bin/env bash + sp-cli2 "$@" + EOF + + chmod +x "$EXTRA_SCRIPTS/signet-sp" + + cat > "$EXTRA_SCRIPTS/regtest-cli" <<'EOF' + #!/usr/bin/env bash + just cli "$@" + EOF + + chmod +x "$EXTRA_SCRIPTS/regtest-cli" + + cat > "$EXTRA_SCRIPTS/regtest-bdk" <<'EOF' + #!/usr/bin/env bash + just regtest-bdk "$@" + EOF + + chmod +x "$EXTRA_SCRIPTS/regtest-bdk" + + cat > "$EXTRA_SCRIPTS/regtest-sp" <<'EOF' + #!/usr/bin/env bash + just regtest-sp "$@" + EOF + + chmod +x "$EXTRA_SCRIPTS/regtest-sp" + + export PATH="$EXTRA_SCRIPTS:$PATH" + + export RPC_USER="__cookie__" + export RPC_PASS=$(cat $BITCOIN_DATA_DIR/signet/.cookie | cut -d ':' -f2) + export RPC_URL="http://127.0.0.1:38332/" + + if [ ! -f "$BDK_DATA_DIR/.external_descriptor" ] || [ ! -f "$BDK_DATA_DIR/.internal_descriptor" ]; then + rm -rf $BDK_DATA_DIR/signet + rm -rf $BDK_DATA_DIR/regtest + XPRV=$(bdk-cli --datadir $BDK_DATA_DIR --network signet key generate | jq -r '.xprv') + echo "tr($XPRV/86h/1h/0h/0/*)" > "$BDK_DATA_DIR/.external_descriptor" + echo "tr($XPRV/86h/1h/0h/1/*)" > "$BDK_DATA_DIR/.internal_descriptor" + fi + + if [ ! -f ".tr_xprv" ]; then + BLOCKCHAININFO=$(bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet getblockchaininfo) + HEIGHT=$(echo $BLOCKCHAININFO | jq -r '.blocks') + HASH=$(echo $BLOCKCHAININFO | jq -r '.bestblockhash') + sp-cli2 create --network signet --birthday-height $HEIGHT --birthday-hash $HASH | jq -r '.tr_xprv' > ".tr_xprv" + fi + + # Start Regtest node on VM machine + just init + + export TR_XPRV=$(cat ".tr_xprv") + export EXT_DESCRIPTOR=$(cat "$BDK_DATA_DIR/.external_descriptor") + export INT_DESCRIPTOR=$(cat "$BDK_DATA_DIR/.internal_descriptor") + export EXTRA_PEER=$(bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet getpeerinfo | jq -r 'map(select(.servicesnames[] | contains ("COMPACT"))) | .[0].addr' | cut -sd ":" -f1) + + trap "bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet stop && just stop" EXIT + + if [[ -z "''${EXTRA_PEER}" ]]; then + echo "No compact block filter peers found. Ask for one." + else + echo "Compact block filter peer available: $EXTRA_PEER"; + fi + ''; + }; + default = self.devShells.${system}.workshop; + }; + } + ); +} From 02c0a1a21d3fd75fe9b529c0f6351d90fc740adf Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Fri, 17 Oct 2025 19:10:11 -0500 Subject: [PATCH 27/31] build(tabconf7): add justfile to launch workshop on regtest This commit adds a justfile to the TABConf7 workshop directory that provides a complete regtest environment setup. The file includes commands for: - Creating and managing podman containers with Bitcoin Core and supporting services - Initializing wallets for BDK and Silent Payments - Managing container lifecycle (start/stop/cleanup) - Mining blocks and interacting with the Bitcoin Core RPC - Accessing logs from various services - Connecting to Esplora, Frigate, Blindbit and a block explorer The justfile allows participants to quickly launch a local Bitcoin regtest network with all necessary tools on a sigle container. --- doc/tabconf7/justfile | 496 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 doc/tabconf7/justfile diff --git a/doc/tabconf7/justfile b/doc/tabconf7/justfile new file mode 100644 index 0000000..0254b65 --- /dev/null +++ b/doc/tabconf7/justfile @@ -0,0 +1,496 @@ +set quiet + +bdk_data_dir := env('BDK_DATA_DIR', '.bdk') + +[doc("List all available commands")] +default: + just --list --unsorted + +[group("Workshop")] +[doc("Launch ephemeral environment without checking dependencies")] +init: (start "ephemeral") _init_regtest_bdk _init_regtest_sp + +[group("Workshop")] +[doc("Ensure dependencies are installed and launch environment")] +non_nix_init: _local_install init + +[group("Silent payment wallet")] +[doc("Send a command to sp-cli2 on regtest")] +regtest-sp COMMAND *ARGS: + #!/usr/bin/env bash + export DB_PATH=".sp_cli2_regtest.db" + export RPC_PASS=$(just cookie) + export RPC_USER="__cookie__" + export RPC_URL="http://127.0.0.1:18443" + sp-cli2 {{COMMAND}} {{ARGS}} + +[group("BDK wallet")] +[doc("Send a command to bdk-cli on regtest")] +regtest-bdk COMMAND *ARGS: + #!/usr/bin/env bash + export EXT_DESCRIPTOR=$(cat "{{bdk_data_dir}}/.external_descriptor") + export INT_DESCRIPTOR=$(cat "{{bdk_data_dir}}/.internal_descriptor") + bdk-cli --datadir "{{bdk_data_dir}}" --network regtest wallet -w regtest -e "$EXT_DESCRIPTOR" -i "$INT_DESCRIPTOR" -c rpc -u http://localhost:18443/ $(just local_cookie_path) -d sqlite {{COMMAND}} {{ARGS}} + +[group("Podman")] +[doc("Set up VM to run containers")] +machine FORCE="false": + #!/usr/bin/env bash + machine_created=$(podman machine list --format json | jq -r 'map(.Name) | any(contains("sptabconf7"))') + if [ "$machine_created" = "true" ] && [ "{{FORCE}}" = "true" ]; then + echo "Machine already created, removing forcefully" + podman machine rm -f sptabconf7 + elif [ "$machine_created" = "true" ]; then + echo "Machine already created." + else + podman machine init --cpus 4 --memory 4096 --disk-size 30 sptabconf7 + fi + + just startvm + +[group("Podman")] +[doc("Build test node images")] +build TAG="1.0.0" VERSION="29.0" RELEASE="29.0": machine + #!/usr/bin/env bash + # Create virtual Containerfile by storing content in file descriptor 3 + exec 3<<- "EOF" + FROM debian:trixie-slim AS debian-builder + + # Install wget dependency + RUN apt-get update && apt-get install -y wget + + # Setup bitcoin core binaries download + ARG BITCOIN_VERSION=26.0 + ARG RELEASE=$BITCOIN_VERSION + ARG TARGET_ARCH=aarch64 + ENV BITCOIN_TARBALL=bitcoin-${BITCOIN_VERSION}-${TARGET_ARCH}.tar.gz + ENV BITCOIN_URL=https://bitcoincore.org/bin/bitcoin-core-${RELEASE}/${BITCOIN_TARBALL} + + # Install bitcoin core + WORKDIR / + RUN mkdir -p /bitcoin + RUN wget -qO- ${BITCOIN_URL} | tar -xzvf - -C /bitcoin + + FROM rust:slim-trixie AS rust-builder + RUN apt-get update && apt-get install -y pkg-config libssl-dev + RUN cargo install sccache --locked + ENV RUSTC_WRAPPER=sccache SCCACHE_DIR=/sccache + # Install dependencies for Esplora + RUN apt-get update && apt-get install -y \ + curl \ + git \ + build-essential \ + pkg-config \ + libssl-dev \ + libclang-dev \ + netcat-openbsd \ + nano \ + && rm -rf /var/lib/apt/lists/* + + # Create directory for building + RUN mkdir -p /build + + # Build Esplora and Electrum services + RUN mkdir -p /electrs + WORKDIR /electrs + RUN git clone --branch new-index --depth 1 https://github.com/Blockstream/electrs.git . + # Remove directories at the end to create smaller images + RUN --mount=type=cache,target=$SCCACHE_DIR,sharing=locked cargo build --release --bin electrs + RUN cp target/release/electrs /build + RUN rm -rf /electrs + + # Build Fast Bitcoin Block Explorer + RUN mkdir -p /fbbe + WORKDIR /fbbe + RUN git clone --depth 1 https://github.com/RCasatta/fbbe . + # Remove directories at the end to create smaller images + RUN --mount=type=cache,target=$SCCACHE_DIR,sharing=locked cargo build --release --bin fbbe + RUN cp target/release/fbbe /build + RUN rm -rf /fbbe + + # golang:trixie cannot be updated because of signature issues https://community.intel.com/t5/Intel-Fortran-Compiler/Can-t-update-in-Denian-13-Trixie/m-p/1715126 + FROM golang:bookworm as go-builder + RUN apt-get update && apt-get install wget + RUN mkdir -p /blindbit + RUN mkdir -p /build + WORKDIR /blindbit + RUN wget -qO- https://github.com/setavenger/blindbit-oracle/archive/refs/tags/indexes-stable.tar.gz | tar -xzvf - --strip-components=1 + RUN go mod download + RUN env CGO_ENABLED=0 go build -o /build/blindbit ./src + + FROM eclipse-temurin:22.0.2_9-jdk AS java-builder + RUN apt-get update && apt-get install -y git rpm fakeroot + RUN mkdir -p /build/frigate + RUN mkdir -p /frigate + WORKDIR /frigate + RUN git clone --recursive --branch 1.1.0 --depth 1 https://github.com/sparrowwallet/frigate.git . + RUN ./gradlew jpackage + RUN cp -r ./build/jpackage/frigate /build/frigate + RUN rm -rf /frigate + + FROM debian:trixie-slim + ARG BITCOIN_VERSION=26.0 + ENV PATH="$PATH:/opt/frigate/bin" + COPY --from=java-builder /build/frigate/ /opt/ + COPY --from=rust-builder /build/electrs /usr/local/bin + COPY --from=rust-builder /build/fbbe /usr/local/bin + COPY --from=go-builder build/blindbit /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-util /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-cli /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-tx /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-wallet /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/bitcoind /usr/local/bin + COPY --from=debian-builder /bitcoin/bitcoin-${BITCOIN_VERSION}/bin/test_bitcoin /usr/local/bin + + WORKDIR /home + ENTRYPOINT ["tail", "-f", "/dev/null"] + EOF + + image_exists=$(podman --connection sptabconf7 images --noheading -f reference=docker.io/nymius/sptabconf7:1.0.0 -f reference=localhost/regtest:1.0.0 --format 'table \{\{.ID\}\}') + + os=$(podman info --format json | jq -r '.host.os') + arch=$(podman info --format json | jq -r '.host.arch') + aarch=$(case $arch in + amd64) echo "x86_64" ;; + arm64) echo "aarch64" ;; + *) echo $arch + esac) + target_arch="$aarch-linux-gnu" # podman setups a linux VM for us + platform="linux/$aarch" + + pulled_blobs=$(podman --connection sptabconf7 pull --platform $platform docker://docker.io/nymius/sptabconf7:$arch-1.0.0 2>&1) + + if [ $? -ne 0 ]; then + echo "Image not found on registry" + fi + + echo $pulled_blobs | tee /dev/stderr | rg -q "WARNING" + + if [ $? -eq 0 ]; then + echo "Pulled image doesn't match host architecture" + else + echo "Pulled image ready to use" + exit + fi + + if [[ $image_exists ]]; then + echo "Image already built." + exit + else + cat <&3 | podman --connection sptabconf7 build --platform $platform --build-arg BITCOIN_VERSION={{VERSION}} --build-arg RELEASE={{RELEASE}} --build-arg TARGET_ARCH=$target_arch --tag localhost/regtest:{{TAG}} -f - + fi + + +[group("Podman")] +[doc("Create container running test node in allocated VM")] +create FORCE="false" TAG="1.0.0" NAME="RegtestBitcoinEnv": (build TAG) + #!/usr/bin/env bash + container_exists=$(podman --connection sptabconf7 ps --all --format json | jq -r '.[] | select(.Names[] | contains("RegtestBitcoinEnv")) | .Id') + if [[ $container_exists ]] && [ "{{FORCE}}" = "false" ]; then + echo "Container already exists." + exit + elif [[ $container_exists ]] && [ "{{FORCE}}" = "true" ]; then + podman --connection sptabconf7 rm -f $container_exists + fi + + arch=$(podman info --format json | jq -r '.host.arch') + + local_build=$(podman --connection sptabconf7 images --noheading -f reference=localhost/regtest:{{TAG}} --format 'table \{\{.ID\}\}' | head -n 1) + external_pull=$(podman --connection sptabconf7 images --noheading -f reference=docker.io/nymius/sptabconf7:$arch-{{TAG}} --format 'table \{\{.ID\}\}' | head -n 1) + + if [[ $local_build ]]; then + echo "Creating from local build" + podman --connection sptabconf7 create --name {{NAME}} --publish 18443:18443 --publish 18444:18444 --publish 3002:3002 --publish 3003:3003 --publish 3004:3004 --publish 60401:60401 localhost/regtest:{{TAG}} + elif [[ $external_pull ]]; then + echo "Creating from external pull" + podman --connection sptabconf7 create --name {{NAME}} --publish 18443:18443 --publish 18444:18444 --publish 3002:3002 --publish 3003:3003 --publish 3004:3004 --publish 60401:60401 docker.io/nymius/sptabconf7:$arch-{{TAG}} + fi + +[group("Podman")] +[doc("Start your podman machine")] +startvm: + #!/usr/bin/env bash + machine_running=$(podman machine list --format json | jq -r '.[] | select(.Name | contains("sptabconf7")) | .Running') + if [ "$machine_running" = "false" ]; then + podman machine start sptabconf7 | tail -n1 + else + echo "Machine is already running." + fi + +[group("Podman")] +[doc("Start your podman machine and regtest environment")] +startcontainer: (create "false" "1.0.0") + #!/usr/bin/env bash + container_state=$(podman --connection sptabconf7 ps --format json | jq -r '.[] | select(.Names[] | contains("RegtestBitcoinEnv")) | .State') + if [ "$container_state" = "running" ]; then + echo "Container is running" + exit + fi + podman --connection sptabconf7 start RegtestBitcoinEnv + +_clean_regtest_bdk: + rm -rf {{bdk_data_dir}}/regtest + +_clean_regtest_sp: + #!/usr/bin/env bash + rm -rf ".regtest_tr_xprv" + rm -rf ".sp_cli2_regtest.db" + +[group("Podman")] +[doc("Stop your podman machine and running environment")] +stop: + #!/usr/bin/env bash + echo "Stopping container" + + machine_running=$(podman machine list --format json | jq -r '.[] | select(.Name | contains("sptabconf7")) | .Running') + if [ "$machine_running" = "false" ]; then + echo "Machine is not running." + exit + fi + + container_state=$(podman --connection sptabconf7 ps --format json | jq -r '.[] | select(.Names[] | contains("RegtestBitcoinEnv")) | .State') + if [ "$container_state" != "running" ]; then + echo "Container is not running" + else + just cli stop + if just podcmd '[ -d /tmp/testenv ]'; then + just podcmd "rm -rf /tmp/testenv" + just _clean_regtest_sp + just _clean_regtest_bdk + fi + podman --connection sptabconf7 stop RegtestBitcoinEnv + fi + + podman machine stop sptabconf7 + +[group("Podman")] +[doc("Launch ephemeral environment")] +start STATE="persistent": + #!/usr/bin/env bash + trap "just stop" SIGHUP SIGINT SIGQUIT SIGTERM + just startcontainer + + ENVDIR="/root/env" + if [ "{{STATE}}" = "ephemeral" ]; then + ENVDIR="/tmp/testenv" + fi + LOGDIR="$ENVDIR/log" + + logdir=$(just podcmd "if [ ! -d $LOGDIR ]; then echo 'true'; fi") + if [ "$logdir" = "true" ]; then + # Create the log directory + just podcmd "mkdir -p $LOGDIR" + fi + + BLINDBIT_DIR="$ENVDIR/blindbit" + FRIGATE_DIR="$ENVDIR/frigate" + + BITCOIND_LOG="$LOGDIR/bitcoin.log" + BLINDBIT_LOG="$LOGDIR/blindbit.log" + FRIGATE_LOG="$LOGDIR/frigate.log" + ESPLORA_LOG="$LOGDIR/esplora.log" + FBBE_LOG="$LOGDIR/fbbe.log" + + # Start the bitcoin daemon + just podcmd "bitcoind --daemonwait --datadir=$ENVDIR --chain=regtest --txindex --blockfilterindex --peerblockfilters --rpcbind=0.0.0.0 --rpcallowip=0.0.0.0/0 --rpcport=18443 --rest -debuglogfile=$BITCOIND_LOG 2>&1" + + # Start the blockchain explorer + just podcmd "fbbe --network regtest --local-addr 0.0.0.0:3003 >> $FBBE_LOG 2>&1 &" + + # Start the Esplora and Electrum services + just podcmd "electrs -vvvv --daemon-dir $ENVDIR --db-dir $ENVDIR --http-addr 0.0.0.0:3002 --electrum-rpc-addr 0.0.0.0:60401 --network=regtest --lightmode >> $ESPLORA_LOG 2>&1 &" + + # Create Blindbit oracle config + just podcmd "mkdir -p $BLINDBIT_DIR" + podman --connection sptabconf7 exec -i RegtestBitcoinEnv /bin/bash -c "cat > $BLINDBIT_DIR/blindbit.toml" <<- EOF + # access from container host + host = "0.0.0.0:3004" + chain = "regtest" + rpc_endpoint = "http://127.0.0.1:18443" + cookie_path = "$ENVDIR/regtest/.cookie" + rpc_pass = "" + rpc_user = "" + sync_start_height = 1 + max_parallel_tweak_computations = 4 + max_parallel_requests = 4 + tweaks_only = 0 + tweaks_full_basic = 1 + tweaks_full_with_dust_filter = 1 + tweaks_cut_through_with_dust_filter = 1 + EOF + + just podcmd "blindbit --datadir $BLINDBIT_DIR >> $BLINDBIT_LOG 2>&1 &" + + just podcmd "mkdir -p $FRIGATE_DIR/regtest" + podman --connection sptabconf7 exec -i RegtestBitcoinEnv /bin/bash -c "cat > $FRIGATE_DIR/regtest/config" <<- EOF + { + "coreServer": "http://127.0.0.1:18443", + "coreAuthType": "COOKIE", + "coreDataDir": "$ENVDIR/regtest", + "coreAuth": "user:password", + "startIndexing": true, + "indexStartHeight": 0, + "scriptPubKeyCacheSize": 10000000 + } + EOF + + just podcmd "frigate --dir $FRIGATE_DIR --network regtest >> $FRIGATE_LOG 2>&1 &" + + just mine 1 + +[group("Podman")] +[doc("Get path to services state directory")] +envpath: + #!/usr/bin/env bash + ENVDIR="/tmp/testenv" + testenv=$(just podcmd "if [ -d $ENVDIR ]; then echo 'true'; fi") + if [ "$testenv" = "true" ]; then + echo $ENVDIR + else + echo "/root/env" + fi + +[group("Bitcoin Core")] +[doc("Print the current session cookie to console")] +cookie: + just podcmd "cat $(just envpath)/regtest/.cookie | cut -d ':' -f2" + +[group("Bitcoin Core")] +[doc("Write the current session cookie to file and return path")] +local_cookie_path: + #!/usr/bin/env bash + just podcmd "cat $(just envpath)/regtest/.cookie" > .regtest_cookie + echo ".regtest_cookie" + +[group("Bitcoin Core")] +[doc("Mine a block, or mine number of blocks")] +mine BLOCKS="1" ADDRESS="bcrt1q6gau5mg4ceupfhtyywyaj5ge45vgptvawgg3aq": + just cli generatetoaddress {{BLOCKS}} {{ADDRESS}} + just _waitesplora + +[group("Bitcoin Core")] +[doc("Send mining reward to
")] +sendminingrewardto ADDRESS: + just cli generatetoaddress 1 {{ADDRESS}} + +[group("Bitcoin Core")] +[doc("Send a command to bitcoin-cli")] +cli COMMAND *ARGS: + #!/usr/bin/env bash + touch /tmp/empty.conf + bitcoin-cli --conf=/tmp/empty.conf -rpcconnect=127.0.0.1 -rpcport=18443 --chain=regtest --rpcuser=__cookie__ --rpcpassword=$(just cookie) {{COMMAND}} {{ARGS}} + +[group("Logs")] +[doc("Print all logs to console")] +logs: + podman --connection sptabconf7 logs RegtestBitcoinEnv + +[group("Logs")] +[doc("Print bitcoin daemon logs to console")] +bitcoindlogs: + just podcmd "tail -f $(just envpath)/log/bitcoin.log" + +[group("Logs")] +[doc("Print Esplora logs to console")] +esploralogs: + just podcmd "tail -f $(just envpath)/log/esplora.log" + +[group("Logs")] +[doc("Print block explorer logs to console")] +explorerlogs: + just podcmd "tail -f $(just envpath)/log/fbbe.log" + +[group("Logs")] +[doc("Print blindbit logs to console")] +blindbitlogs: + just podcmd "tail -f $(just envpath)/log/blindbit.log" + +[group("Logs")] +[doc("Print frigate logs to console")] +frigatelogs: + just podcmd "tail -f $(just envpath)/log/frigate.log" + +[group("Esplora")] +[doc("Wait for esplora to update changes in blockchain")] +_waitesplora: + just podcmd "tail -n 2 --pid=\$\$ -f $(just envpath)/log/esplora.log | grep -m 1 -E 'DEBUG applying [0-9]+ new headers from height [0-9]+'" >/dev/null 2>&1 + +[group("Podman")] +[doc("Enter the shell in the pod")] +podshell: + podman --connection sptabconf7 exec -it RegtestBitcoinEnv /bin/bash + +[group("Podman")] +[doc("Execute command inside pod")] +[no-exit-message] +podcmd *ARGS="": + #!/usr/bin/env bash + containers_running=$(podman machine ls --format json | jq -r .[0].Running) + if [ "$containers_running" = "false" ]; then + echo "Container is not running" + else + podman --connection sptabconf7 exec RegtestBitcoinEnv /bin/bash -c '{{ARGS}}' + fi + +[group("Podman")] +[doc("Open the block explorer")] +explorer: + open http://127.0.0.1:3003 + +[group("Docs")] +[doc("Serve the local docs")] +servedocs: + mkdocs serve + +[group("Docs")] +[doc("Open the website for docs")] +docs: + open https://thunderbiscuit.github.io/regtest-in-a-pod/ + +[group("Bitcoin Core")] +[doc("Create a default wallet")] +createwallet: + just cli createwallet podmanwallet + just cli -rpcwallet=podmanwallet settxfee 0.0001 + +[group("Bitcoin Core")] +[doc("Print an address from the default wallet")] +newaddress: + just cli -rpcwallet=podmanwallet getnewaddress + +[group("Bitcoin Core")] +[doc("Print the balance of the default wallet")] +walletbalance: + just cli -rpcwallet=podmanwallet getbalance + +[group("Bitcoin Core")] +[doc("Send 1 bitcoin to
using the default wallet")] +sendto ADDRESS: + just cli -rpcwallet=podmanwallet sendtoaddress {{ADDRESS}} 1 + +_init_regtest_bdk: + #!/usr/bin/env bash + mkdir -p {{bdk_data_dir}} + if [ ! -f "{{bdk_data_dir}}/.external_descriptor" ] || [ ! -f "{{bdk_data_dir}}/.internal_descriptor" ]; then + rm -rf {{bdk_data_dir}}/signet + rm -rf {{bdk_data_dir}}/regtest + XPRV=$(bdk-cli --datadir {{bdk_data_dir}} --network signet key generate | jq -r '.xprv') + echo "tr($XPRV/86h/1h/0h/0/*)" > "{{bdk_data_dir}}/.external_descriptor" + echo "tr($XPRV/86h/1h/0h/1/*)" > "{{bdk_data_dir}}/.internal_descriptor" + fi + +_init_regtest_sp: + #!/usr/bin/env bash + if [ ! -f ".regtest_tr_xprv" ]; then + rm -rf ".sp_cli2_regtest.db" + BLOCKCHAININFO=$(bitcoin-cli --datadir=$BITCOIN_DATA_DIR --chain=signet getblockchaininfo) + HEIGHT=$(echo $BLOCKCHAININFO | jq -r '.blocks') + HASH=$(echo $BLOCKCHAININFO | jq -r '.bestblockhash') + DB_PATH=".sp_cli2_regtest.db" sp-cli2 create --network regtest --birthday-height $HEIGHT --birthday-hash $HASH | jq -r '.tr_xprv' > ".regtest_tr_xprv" + fi + +_local_install: + #!/usr/bin/env bash + which podman || echo "Install podman following the instructions: https://podman.io/docs/installation" + cargo install --git https://github.com/nymius/bdk-cli bdk-cli --branch feat/nix-env --all-features + cargo install --git https://github.com/nymius/bdk-sp bdk_sp_cli_v2 --branch docs/workshops --all-features From 7c4707954852c6ed1cc8f4136050c54cb67b0ada Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:49:01 -0300 Subject: [PATCH 28/31] build(tabconf7): add command playbooks for silent payment demo Add script files that guide users through setting up and using silent payments with BDK in different environments (regtest, signet, non-nix). The playbooks provide step-by-step instructions to: 1. Set up the environment 2. Fund wallets 3. Create silent payment outputs 4. Find and verify silent payment outputs 5. Create and broadcast transactions with silent payments 6. Verify change outputs 7. Spend silent payment outputs Also includes an interactive auto-playbook script that walks users through each step with colored output and guidance. These scripts serve as educational tools for the TabConf7 workshop on silent payments implementation. --- doc/tabconf7/auto_playbook.sh | 203 +++++++++++++++++++++++++++++++ doc/tabconf7/non_nix_playbook.sh | 95 +++++++++++++++ doc/tabconf7/regtest_playbook.sh | 107 ++++++++++++++++ doc/tabconf7/signet_playbook.sh | 103 ++++++++++++++++ 4 files changed, 508 insertions(+) create mode 100755 doc/tabconf7/auto_playbook.sh create mode 100644 doc/tabconf7/non_nix_playbook.sh create mode 100644 doc/tabconf7/regtest_playbook.sh create mode 100644 doc/tabconf7/signet_playbook.sh diff --git a/doc/tabconf7/auto_playbook.sh b/doc/tabconf7/auto_playbook.sh new file mode 100755 index 0000000..18bd9f5 --- /dev/null +++ b/doc/tabconf7/auto_playbook.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_stage() { + echo -e "${BLUE}==================== $1 ====================${NC}" +} + +stages=( + "STAGE 1: SETUP" + "STAGE 2: FUND BDK-CLI WALLET" + "STAGE 3: CREATE A SILENT PAYMENT OUTPUT" + "STAGE 4: FIND A SILENT PAYMENT OUTPUT" + "STAGE 5: FUND A TRANSACTION WITH A SILENT PAYMENT OUTPUT" + "STAGE 6: VERIFY A SILENT PAYMENT CHANGE OUTPUT" + "STAGE 7: SPEND A SILENT PAYMENT OUTPUT" +) + +print_step() { + echo -e "${YELLOW}Step $1: $2${NC}" + echo -e "\n${GREEN}ENTER${NC} (to execute), or ${RED}Ctrl+C${NC} (to exit)\n" +} + +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_info() { + echo -e "${BLUE}ℹ $1${NC}" +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +check_dependencies() { + local deps=("$@") + local missing_deps=() + + for dep in "${deps[@]}"; do + if ! command_exists "$dep"; then + missing_deps+=("$dep") + fi + done + + if [ ${#missing_deps[@]} -ne 0 ]; then + print_error "Missing dependencies: ${missing_deps[*]}" + echo "Please install the missing dependencies before proceeding." + return 1 + fi + + print_success "All dependencies are available: ${deps[*]}" + return 0 +} + +execute_step() { + local stage="$1" + local step_num="$2" + local description="$3" + local command="$4" + + print_stage "${stages[$stage]}" + print_step "$step_num" "$description" + printf '%s' "\$ $command" + read -r + + if eval "$command"; then + echo -e "\nPress ${GREEN}ENTER${NC} to continue to the next step" + read -r + clear + return 0 + else + print_error "Step $step_num failed" + echo "Do you want to continue anyway? (y/N)" + read -r continue_choice + if [[ ! "$continue_choice" =~ ^[Yy]$ ]]; then + exit 1 + fi + echo + return 1 + fi +} + +check_wallet_exists() { + local wallet_command="$1" + + if ! eval "$wallet_command balance" >/dev/null 2>&1; then + print_error "Wallet not accessible with command: $wallet_command" + return 1 + fi + + return 0 +} + +trap "just stop" EXIT +clear +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE} Silent Payment Demo Auto Script ${NC}" +echo -e "${BLUE}========================================${NC}" +echo + +print_info "Checking global dependencies..." +if ! check_dependencies just jq podman cargo; then + exit 1 +fi + +execute_step 0 1 "Install dependencies locally and setup regtest environment" "just non_nix_init" + +execute_step 0 2 "Check bitcoind is running on regtest" "just cli getblockchaininfo" + +execute_step 0 3 "Check bdk-cli wallet was created correctly" "just regtest-bdk balance" + +execute_step 0 4 "Check sp-cli wallet was created correctly" "just regtest-sp balance" + +execute_step 0 5 "Synchronize bdk-cli wallet" "just regtest-bdk sync" + +execute_step 1 6 "Get a new address from bdk-cli wallet" \ + "REGTEST_ADDRESS=\$(just regtest-bdk unused_address | jq -r '.address' | tr -d '\n')" + +print_info "Retrieved address: $REGTEST_ADDRESS" + +execute_step 1 7 "Mine one block to fund the wallet" "just mine 1 $REGTEST_ADDRESS" + +execute_step 1 8 "Mine 100 more blocks to confirm the balance" "just mine 100" + +execute_step 1 9 "Synchronize bdk-cli wallet" "just regtest-bdk sync" + +execute_step 1 10 "Check balance" "just regtest-bdk balance" + +execute_step 2 11 "Get a silent payment code from sp-cli2 wallet" \ + "SP_CODE=\$(just regtest-sp code | jq -r '.silent_payment_code' | tr -d '\\n')" + +print_info "Retrieved SP code: $SP_CODE" + +execute_step 2 12 "Create transaction spending bdk-cli wallet UTXOs to silent payment" \ + "RAW_TX=\$(just regtest-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee_rate 5 | jq -r '.raw_tx' | tr -d '\\n')" + +print_info "Created raw transaction" + +execute_step 2 13 "Broadcast transaction using bdk-cli wallet" \ + "TXID=\$(just regtest-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\\n')" + +print_info "Transaction ID: $TXID" + +execute_step 2 14 "Mine a new block" "just mine 1" + +execute_step 2 15 "Synchronize bdk-cli wallet again" "just regtest-bdk sync" + +execute_step 3 16 "Synchronize sp-cli2 wallet using RPC" "just regtest-sp scan-rpc" + +execute_step 3 17 "Check balance on sp-cli2 wallet" "just regtest-sp balance" + +execute_step 3 18 "Check balance on bdk-cli wallet" "just regtest-bdk balance" + +execute_step 4 19 "Get a new address from bdk-cli wallet" \ + "REGTEST_ADDRESS=\$(just regtest-bdk unused_address | jq -r '.address' | tr -d '\\n')" + +print_info "New address: $REGTEST_ADDRESS" + +execute_step 4 20 "Create new transaction with sp-cli2 spending silent payment outputs" \ + "SP_TX=\$(just regtest-sp new-tx --to $REGTEST_ADDRESS:5000 --fee-rate 5 -- \$(printf '%q' \$(cat .regtest_tr_xprv)) | jq -r '.tx' | tr -d '\\n')" + +print_info "Created SP transaction" + +execute_step 5 21 "Verify the change output derivation" " + DERIVATION_ORDER=0; + CHANGE_LABEL=0; + EXPECTED_CHANGE_SPK=\$(just regtest-sp derive-sp-for-tx \$DERIVATION_ORDER --label \$CHANGE_LABEL --tx-hex $SP_TX | jq -r '.script_pubkey_hex' | tr -d '\\n'); + TX_OUTPUT_SPKS=\$(just cli decoderawtransaction $SP_TX | jq -r '.vout[].scriptPubKey.hex' | tr '\\n' ' ' | tr -d '\\n'); + if [[ -n \$EXPECTED_CHANGE_SPK ]] && [[ \$TX_OUTPUT_SPKS == *\$EXPECTED_CHANGE_SPK* ]]; then + echo 'Change output matches!'; + else + echo 'Something went wrong...'; + fi +" + +execute_step 6 22 "Broadcast transaction" \ + "SP_TXID=\$(just cli sendrawtransaction $SP_TX | tr -d '\\n')" + +print_info "SP Transaction ID: $SP_TXID" + +execute_step 6 23 "Mine a new block" "just mine 1" + +execute_step 6 24 "Synchronize bdk-cli wallet" "just regtest-bdk sync" + +execute_step 6 25 "Synchronize sp-cli2 wallet using RPC scanning" "just regtest-sp scan-rpc" + +execute_step 6 26 "Check bdk-cli wallet balance (should have 5000 sats more)" "just regtest-bdk balance" + +execute_step 6 27 "Check sp-cli2 wallet balance (should have >5000 sats less)" "just regtest-sp balance" + +echo +print_success "Congratulations 🍻!" +echo -e "${GREEN}You have performed your first sat-round trip using silent payments on top of BDK!${NC}" +echo diff --git a/doc/tabconf7/non_nix_playbook.sh b/doc/tabconf7/non_nix_playbook.sh new file mode 100644 index 0000000..38e9bea --- /dev/null +++ b/doc/tabconf7/non_nix_playbook.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +########################### STAGE 1: setup #################################### + +# 1. Install dependencies locally and setup regtest environment +just non_nix_init +# 2. Check bitcoind is running on regtest +just cli getblockchaininfo +# 3. Check bdk-cli wallet was created correctly +just regtest-bdk balance +# 4. Check sp-cli wallet was created correctly +just regtest-sp balance +# 5. Synchronize bdk-cli wallet +just regtest-bdk sync + +###################### STAGE 2: fund bdk-cli wallet ########################### + +# 6. Get a new address from bdk-cli wallet +REGTEST_ADDRESS=$(just regtest-bdk unused_address | jq -r '.address' | tr -d '\n') +# 7. Mine a few more blocks to fund the wallet +just mine 1 $REGTEST_ADDRESS +# 8. Mine some of them to the internal wallet to confirm the bdk-cli balance +just mine 101 +# 9. Synchronize bdk-cli wallet +just regtest-bdk sync +# 10. Check balance +just regtest-bdk balance + +################ STAGE 3: create a silent payment output ###################### + +# 11. Get a silent payment code from sp-cli2 wallet +SP_CODE=$(just regtest-sp code | jq -r '.silent_payment_code' | tr -d '\n') +# 12. Create a transaction spending bdk-cli wallet UTXOs to a the previous silent payment code +RAW_TX=$(just regtest-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee_rate 5 | jq -r '.raw_tx' | tr -d '\n') +# Add an OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# RAW_TX=$(just regtest-bdk create-sp-tx --to-sp $SP_CODE:10000 --fee 5 --add_string $OP_RETURN) +# 13. Broadcast transaction using bdk-cli wallet +TXID=$(just regtest-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\n') +# 14. Mine a new block +just mine 1 +# 15. Once the new transaction has been mined, synchronize bdk-cli wallet again +just regtest-bdk sync + +################## STAGE 4: find a silent payment output ###################### + +# 16. Now synchronize sp-cli2 wallet using RPC +just regtest-sp scan-rpc +# 17. Check balance on sp-cli2 wallet +just regtest-sp balance +# 18. Check balance on bdk-cli wallet +just regtest-bdk balance + +########## STAGE 5: fund a transaction with a silent payment output ########### + +# 19. Get a new address from bdk-cli wallet +REGTEST_ADDRESS=$(just regtest-bdk unused_address | jq -r '.address' | tr -d '\n') +# 20. Create new transaction with sp-cli2 spending silent payment outputs +SP_TX=$(just regtest-sp new-tx --to $REGTEST_ADDRESS:5000 --fee-rate 5 -- $(printf '%q' $(cat .regtest_tr_xprv)) | jq -r '.tx' | tr -d '\n') +# Add a OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# SP_TX=$(just regtest-sp new-tx --to $REGTEST_ADDRESS:5000 --data $OP_RETURN --fee_rate 5 | jq -r '.tx' | tr -d '\n') + +############ STAGE 6: verify a silent payment change output ################### + +# This transaction as it is created by a silent payment wallet should have +# derived a silent payment output to receive the change back. That output is +# derived from a labelled silent payment code with label 0, the default +# specified by BIP 352 for change. +# 21. Verify the change output has been correctly derived for $SP_TX +DERIVATION_ORDER=0 +CHANGE_LABEL=0 +EXPECTED_CHANGE_SPK=$(just regtest-sp derive-sp-for-tx $DERIVATION_ORDER --label $CHANGE_LABEL --tx-hex $SP_TX | jq -r '.script_pubkey_hex' | tr -d '\n') +TX_OUTPUT_SPKS=$(just cli decoderawtransaction $SP_TX | jq -r '.vout[].scriptPubKey.hex' | tr '\n' ' ' | tr -d '\n') +if [[ -n "$EXPECTED_CHANGE_SPK" ]] && [[ $TX_OUTPUT_SPKS == *$EXPECTED_CHANGE_SPK* ]]; then + echo "Change output matches!"; +else + echo "Something went wrong..."; +fi + +################# STAGE 7: spend a silent payment output ###################### + +# 22. Broadcast transaction +SP_TXID=$(just cli sendrawtransaction $SP_TX | tr -d '\n') +# 23. Mine a new block +just mine 1 +# 24. Once the new transaction has been mined, synchronize bdk-cli wallet again +just regtest-bdk sync +# 25. Now synchronize sp-cli2 wallet using RPC scanning +just regtest-sp scan-rpc +# 26. Check bdk-cli wallet balance, should have 5000 sats more than last time we checked +just regtest-bdk balance +# 27. Check sp-cli2 wallet balance, should have >5000 sats less than last time we checked +just regtest-sp balance +# 28. Congratulations 🍻 , you have performed your first sat-round trip using silent payments on top of BDK! diff --git a/doc/tabconf7/regtest_playbook.sh b/doc/tabconf7/regtest_playbook.sh new file mode 100644 index 0000000..f22f924 --- /dev/null +++ b/doc/tabconf7/regtest_playbook.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +########################### STAGE 1: setup #################################### + +# 1. Ensure you have nix on your $PATH +which nix || curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --determinate +# 2. Create a user local configuration directory for nix +mkdir -p ~/.config/nix +# 3. Once you have nix installed enable nix flakes +echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf +# 4. Install cachix +nix-env -iA cachix -f https://cachix.org/api/v1/install +# 5. Include your user in the list of trused users +echo "trusted-users = root $USER" | sudo tee -a /etc/nix/nix.conf && sudo pkill nix-daemon +# 6. Setup sptabconf7 cachix to use substitutes for this workshop +cachix use sptabconf7 +# 7. Launch workshop environment. +nix develop . +# 8. Check bitcoind is running on regtest +regtest-cli getblockchaininfo +# 9. Check bdk-cli wallet was created correctly +regtest-bdk balance +# 10. Check sp-cli wallet was created correctly +regtest-sp balance +# 11. Synchronize bdk-cli wallet +regtest-bdk sync + +###################### STAGE 2: fund bdk-cli wallet ########################### + +# 12. Get a new address from bdk-cli wallet +REGTEST_ADDRESS=$(regtest-bdk unused_address | jq -r '.address' | tr -d '\n') +# 13. Mine a few more blocks to fund the wallet +just mine 1 $REGTEST_ADDRESS +# 14. Mine some of them to the internal wallet to confirm the bdk-cli balance +just mine 101 +# 15. Synchronize bdk-cli wallet +regtest-bdk sync +# 16. Check balance +regtest-bdk balance + +################ STAGE 3: create a silent payment output ###################### + +# 17. Get a silent payment code from sp-cli2 wallet +SP_CODE=$(regtest-sp code | jq -r '.silent_payment_code' | tr -d '\n') +# 18. Create a transaction spending bdk-cli wallet UTXOs to a the previous silent payment code +RAW_TX=$(regtest-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee_rate 5 | jq -r '.raw_tx' | tr -d '\n') +# Add a OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# RAW_TX=$(regtest-bdk create-sp-tx --to-sp $SP_CODE:10000 --fee 5 --add_string $OP_RETURN) +# 19. Broadcast transaction using bdk-cli wallet +TXID=$(regtest-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\n') +# 20. Mine a new block +just mine 1 +# 21. Once the new transaction has been mined, synchronize bdk-cli wallet again +regtest-bdk sync + +################## STAGE 4: find a silent payment output ###################### + +# 22. Now synchronize sp-cli2 wallet using RPC +regtest-sp scan-rpc +# 23. Check balance on sp-cli2 wallet +regtest-sp balance +# 24. Check balance on bdk-cli wallet +regtest-bdk balance + +########## STAGE 5: fund a transaction with a silent payment output ########### + +# 25. Get a new address from bdk-cli wallet +REGTEST_ADDRESS=$(regtest-bdk unused_address | jq -r '.address' | tr -d '\n') +# 26. Create new transaction with sp-cli2 spending silent payment outputs +SP_TX=$(regtest-sp new-tx --to $REGTEST_ADDRESS:5000 --fee-rate 5 -- $(printf '%q' $(cat .regtest_tr_xprv)) | jq -r '.tx' | tr -d '\n') +# Add a OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# SP_TX=$(regtest-sp new-tx --to $REGTEST_ADDRESS:5000 --data $OP_RETURN --fee_rate 5 | jq -r '.tx' | tr -d '\n') + +############ STAGE 6: verify a silent payment change output ################### + +# This transaction as it is created by a silent payment wallet should have +# derived a silent payment output to receive the change back. That output is +# derived from a labelled silent payment code with label 0, the default +# specified by BIP 352 for change. +# 27. Verify the change output has been correctly derived for $SP_TX +DERIVATION_ORDER=0 +CHANGE_LABEL=0 +EXPECTED_CHANGE_SPK=$(regtest-sp derive-sp-for-tx $DERIVATION_ORDER --label $CHANGE_LABEL --tx-hex $SP_TX | jq -r '.script_pubkey_hex' | tr -d '\n') +TX_OUTPUT_SPKS=$(regtest-cli decoderawtransaction $SP_TX | jq -r '.vout[].scriptPubKey.hex' | tr '\n' ' ' | tr -d '\n') +if [[ -n "$EXPECTED_CHANGE_SPK" ]] && [[ $TX_OUTPUT_SPKS == *$EXPECTED_CHANGE_SPK* ]]; then + echo "Change output matches!"; +else + echo "Something went wrong..."; +fi + +################# STAGE 7: spend a silent payment output ###################### + +# 28. Broadcast transaction +SP_TXID=$(regtest-cli sendrawtransaction $SP_TX | tr -d '\n') +# 29. Mine a new block +just mine 1 +# 30. Once the new transaction has been mined, synchronize bdk-cli wallet again +regtest-bdk sync +# 31. Now synchronize sp-cli2 wallet using RPC scanning +regtest-sp scan-rpc +# 32. Check bdk-cli wallet balance, should have 5000 sats more than last time we checked +regtest-bdk balance +# 33. Check sp-cli2 wallet balance, should have >5000 sats less than last time we checked +regtest-sp balance +# 34. Congratulations 🍻 , you have performed your first sat-round trip using silent payments on top of BDK! diff --git a/doc/tabconf7/signet_playbook.sh b/doc/tabconf7/signet_playbook.sh new file mode 100644 index 0000000..9eb9553 --- /dev/null +++ b/doc/tabconf7/signet_playbook.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +########################### STAGE 1: setup #################################### + +# 1. Ensure you have nix on your $PATH +which nix || curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --determinate +# 2. Create a user local configuration directory for nix +mkdir -p ~/.config/nix +# 3. Once you have nix installed enable nix flakes +echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf +# 4. Install cachix +nix-env -iA cachix -f https://cachix.org/api/v1/install +# 5. Include your user in the list of trused users +echo "trusted-users = root $USER" | sudo tee -a /etc/nix/nix.conf && sudo pkill nix-daemon +# 6. Setup sptabconf7 cachix to use substitutes for this workshop +cachix use sptabconf7 +# 7. Launch workshop environment. +nix develop . +# 8. Check bitcoind is running on signet +signet-cli getblockchaininfo +# 9. Check bdk-cli wallet was created correctly +signet-bdk balance +# 10. Check sp-cli wallet was created correctly +signet-sp balance +# 11. Synchronize bdk-cli wallet +signet-bdk sync + +###################### STAGE 2: fund bdk-cli wallet ########################### + +# 12. Get a new address from bdk-cli wallet +SIGNET_ADDRESS=$(signet-bdk unused_address | jq -r '.address') +# 13. Encode the address as a QR code +echo $SIGNET_ADDRESS | tr -d '\n' | qrencode -d 90 -t utf8 -o - +# 14. Use `padawan` wallet, or whatever other signet wallet to fund the bdk-cli wallet +# 15. Wait for the next block +# 16. Once the new transaction has been mined, synchronize bdk-cli wallet again +signet-bdk sync + +################ STAGE 3: create a silent payment output ###################### + +# 17. Get a silent payment code from sp-cli2 wallet +SP_CODE=$(signet-sp code | jq -r '.silent_payment_code' | tr -d '\n') +# 18. Create a transaction spending bdk-cli wallet UTXOs to the previous silent payment code +RAW_TX=$(signet-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee_rate 5 | jq -r '.raw_tx' | tr -d '\n') +# Add a OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# RAW_TX=$(signet-bdk create_sp_tx --to-sp $SP_CODE:10000 --fee 5 --add_string $OP_RETURN) +# 19. Broadcast transaction using bdk-cli wallet +TXID=$(signet-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\n') +# 20. Wait for the next block +# 21. Once the new transaction has been mined, synchronize bdk-cli wallet again +signet-bdk sync + +################## STAGE 4: find a silent payment output ###################### + +# 22. Now synchronize sp-cli2 wallet using compact block filter scanning +signet-sp scan-cbf "https://silentpayments.dev/blindbit/signet/" --extra-peer $EXTRA_PEER +# 23. Check balance on sp-cli2 wallet +signet-sp balance +# 24. Check balance on bdk-cli wallet +signet-bdk balance + +########## STAGE 5: fund a transaction with a silent payment output ########### + +# 25. Get a new address from bdk-cli wallet +SIGNET_ADDRESS=$(signet-bdk unused_address | jq -r '.address' | tr -d '\n') +# 26. Create new transaction with sp-cli2 spending silent payment outputs +SP_TX=$(signet-sp new-tx --to $SIGNET_ADDRESS:4300 --fee-rate 3 -- $TR_XPRV | jq -r '.tx' | tr -d '\n') +# Add a OP_RETURN if you want +# OP_RETURN="Spending to silent payment UTXOs using BDK 🚀 +# SP_TX=$(signet-sp new-tx --to $SIGNET_ADDRESS:5000 --data $OP_RETURN --fee_rate 5 | jq -r '.tx' | tr -d '\n') + +############ STAGE 6: verify a silent payment change output ################### + +# This transaction as it is created by a silent payment wallet should have +# derived a silent payment output to receive the change back. That output is +# derived from a labelled silent payment code with label 0, the default +# specified by BIP 352 for change. +# 27. Verify the change output has been correctly derived for $SP_TX +DERIVATION_ORDER=0 +CHANGE_LABEL=0 +EXPECTED_CHANGE_SPK=$(signet-sp derive-sp-for-tx $DERIVATION_ORDER --label $CHANGE_LABEL --tx-hex $SP_TX | jq -r '.script_pubkey_hex' | tr -d '\n') +TX_OUTPUT_SPKS=$(signet-cli decoderawtransaction $SP_TX | jq -r '.vout[].scriptPubKey.hex' | tr '\n' ' ' | tr -d '\n') +if [[ -n "$EXPECTED_CHANGE_SPK" ]] && [[ $TX_OUTPUT_SPKS == *$EXPECTED_CHANGE_SPK* ]]; then + echo "Change output matches!"; +else + echo "Something went wrong..."; +fi + +################# STAGE 7: spend a silent payment output ###################### + +# 28. Broadcast transaction +SP_TXID=$(signet-cli sendrawtransaction $SP_TX | tr -d '\n') +# 29. Wait for the next block +# 30. Once the new transaction has been mined, synchronize bdk-cli wallet again +signet-bdk sync +# 31. Now synchronize sp-cli2 wallet using compact block filter scanning +signet-sp scan-cbf "https://silentpayments.dev/blindbit/" +# 32. Check bdk-cli wallet balance, should have 5000 sats more than last time we checked +signet-bdk balance +# 33. Check sp-cli2 wallet balance, should have >5000 sats less than last time we checked +signet-sp balance +# 34. Congratulations 🍻 , you have performed your first sat-round trip using silent payments on top of BDK! From 398b18f73fb63d65909627f9d2cae837957f87ec Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:04:09 -0300 Subject: [PATCH 29/31] doc(tabconf7): add README.md for silent payments workshop The document provides essential information for workshop participants, including: - Safety notice regarding signet/regtest usage only - Workshop organization into 7 stages - Details on available playbooks based on user environments - Installation requirements for different setup options - FAQs for common issues participants might encounter This documentation ensures workshop participants can prepare and follow the correct procedures during the session. --- doc/tabconf7/README.md | 92 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 doc/tabconf7/README.md diff --git a/doc/tabconf7/README.md b/doc/tabconf7/README.md new file mode 100644 index 0000000..f14e4cd --- /dev/null +++ b/doc/tabconf7/README.md @@ -0,0 +1,92 @@ +# TABConf7: Adding Silent Payments Support to BDK + +> [!CAUTION] +> This workshop has been prepared for educative purposes. Only runs on bitcoin signet or regtest. Do not try to run it on bitcoin mainnet. + +## Organization + +> [!TIP] +> Execute the `stage 1` of your preferred playbook before participating of the workshop. Installation of dependencies takes time and depends of connectivity. + +The workshop has been packaged in different playbooks depending on your local setup and level of expertise with shell tools. + +The presentation as well as the playbooks has been structured semantically by numbered stages. The same stage achieves the same outcome on each different playbook and in the presentation. There are 7 in total: + +1. **Setup** +2. **Fund bdk-cli wallet** +3. **Create a silent payment output** +4. **Find a silent payment output** +5. **Fund a transaction with a silent payment output** +6. **Verify a silent payment change output** +7. **Spend a silent payment output** + +Each stage is composed of multiple steps, all numbered, to ensure execution order. +All seps are documented with an accompanying comment. + +> [!IMPORTANT] +> If you are following this workshop live, do not execute the commands you see on the presentation blindly! +> Follow the presentation through stages, but stick to the steps in the playbook of your choice. + +## Playbooks + +> [!TIP] +> Do not use `chmod +x script.sh && ./script.sh` to execute `signet_playbook.sh`, `regtest_playbook.sh` nor `non_nix_playbook.sh`. It will work, but is easier to debug during workshop if you execute each command separately. + +There are three intended to be executed by **copying commands** from the file to the shell: + +##### [`signet_playbook.sh`](./signet_playbook.sh) +###### Requirements: +- **nix**, the easiest way of installing it on your system is by following: [https://determinate.systems/nix-installer/](https://determinate.systems/nix-installer/). + +##### [`regtest_playbook.sh`](./regtest_playbook.sh) +###### Requirements: +- **nix**, the easiest way of installing it on your system is by following: [https://determinate.systems/nix-installer/](https://determinate.systems/nix-installer/). + +##### [`non_nix_playbook.sh`](./non_nix_playbook.sh) +###### Requirements: +- [podman](https://podman.io/docs/installation) +- [rust toolchain](https://rustup.rs/) +- [just](https://just.systems/man/en/packages.html) + +##### [`auto_playbook.sh`](./auto_playbook.sh) + +Based on [`non_nix_playbook.sh`](./non_nix_playbook.sh), directed for users not familiar with the shell, that also want to participate of the workshop. + +> [!NOTE] +> This playbook is different to the previous ones. +> It only requires you to execute it with `chmod +x auto_playbook.sh && ./auto_playbook.sh` and pressing enter as instructed by the script itself. + +###### Requirements: +- [podman](https://podman.io/docs/installation) +- [rust toolchain](https://rustup.rs/) +- [just](https://just.systems/man/en/packages.html) + +Once you have the dependencies for the playbook installed, you are ready to follow the workshop. + +Happy workshop! + +## FAQ + +
+ +How to choose what playbook to follow? + +First, try to install `nix` and execute `stage 1` of [`signet_playbook.sh`](./signet_playbook.sh). If [`nix`](https://determinate.systems/nix-installer/) is taking too long, you have issues due to your architecture or any other error you cannot figure out how to fix, try installing [`podman`](https://podman.io/docs/installation) with their indicated method for your machine, and proceed to execute `stage 1` of [`non_nix_playbook.sh`](./non_nix_playbook.sh). Please, fill an [issue](https://github.com/bitcoindevkit/bdk-sp/issues/new/choose) documenting the error on the repository to try to find a fix and improve this **FAQ**. + +
+ +
+ +On which network is the workshop running? + +If you choose [`signet_playbook.sh`](./signet_playbook.sh), you will be working with `signet`. If you choose [`regtest_playbook.sh`](./regtest_playbook.sh), [`non_nix_playbook.sh`](./non_nix_playbook.sh) or [`auto_playbook.sh`](./auto_playbook.sh) you will be working on `regtest`. There is no playbook for `testnet3`, `testnet4` nor `mainnet`. + +
+ +
+ +Signet is taking too long, what can I do? + +Choose any of the `regtest` playbooks working on your machine and follow the commands there. + +
From 2d0889ef655073c2db26a008a324e1fa15e69d6b Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:07:59 -0300 Subject: [PATCH 30/31] chore(tabconf7): add .gitignore --- doc/tabconf7/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/tabconf7/.gitignore diff --git a/doc/tabconf7/.gitignore b/doc/tabconf7/.gitignore new file mode 100644 index 0000000..97c429a --- /dev/null +++ b/doc/tabconf7/.gitignore @@ -0,0 +1,2 @@ +.* +!/.gitignore From b74ecf2484043c7d5c7f96ac4260940a665e221b Mon Sep 17 00:00:00 2001 From: nymius <155548262+nymius@users.noreply.github.com> Date: Thu, 11 Sep 2025 14:52:32 -0300 Subject: [PATCH 31/31] docs(tabconf7): add presentation slides The slides cover background information, an interactive workshop for using silent payments with BDK, technical explanations of the implementation, challenges faced, and next steps for further development. The presentation demonstrates how to spend to silent payment addresses, scan for received payments, derive silent payment outputs, verify change outputs, and spend silent payment UTXOs using various command-line tools. --- doc/tabconf7/presentation.md | 614 +++++++++++++++++++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 doc/tabconf7/presentation.md diff --git a/doc/tabconf7/presentation.md b/doc/tabconf7/presentation.md new file mode 100644 index 0000000..34d217a --- /dev/null +++ b/doc/tabconf7/presentation.md @@ -0,0 +1,614 @@ +--- +title: Integrating silent payments in BDK +sub_title: advances & challenges +author: nymius +theme: + name: tokyonight-storm # catppuccin-frappe +--- + +# Background + + +- Did some previous contributions to other sections of BDK +- Funded by BDK Foundation to focus on silent payment integration + + + +# What are we going to do? + +> Have your mobile phone at hand, we will be using [`padawan`](https://padawanwallet.com/) signet wallet during the process + +- Spend to a silent payment address with `bdk-cli` `create-sp-tx` command +- Scan received silent payments using `sp-cli2` compact block filter scanning +- Derive a silent payment output using a silent payment labelled address +- Verify the change output of a silent payment transaction was correctly derived +- Spend silent payment UTXOs using `sp-cli2` `new-tx` command + + +# Stage 1: setup + +Launch workshop environment +```bash +nix develop . +``` + + +# Stage 1: setup + +Check bitcoind is running on signet +```bash +exec +signet-cli getblockchaininfo +``` + + +# Stage 1: setup + +Check `bdk-cli` wallet was created correctly +```bash +exec +signet-bdk balance +``` + +# Stage 1: setup + +Check `sp-cli2` wallet was created correctly +```bash +exec +signet-sp balance +``` + + +# Stage 1: setup + +Synchronize `bdk-cli` wallet +```bash +exec +acquire_terminal +signet-bdk sync +``` + + +# Stage 2: fund bdk-cli wallet + +Get a new address from `bdk-cli` wallet and encode the address as a QR code + +> use `padawan` wallet, or whatever other signet wallet to fund the `bdk-cli` wallet + +```bash +exec +SIGNET_ADDRESS=$(signet-bdk unused_address | jq -r '.address' | tr -d '\n') + +echo -n $SIGNET_ADDRESS | qrencode -d 90 -t utf8 -o - +``` + + + +# Recap: silent payments recap + +> as we wait for confirmations... + +### **RECEIVER** +- publishes two public keys: + - one for shared secret derivation + - one to lock funds + +### **SENDER**: + +- hashes some transaction input data +- combines the key for shared secret derivation with the hash and produces the shared secret +- combines the shared secret with the locking key and produces the output script pubkey +- broadcast the transaction that looks like any P2TR transaction + +### **RECEIVER**: +- uses the transaction input data and the private key for shared secret derivation to produce back the shared secret +- with the shared secret and the locking public key the receiver can find its UTXOs + + +# Stage 2: fund bdk-cli wallet + +Once the transaction has been mined, synchronize `bdk-cli` wallet to become aware of the funds +```bash +exec +signet-bdk sync +``` + + +# Stage 2: fund bdk-cli wallet + +Check balance to confirm synchronization discovered the funds +```bash +exec +signet-bdk balance +``` + + +# Stage 3: create a silent payment output + +Get a silent payment code from `sp-cli2` wallet +```bash +exec +id:sp_code +SP_CODE=$(signet-sp code | jq -r '.silent_payment_code' | tr -d '\n') +/// echo $SP_CODE | xclip -sel clipboard -l 2 && xclip -sel clipboard -o > /dev/null +/// MAX_LEN=60 +/// OFFSET="\t" +/// [[ ${#SP_CODE} -le $MAX_LEN ]] && echo $SP_CODE || echo -e "$OFFSET${SP_CODE:0:$(((($MAX_LEN)/2)-3))}...${SP_CODE:$((${#SP_CODE}-(($MAX_LEN)/2)-3))}$OFFSET " +``` + + + + + +# Stage 3: create a silent payment output + + + +- `bech32m` encoded string +- The human readable part changes with the network: + - `sp` for `mainnet`. + - `tsp` for `signet`, `testnet3` and `testnet4`. + - `sprt` for `regtest`. + + +# Stage 3: create a silent payment output + +Create a transaction spending `bdk-cli` wallet UTXOs to the previous silent payment code +```bash +exec +/// SP_CODE=$(xclip -sel clipboard -o) +/// # TX=$(signet-bdk create_sp_tx --to-sp $SP_CODE:5000 --fee_rate 2) +OP_RETURN="Creating silent payment UTXOs using BDK at TABConf7 🚀" +TX=$(signet-bdk create_sp_tx --to-sp $SP_CODE:5000 --fee_rate 2 --add_string "$OP_RETURN") + +RAW_TX=$(echo $TX | jq -r '.raw_tx' | tr -d '\n') +/// echo $RAW_TX | xclip -sel clipboard -l 2 && xclip -sel clipboard -o +``` + +# Stage 3: create a silent payment output + +Broadcast transaction using `bdk-cli` wallet +```bash +exec +/// RAW_TX=$(xclip -sel clipboard -o) +TXID=$(signet-bdk broadcast --tx $RAW_TX | jq -r '.txid' | tr -d '\n') +/// echo $TXID | xclip -sel clipboard -l 2 && xclip -sel clipboard -o +``` + +# Recap: as we wait for confirmations... + +## What does `create_sp_tx` do? + +- Derives placeholder scriptpubkeys from the received silentpayment codes + +```rust +exec:rust-script +# //! ```cargo +# //! [dependencies] +# //! bdk_sp = { version = "0.1.0", git = "https://github.com/bitcoindevkit/bdk-sp", tag = "v0.1.0" } +# //! anyhow = "1" +# //! ``` +# use bdk_sp::encoding::SilentPaymentCode; +# const SP_CODE: &str = "sp1qq0u4yswlkqx36shz7j8mwt335p4el5txc8tt6yny3dqewlw4rwdqkqewtzh728u7mzkne3uf0a35mzqlm0jf4q2kgc5aakq4d04a9l734ujpez3s"; +# fn main() -> Result<(), anyhow::Error> { + let sp_code = SilentPaymentCode::try_from(SP_CODE)?; + + println!("{}", sp_code.get_placeholder_p2tr_spk()); + +# Ok(()) +# } +``` +- Creates, signs and finalizes a `PSBT` using these placeholder outputs + +```rust +let mut psbt = tx_builder.finish()?; + +wallet.sign(&mut psbt, SignOptions::default())?; +``` + + +# Recap: as we wait for confirmations... + +## What does `create_sp_tx` do? + +- Re adds to the `PSBT` the key derivation paths for each input, scrapped during PSBT finalization + +```rust +for (full_input, psbt_input) in unsigned_psbt.inputs.iter().zip(psbt.inputs.iter_mut()) +{ + psbt_input.bip32_derivation = full_input.bip32_derivation.clone(); + psbt_input.tap_key_origins = full_input.tap_key_origins.clone(); +} +``` + +- And calls `bdk_sp::send::psbt::derive_sp` + + +# Recap: as we wait for confirmations... + +## What does `bdk_sp::send::psbt::derive_sp` do? + +- Extracts public keys by looking at the prevouts and input witnesses +```rust +# Originally intended for receiving side, two rounds of signing enable it for sending too +pub fn tag_txin(txin: &TxIn, script_pubkey: &ScriptBuf) -> Option +``` +```rust +pub enum SpInputs { + /// The input spends a P2TR output. + Tr, + /// The input spends a P2WPKH output. + Wpkh, + /// The input spends a P2WPKH output nested in a P2SH. + ShWpkh, + /// The inputs spends a P2PKH output. + Pkh, +} +``` + + +# Recap: as we wait for confirmations... + +## What does `bdk_sp::send::psbt::derive_sp` do? + +- Lookups private keys again using the attached derivation paths +```rust +match pubkey_data { + (SpInputs::Tr, even_tr_output_key) => get_taproot_secret(psbt_input, k, secp) + _ => get_non_taproot_secret(psbt_input, k, secp) +} +``` +- Uses the private keys and the public data from the silent payment code to create the shared secret +```rust +pub fn create_silentpayment_partial_secret( + smallest_outpoint_bytes: &[u8; 36], + spks_with_keys: &[(ScriptBuf, SecretKey)], +) -> Result +``` + +# Recap: as we wait for confirmations... + +## What does `bdk_sp::send::psbt::derive_sp` do? + +- Derives the silent payment script pubkey outputs and replaces them +```rust +for (sp_code, x_only_pks) in silent_payments.iter() { + let placeholder_spk = sp_code.get_placeholder_p2tr_spk(); + + if let Some(indexes) = placeholder_spk_to_idx.get(&placeholder_spk) { + // Replace here + } +} +``` + +- Then retrieves control to the `create_sp_tx` command handler. + + +# Recap: as we wait for confirmations... + +## What does `create_sp_tx` do? + +- Clears transaction signatures and signs again with the new outputs +```rust +for psbt_input in psbt.inputs.iter_mut() { + psbt_input.final_script_sig = None; + psbt_input.final_script_witness = None; +} + +wallet.sign(&mut psbt, SignOptions::default())?; +``` + +- Finalizes it and publish the resultant raw transaction +```rust +let raw_tx = psbt.extract_tx()?; +``` + + +# Recap: as we wait for confirmations... + +## Why signing and finalizing before silent payment derivation? + +Avoid the premature implementation of complex key introspection logic into wallet. + +Is easier to look at the witness to find out if an input is valid for shared secret derivation. + +On finalization it's always placed in the `final_script_witness` or `final_script_sig` fields + + + +## Why re attaching key derivation paths for each input? + +Finalization removes derivation path information from the input. + +This data is needed during output derivation to find the right private keys associated with each input. + + + +## Why clearing the signatures prior to signing? + +Signatures are not created if inputs are already signed (have a signature in the expected field). + +## Why producing a raw transaction and not a PSBT? + +We don't want the transaction to be changed after the silent payments outputs are derived. + +And we don't want this to be considered a possible way to create multiparty transactions. + + + + +# Stage 4: find a silent payment output + +Now synchronize `sp-cli2` wallet using compact block filter scanning +```bash +exec +acquire_terminal +signet-sp scan-cbf "https://silentpayments.dev/blindbit/" --extra-peer $EXTRA_PEER +``` + +# Stage 4: find a silent payment output + +Once scanning is finished, check balance on `sp-cli2` wallet +```bash +exec +signet-sp balance +``` + + +# Stage 4: find a silent payment output + +Congratulations, you found the silent payment UTXO! + + +# Stage 4: find a silent payment output + +Check the balance on `bdk-cli` wallet has been discounted +```bash +exec +signet-bdk balance +``` + + +# Stage 5: fund a transaction with a silent payment output + +Get a new address from `bdk-cli` wallet +```bash +exec +SIGNET_ADDRESS=$(signet-bdk unused_address | jq -r '.address' | tr -d '\n') +/// echo $SIGNET_ADDRESS | xclip -sel clipboard -l 2 && xclip -sel clipboard -o +``` + + +# Stage 5: fund a transaction with a silent payment output + +Create new transaction with `sp-cli2` spending silent payment outputs +```bash +exec +/// SIGNET_ADDRESS=$(xclip -sel clipboard -o) +/// TR_XPRV=$(cat .tr_xprv) +/// # SP_TX=$(signet-sp new-tx --to $SIGNET_ADDRESS:1000 --fee-rate 1 -- $TR_XPRV) +AMOUNT=$(echo "$(($(signet-sp balance | jq -r '.confirmed.spendable | select(. != null)') - 3000))") +OP_RETURN="Spending silent payment UTXOs using BDK at TABConf7 🚀" +SP_TX=$(signet-sp new-tx --to $SIGNET_ADDRESS:$AMOUNT --data "$OP_RETURN" --fee-rate 2 -- $TR_XPRV) + +SP_RAW_TX=$(echo $SP_TX | jq -r '.tx' | tr -d '\n') +/// echo $SP_RAW_TX | xclip -sel clipboard -l 2 && xclip -sel clipboard -o +``` + + +# Stage 6: verify a silent payment change output + +This transaction should derive a silent payment output to receive the change back. + +The output is derived from a labelled silent payment code with label 0, the default specified by `BIP 352` for change. + +Verify the change output has been correctly derived for it with +```bash +exec +/// SP_TX=$(xclip -sel clipboard -o) +DERIVATION_ORDER=0 +CHANGE_LABEL=0 + +DERIVATION=$(signet-sp derive-sp-for-tx $DERIVATION_ORDER --label $CHANGE_LABEL --tx-hex $SP_TX) +EXPECTED_CHANGE_SPK=$(echo $DERIVATION | jq -r '.script_pubkey_hex' | tr -d '\n') + +DECODED_TX=$(signet-cli decoderawtransaction $SP_TX) +TX_OUTPUT_SPKS=$(echo $DECODED_TX | jq -r '.vout[].scriptPubKey.hex' | tr '\n' ' ' | tr -d '\n') + +if [[ -n "$EXPECTED_CHANGE_SPK" ]] && [[ $TX_OUTPUT_SPKS == *$EXPECTED_CHANGE_SPK* ]]; then + echo "Change output matches!"; +else + echo "Something went wrong..."; +fi +``` + + +# Stage 7: spend a silent payment output + +Broadcast transaction +```bash +exec +/// SP_TX=$(xclip -sel clipboard -o) +SP_TXID=$(signet-cli sendrawtransaction $SP_TX | tr -d '\n') +/// echo $SP_TXID | xclip -sel clipboard -l 2 && xclip -sel clipboard -o +``` + + +# Recap: as we wait for confirmations... + +## How does `scan-cbf` work? + +1. Synchronizes a `kyoto` cbf node +2. Listens and stores filters +3. On each filter received requests silent payment tweaks (partial secret) from `blindbit` server +4. Computes the silent payment script pubkeys from each tweak and checks against filter +5. If a match is found, request and indexes the block on the wallet +6. All this process is repeated from the birthday of the wallet up to the tip of the chain + + +# Recap: as we wait for confirmations... + +## How does `new-tx` work? + +Uses placeholder script pubkeys just as `create_sp_tx` to allow coin selection. + +Taproot key path spend for all outputs is assumed, so no prior signing nor finalization is required. + +The are no suited PSBT fields to provide the tweak data required for output derivation, so `add_sp_data_to_input` was implemented. + + +# Recap: as we wait for confirmations... + +## How does `add_sp_data_to_input` work? + +`add_sp_data_to_input` fills a propietary field into the PSBT with the spend public key of the silent payment code as key, and the tweak of that particular input as the value. + +```rust +pub fn add_sp_data_to_input( + psbt: &mut Psbt, + input_index: usize, + spend_pk: PublicKey, + tweak: Scalar, +) { + let prop_key = ProprietaryKey { + prefix: b"bip352".to_vec(), + subtype: self::SPEND_PK_SUBTYPE, + key: spend_pk.serialize().to_vec(), + }; + + let derivation_data = tweak.to_be_bytes().to_vec(); + + if let Some(input) = psbt.inputs.get_mut(input_index) { + input.proprietary.insert(prop_key, derivation_data); + } +} +``` + +Once this information is added, `new-tx` calls `derive-sp`, just as with `bdk_cli::create_sp_tx`. + + +# Recap: as we wait for confirmations... + +## Does `derive_sp` do something different? + +`derive_sp` has a gated feature just for silent payment wallets, to recognize first this field, and shortcircuit any other lookup method to derive the right private key for the input. + +```rust +if let Ok(Some(secret)) = get_sp_secret(psbt_input, k, secp) { + Some(secret) +} else { + match pubkey_data { + (SpInputs::Tr, even_tr_output_key) => get_taproot_secret(psbt_input, k, secp), + _ => get_non_taproot_secret(psbt_input, k, secp) + } +} +``` + +Finally, `new-tx` calls `sign_sp`. + + +# Recap: as we wait for confirmations... + +## How does `sign_sp` work? + +`sign_sp` is the final function that takes these inputs, extracts the tweaks from the propietary field, combines it with the spend private key and signs each of the silent payment inputs. + +```rust +pub fn sign_sp(psbt: &mut Psbt, k: &K, secp: &Secp256k1) +where + C: Signing + Verification, + K: GetKey, +``` + +Then, `new-tx` finalizes and extracts the PSBT. + + +# Stage 7: spend a silent payment output + +Once the new transaction has been mined, synchronize `bdk-cli` wallet again +```bash +exec +signet-bdk sync +``` + + +# Stage 7: spend a silent payment output + +Now synchronize `sp-cli2` wallet using compact block filter scanning +```bash +exec +acquire_terminal +signet-sp scan-cbf "https://silentpayments.dev/blindbit/" --extra-peer $EXTRA_PEER +``` + + +# Stage 7: spend a silent payment output + +Check `bdk-cli` wallet balance, should have more sats than last time we checked +```bash +exec +signet-bdk balance +``` + + +# Stage 7: spend a silent payment output + +Check `sp-cli2` wallet balance, should have less sats than last time we checked +```bash +exec +signet-sp balance +``` + + +# Stage 7: spend a silent payment output + +Congratulations 🍻 , you have performed your first sat-round trip using silent payments on top of BDK! + + +# Reflections + +## What was the target of this implementation? + +The work showed on this presentation was targeted as a quick way to provide functionality using BDK primitives. + +This enables a fast feedback loop and a good comprehension of the landscape of silent payment integration on wallets. + +This allowed the recognition of the upstream gaps and the features required on BDK. + + + +# Challenges + +- The `rust-secp256k1` bindings were WIP and the API wasn't stable. +- BDK transaction building process is PSBT centric +- Silent payment PSBT support is tricky: + - BIP 374 and BIP 375 are not finalized yet, and its implementation in `rust-psbt` was going to require more work there than in BDK + - `tweaks` used in silent payments for signing, like `bip32_derivation_path` or `tap_merkle_root`. +- BDK structures were not flexible enough: + - there's no way to index partial secrets in the current BDK `TxGraph`. + +This implied higher complexity for implementing multiparty silent payment transaction with PSBTs. + +By aiming this implementation for single party only, the goal was made fairly achievable. + + + +# Next steps + +- Implement `libsecp256k1` bindings in `rust-secp256k1`. +- Push for the specification of a new PSBT field to add silent payment tweaks in the same fashion than `bip32_derivation_path` and `tap_merkle_root`. +- Implement BIP 374 and BIP 375 features on `rust-psbt`. +- Implement `KeyRequest` for silent payments on `rust-psbt`. +- Implement `miniscript` `planning` for silent payment descriptor. +- Implement silent payment queries for `PlannedUtxo`s: `Is this UTXO available for silent payment derivation?` +- Implement the storage of meta data on BDK `TxGraph`. + + + + + +# Questions? + + + +# Contact + +- github: `nymius` +- discord: `#silent-payments` channel on [BDK server](https://discord.gg/dstn4dQ) + + + +# Resources + +- [BIP 352: Silent Payments V1](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki) +- [BIP 375: PSBTs for Silent Payments](https://github.com/bitcoin/bips/blob/master/bip-0375.mediawiki) +- [BIP 374: DLEQ for PSBT for Silent Payments](https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki) + + + + +# Thanks!