From e1ea0b940bdc4dbf8bde81121cc8b4b98d6e626e Mon Sep 17 00:00:00 2001 From: Benalleng Date: Tue, 7 Apr 2026 15:53:29 -0400 Subject: [PATCH 1/3] Add optional esplora wallet setup for payjoin-cli backend This adds a new esplora feature to use a bdk wallet as the supporting backend for payjoin-cli to reduce the need for a bitcoind rpc connection when testing against integrations. This does retain the bitcoind functionality so we can continue to run local e2e tests during the payjoin-cli CI tests. --- Cargo-minimal.lock | 1744 ++++++++--------- Cargo-recent.lock | 137 +- contrib/coverage.sh | 4 +- payjoin-cli/Cargo.toml | 23 +- payjoin-cli/contrib/lint.sh | 14 +- payjoin-cli/contrib/test.sh | 4 +- ...nfig.toml => example.bitcoind.config.toml} | 0 payjoin-cli/example.esplora.config.toml | 47 + payjoin-cli/src/app/config.rs | 48 +- payjoin-cli/src/app/mod.rs | 5 +- payjoin-cli/src/app/v1.rs | 17 +- payjoin-cli/src/app/v2/mod.rs | 12 +- payjoin-cli/src/app/wallet.rs | 740 +++++-- payjoin-cli/src/cli/mod.rs | 20 + payjoin-cli/tests/cli_esplora.rs | 60 + payjoin-cli/tests/common/mod.rs | 231 +++ payjoin-cli/tests/e2e.rs | 5 +- payjoin-cli/tests/e2e_esplora.rs | 386 ++++ 18 files changed, 2403 insertions(+), 1094 deletions(-) rename payjoin-cli/{example.config.toml => example.bitcoind.config.toml} (100%) create mode 100644 payjoin-cli/example.esplora.config.toml create mode 100644 payjoin-cli/tests/cli_esplora.rs create mode 100644 payjoin-cli/tests/common/mod.rs create mode 100644 payjoin-cli/tests/e2e_esplora.rs diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index acea0a635..cc63e66ba 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "adler2" -version = "2.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -36,7 +36,7 @@ checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", "cipher 0.3.0", - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "opaque-debug", ] @@ -63,14 +63,14 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.8.26", ] [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "anstream" -version = "1.0.0" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -107,44 +107,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.14" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "1.0.0" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.11" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arbitrary" @@ -154,9 +154,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6" +checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" dependencies = [ "rustversion", ] @@ -200,7 +200,7 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -212,7 +212,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -239,7 +239,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", "synstructure", ] @@ -251,7 +251,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -285,7 +285,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -307,9 +307,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" @@ -372,16 +372,16 @@ dependencies = [ "arc-swap", "bytes", "either", - "fs-err 3.3.0", + "fs-err 3.2.2", "http", "http-body", "hyper", "hyper-util", "pin-project-lite", - "rustls 0.23.37", + "rustls 0.23.31", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.2", "tower-service", ] @@ -392,7 +392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.0", ] [[package]] @@ -431,14 +431,14 @@ dependencies = [ "async-trait", "bdk-macros", "bip39", - "bitcoin 0.30.3", + "bitcoin 0.30.2", "core-rpc", - "electrum-client", - "esplora-client", - "getrandom 0.2.17", + "electrum-client 0.18.0", + "esplora-client 0.6.0", + "getrandom 0.2.15", "js-sys", "log", - "miniscript", + "miniscript 10.2.3", "rand 0.8.5", "serde", "serde_json", @@ -457,6 +457,55 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bdk_chain" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c290eff038799a8ac0c5a82b6160a9ca456baa299a6f22b262c771342d2846c0" +dependencies = [ + "bdk_core", + "bitcoin 0.32.8", + "miniscript 12.3.5", + "serde", +] + +[[package]] +name = "bdk_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3028782f6bf14a6df987244333d34e6b272b5a40a53e4879ec2dfd82275a3a" +dependencies = [ + "bitcoin 0.32.8", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "bdk_esplora" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83986307ea92997c3d051e8c306af8115a05add601e22acb7c1903008e6b614e" +dependencies = [ + "async-trait", + "bdk_core", + "esplora-client 0.12.3", + "futures", +] + +[[package]] +name = "bdk_wallet" +version = "3.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b989a12f0398a844bf22b14a197e2676aea2775aabca52057627f596ad3a0ef" +dependencies = [ + "bdk_chain", + "bitcoin 0.32.8", + "miniscript 12.3.5", + "rand_core 0.6.4", + "serde", + "serde_json", +] + [[package]] name = "bech32" version = "0.9.1" @@ -465,9 +514,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bech32" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bhttp" @@ -475,32 +524,31 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16fc24bc615b9fd63148f59b218ea58a444b55762f8845da910e23aca686398b" dependencies = [ - "thiserror 1.0.69", + "thiserror 1.0.63", "url", ] [[package]] name = "bip39" -version = "2.2.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" +checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" dependencies = [ - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.13.0", "serde", "unicode-normalization", ] [[package]] name = "bitcoin" -version = "0.30.3" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f50161c4b69a2c8fd7d5d7d8b58bb83900a7ba7080010014cca7a80fe56d1d" +checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "base64 0.13.1", "bech32 0.9.1", "bitcoin-private", "bitcoin_hashes 0.12.0", - "hex-conservative 0.2.2", "hex_lit", "secp256k1 0.27.0", "serde", @@ -514,11 +562,11 @@ checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ "base58ck", "base64 0.21.7", - "bech32 0.11.1", + "bech32 0.11.0", "bitcoin-internals 0.3.0", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.0", "hex-conservative 0.2.2", "hex_lit", "secp256k1 0.29.1", @@ -539,7 +587,7 @@ dependencies = [ "hmac 0.12.1", "rand_core 0.6.4", "secp256k1 0.29.1", - "sha2 0.10.9", + "sha2 0.10.8", "subtle", "zeroize", ] @@ -550,6 +598,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b" +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + [[package]] name = "bitcoin-internals" version = "0.3.0" @@ -561,9 +615,9 @@ dependencies = [ [[package]] name = "bitcoin-io" -version = "0.1.4" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" [[package]] name = "bitcoin-ohttp" @@ -584,7 +638,7 @@ dependencies = [ "serde", "serde_derive", "sha2 0.9.9", - "thiserror 1.0.69", + "thiserror 1.0.63", "toml 0.5.11", ] @@ -616,9 +670,19 @@ dependencies = [ [[package]] name = "bitcoin_hashes" -version = "0.14.1" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals 0.2.0", + "hex-conservative 0.1.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ "bitcoin-io", "hex-conservative 0.2.2", @@ -662,11 +726,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -702,9 +766,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -714,9 +778,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bzip2" @@ -730,21 +794,22 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.13+1.0.8" +version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ "cc", + "libc", "pkg-config", ] [[package]] name = "camino" -version = "1.2.2" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -767,7 +832,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 1.0.63", ] [[package]] @@ -786,21 +851,20 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.59" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" dependencies = [ - "find-msvc-tools", "jobserver", "libc", - "shlex", + "once_cell", ] [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" @@ -828,18 +892,7 @@ checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher 0.4.4", - "cpufeatures 0.2.17", -] - -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.0", + "cpufeatures 0.2.14", ] [[package]] @@ -870,14 +923,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -919,23 +972,23 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" dependencies = [ "clap_builder", - "clap_derive 4.6.0", + "clap_derive 4.5.45", ] [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" dependencies = [ "anstream", "anstyle", - "clap_lex 1.1.0", + "clap_lex 0.7.5", "strsim 0.11.1", ] @@ -954,14 +1007,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -975,30 +1028,30 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" -version = "3.1.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "config" -version = "0.15.22" +version = "0.15.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68cfe19cd7d23ffde002c24ffa5cda73931913ef394d5eaaa32037dc940c0c" +checksum = "aa4092bf3922a966e2bd74640b80f36c73eaa7251a4fd0fbcda1f8a4de401352" dependencies = [ "async-trait", "convert_case", @@ -1006,11 +1059,11 @@ dependencies = [ "pathdiff", "ron", "rust-ini", + "serde", "serde-untagged", - "serde_core", "serde_json", - "toml 1.1.2+spec-1.1.0", - "winnow 1.0.1", + "toml 0.9.5", + "winnow", "yaml-rust2", ] @@ -1029,7 +1082,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] @@ -1079,7 +1132,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581898ed9a83f31c64731b1d8ca2dfffcfec14edf1635afacd5234cddbde3a41" dependencies = [ - "bitcoin 0.30.3", + "bitcoin 0.30.2", "bitcoin-private", "serde", "serde_json", @@ -1101,12 +1154,12 @@ dependencies = [ [[package]] name = "corepc-node" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768391062ec3812e223bb3031c5b2fcdd6e0e60b816157f21df82fd3e6617dc0" +checksum = "69bd382fc775f760a8b55d658527621b890eaa3d8e8bc9779864659b172e81c6" dependencies = [ "anyhow", - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.0", "corepc-client", "flate2", "log", @@ -1140,27 +1193,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.3.0" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -1176,9 +1220,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1188,9 +1232,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1237,7 +1281,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -1248,14 +1292,14 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der-parser" @@ -1273,9 +1317,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1330,7 +1374,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -1363,13 +1407,29 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "electrsd" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8926868af723c2819807809e54585992aaea0e26a6f5089ac8c2598eaec8d01" +dependencies = [ + "bitcoin_hashes 0.14.0", + "corepc-client", + "corepc-node", + "electrum-client 0.24.1", + "log", + "minreq", + "nix 0.25.1", + "zip", +] + [[package]] name = "electrum-client" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bc133f1c8d829d254f013f946653cbeb2b08674b960146361d1e9b67733ad19" dependencies = [ - "bitcoin 0.30.3", + "bitcoin 0.30.2", "bitcoin-private", "byteorder", "libc", @@ -1382,6 +1442,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "electrum-client" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" +dependencies = [ + "bitcoin 0.32.8", + "log", + "serde", + "serde_json", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1399,23 +1471,22 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.10" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", - "serde_core", "typeid", ] [[package]] name = "errno" -version = "0.3.14" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1424,13 +1495,28 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cb1f7f2489cce83bc3bd92784f9ba5271eeb6e729b975895fc541f78cbfcdca" dependencies = [ - "bitcoin 0.30.3", + "bitcoin 0.30.2", "bitcoin-internals 0.1.0", "log", "serde", "ureq", ] +[[package]] +name = "esplora-client" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f19e3ea99dbfbef0c1ec26d83e69de0c579f6aa6aaac4f44597805fcc27e97af" +dependencies = [ + "bitcoin 0.32.8", + "hex-conservative 0.2.2", + "log", + "reqwest", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "extend" version = "1.2.0" @@ -1439,7 +1525,7 @@ checksum = "311a6d2f1f9d60bff73d2c78a0af97ed27f79672f15c238192a5bbb64db56d00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -1456,27 +1542,22 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "filetime" -version = "0.2.27" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", "libredox", + "windows-sys 0.59.0", ] -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - [[package]] name = "flate2" version = "1.1.9" @@ -1519,9 +1600,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "3.3.0" +version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fde052dbfc920003cfd2c8e2c6e6d4cc7c1091538c3a24226cec0665ab08c0" +checksum = "baf68cef89750956493a66a10f512b9e58d9db21f2a573c079c0bdf1207a54a7" dependencies = [ "autocfg", "tokio", @@ -1539,9 +1620,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1554,9 +1635,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1564,15 +1645,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1581,38 +1662,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1622,6 +1703,7 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", + "pin-utils", "slab", ] @@ -1653,7 +1735,7 @@ checksum = "43eaff6bbc0b3a878361aced5ec6a2818ee7c541c5b33b5880dfa9a86c23e9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -1668,45 +1750,31 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi 5.3.0", - "wasip2", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "rand_core 0.10.0", - "wasip2", - "wasip3", -] - [[package]] name = "ghash" version = "0.4.4" @@ -1736,9 +1804,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -1746,7 +1814,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.13.1", + "indexmap 2.10.0", "slab", "tokio", "tokio-util", @@ -1767,6 +1835,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", + "serde", ] [[package]] @@ -1778,12 +1847,6 @@ dependencies = [ "foldhash", ] -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - [[package]] name = "hashlink" version = "0.8.4" @@ -1899,11 +1962,12 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", + "fnv", "itoa", ] @@ -1932,9 +1996,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.10.1" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1944,9 +2008,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.9.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", @@ -1959,6 +2023,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1973,13 +2038,13 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.37", + "rustls 0.23.31", "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 1.0.6", + "webpki-roots 1.0.2", ] [[package]] @@ -1999,7 +2064,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.6.0", "tokio", "tower-service", "tracing", @@ -2007,9 +2072,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.65" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2031,9 +2096,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", @@ -2057,10 +2122,11 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33747cecc725eebb47ac503fab725e395d50cb7889ae490a1359f130611d4cc5" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ + "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2071,29 +2137,31 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d70f9b6574c79f7a83ea5ce72cc88d271a3e77355c5f7748a107e751d8617fb" +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.1.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -2112,12 +2180,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -2158,14 +2220,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.15.5", "serde", - "serde_core", ] [[package]] @@ -2188,9 +2249,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "ipnetwork" @@ -2200,9 +2261,9 @@ checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763" [[package]] name = "iri-string" -version = "0.7.12" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" dependencies = [ "memchr", "serde", @@ -2210,9 +2271,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2225,9 +2286,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" @@ -2235,18 +2296,16 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ - "cfg-if", - "futures-util", "once_cell", "wasm-bindgen", ] @@ -2291,23 +2350,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" -version = "0.2.184" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" -version = "0.4.12" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", @@ -2315,14 +2368,13 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "libc", - "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.5.3", ] [[package]] @@ -2338,15 +2390,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.12.1" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" @@ -2356,18 +2414,19 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.14" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.29" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru-slab" @@ -2405,9 +2464,18 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -2427,11 +2495,22 @@ version = "10.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e88ef03cc0ce21bcf584da157890b292fc4b69bfeaa4e9d41bbf492da59b22f" dependencies = [ - "bitcoin 0.30.3", + "bitcoin 0.30.2", "bitcoin-private", "serde", ] +[[package]] +name = "miniscript" +version = "12.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" +dependencies = [ + "bech32 0.11.0", + "bitcoin 0.32.8", + "serde", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2444,10 +2523,12 @@ dependencies = [ [[package]] name = "minreq" -version = "2.14.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" +checksum = "763d142cdff44aaadd9268bebddb156ef6c65a0e13486bb81673cf2d8739f9b0" dependencies = [ + "log", + "once_cell", "rustls 0.21.12", "rustls-webpki 0.101.7", "serde", @@ -2457,20 +2538,20 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", - "windows-sys 0.61.2", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "mockito" -version = "1.7.2" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90820618712cab19cfc46b274c6c22546a82affcb3c3bdf0f29e3db8e1bb92c0" +checksum = "7e0603425789b4a70fcc4ac4f5a46a566c116ee3e2a6b768dc623f7719c611de" dependencies = [ "assert-json-diff", "bytes", @@ -2483,7 +2564,7 @@ dependencies = [ "hyper-util", "log", "pin-project-lite", - "rand 0.9.2", + "rand 0.9.1", "regex", "serde_json", "serde_urlencoded", @@ -2491,6 +2572,20 @@ dependencies = [ "tokio", ] +[[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 = "nix" version = "0.26.4" @@ -2508,7 +2603,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -2579,15 +2674,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.4" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "opaque-debug" @@ -2597,9 +2692,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" -version = "0.2.1" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "opentelemetry" @@ -2630,9 +2725,9 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.31.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ "http", "opentelemetry", @@ -2669,7 +2764,7 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.2", + "rand 0.9.1", "thiserror 2.0.18", "tokio", "tokio-stream", @@ -2710,12 +2805,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.5" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.12", + "parking_lot_core 0.9.11", ] [[package]] @@ -2734,15 +2829,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.12" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.18", + "redox_syscall 0.5.3", "smallvec", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -2753,9 +2848,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "payjoin" @@ -2770,7 +2865,7 @@ dependencies = [ "once_cell", "payjoin-test-utils", "reqwest", - "rustls 0.23.37", + "rustls 0.23.31", "serde", "serde_json", "tokio", @@ -2785,10 +2880,14 @@ version = "0.2.0" dependencies = [ "anyhow", "async-trait", + "bdk_esplora", + "bdk_wallet", "bitcoind-async-client", - "clap 4.6.0", + "clap 4.5.46", "config", "dirs", + "electrsd", + "esplora-client 0.12.3", "http-body-util", "hyper", "hyper-util", @@ -2803,7 +2902,7 @@ dependencies = [ "serde_json", "tempfile", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.2", "tracing", "tracing-subscriber", "url", @@ -2816,7 +2915,7 @@ dependencies = [ "async-trait", "bdk", "bitcoin-ohttp", - "getrandom 0.2.17", + "getrandom 0.2.15", "icu_locale_core", "icu_provider", "lazy_static", @@ -2855,7 +2954,7 @@ dependencies = [ "bitcoin-ohttp", "byteorder", "bytes", - "clap 4.6.0", + "clap 4.5.46", "config", "flate2", "futures", @@ -2876,12 +2975,12 @@ dependencies = [ "rand 0.8.5", "rcgen 0.12.1", "reqwest", - "rustls 0.23.37", + "rustls 0.23.31", "serde", "tempfile", "tokio", "tokio-listener", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.2", "tokio-rustls-acme", "tokio-stream", "tokio-tungstenite", @@ -2904,9 +3003,9 @@ dependencies = [ "once_cell", "payjoin", "payjoin-mailroom", - "rcgen 0.14.7", + "rcgen 0.14.3", "reqwest", - "rustls 0.23.37", + "rustls 0.23.31", "tempfile", "time", "tokio", @@ -2916,12 +3015,12 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.6" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ "base64 0.22.1", - "serde_core", + "serde", ] [[package]] @@ -2938,19 +3037,20 @@ checksum = "3637c05577168127568a64e9dc5a6887da720efef07b3d9472d45f63ab191166" [[package]] name = "pest" -version = "2.8.6" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", + "thiserror 1.0.63", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" dependencies = [ "pest", "pest_generator", @@ -2958,52 +3058,53 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" dependencies = [ + "once_cell", "pest", - "sha2 0.10.9", + "sha2 0.10.8", ] [[package]] name = "pin-project" -version = "1.1.11" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.11" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "pin-project-lite" -version = "0.2.17" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3013,9 +3114,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -3029,7 +3130,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "opaque-debug", "universal-hash 0.4.0", ] @@ -3040,7 +3141,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "opaque-debug", "universal-hash 0.5.1", ] @@ -3052,16 +3153,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "opaque-debug", "universal-hash 0.4.0", ] [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" dependencies = [ "zerovec", ] @@ -3074,21 +3175,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.21" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", + "zerocopy 0.7.35", ] [[package]] @@ -3117,9 +3208,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -3144,14 +3235,14 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -3159,8 +3250,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.37", - "socket2 0.6.3", + "rustls 0.23.31", + "socket2 0.5.10", "thiserror 2.0.18", "tokio", "tracing", @@ -3169,17 +3260,17 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.3.3", "lru-slab", - "rand 0.9.2", + "rand 0.9.1", "ring", "rustc-hash", - "rustls 0.23.37", + "rustls 0.23.31", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -3190,23 +3281,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2 0.5.10", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -3217,12 +3308,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "r2d2" version = "0.8.10" @@ -3230,7 +3315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot 0.12.5", + "parking_lot 0.12.3", "scheduled-thread-pool", ] @@ -3258,23 +3343,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" -dependencies = [ - "chacha20 0.10.0", - "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.9.3", ] [[package]] @@ -3294,7 +3368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -3303,24 +3377,18 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.15", ] [[package]] name = "rand_core" -version = "0.9.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", ] -[[package]] -name = "rand_core" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" - [[package]] name = "rcgen" version = "0.12.1" @@ -3335,15 +3403,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.14.7" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" +checksum = "0068c5b3cab1d4e271e0bb6539c87563c43411cad90b057b15c79958fbeb41f7" dependencies = [ "pem", "ring", "rustls-pki-types", "time", - "x509-parser", + "x509-parser 0.17.0", "yasna", ] @@ -3358,20 +3426,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.11.0", -] - -[[package]] -name = "redox_syscall" -version = "0.7.3" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", ] [[package]] @@ -3380,7 +3439,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.15", "libredox", "thiserror 2.0.18", ] @@ -3402,14 +3461,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -3419,9 +3478,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3430,9 +3489,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -3462,7 +3521,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.37", + "rustls 0.23.31", "rustls-native-certs", "rustls-pki-types", "serde", @@ -3470,7 +3529,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.2", "tower", "tower-http", "tower-service", @@ -3478,35 +3537,34 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.6", + "webpki-roots 1.0.2", ] [[package]] name = "ring" -version = "0.17.14" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.17", + "getrandom 0.2.15", "libc", + "spin", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "ron" -version = "0.12.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "bitflags 2.11.0", - "once_cell", + "base64 0.21.7", + "bitflags 2.6.0", "serde", "serde_derive", - "typeid", - "unicode-ident", ] [[package]] @@ -3515,7 +3573,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink 0.8.4", @@ -3525,19 +3583,20 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.21.3" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" dependencies = [ "cfg-if", "ordered-multimap", + "trim-in-place", ] [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rusticata-macros" @@ -3550,15 +3609,28 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.61.2", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", ] [[package]] @@ -3575,24 +3647,24 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.10", + "rustls-webpki 0.103.4", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -3602,9 +3674,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", "zeroize", @@ -3622,9 +3694,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -3639,17 +3711,17 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.23" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.29" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3658,7 +3730,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "parking_lot 0.12.5", + "parking_lot 0.12.3", ] [[package]] @@ -3675,9 +3747,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -3708,7 +3780,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -3739,9 +3811,9 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.1", + "bitcoin_hashes 0.14.0", "rand 0.8.5", - "secp256k1-sys 0.10.1", + "secp256k1-sys 0.10.0", "serde", ] @@ -3756,20 +3828,20 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" dependencies = [ "cc", ] [[package]] name = "security-framework" -version = "3.7.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -3778,9 +3850,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.17.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -3788,12 +3860,11 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", - "serde_core", ] [[package]] @@ -3808,13 +3879,12 @@ dependencies = [ [[package]] name = "serde-untagged" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3" dependencies = [ "erased-serde", "serde", - "serde_core", "typeid", ] @@ -3835,7 +3905,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -3864,11 +3934,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -3885,17 +3955,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.17.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.1", + "indexmap 2.10.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.0", "serde_core", "serde_json", "serde_with_macros", @@ -3904,14 +3974,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.17.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -3921,7 +3991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "digest 0.10.7", ] @@ -3933,19 +4003,19 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "digest 0.9.0", "opaque-debug", ] [[package]] name = "sha2" -version = "0.10.9" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures 0.2.14", "digest 0.10.7", ] @@ -3958,27 +4028,20 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" -version = "1.4.8" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ - "errno", "libc", ] [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "similar" @@ -3994,9 +4057,12 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.12" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "sled" @@ -4016,9 +4082,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smawk" @@ -4038,12 +4104,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4057,11 +4123,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "stable_deref_trait" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" @@ -4112,9 +4184,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -4138,14 +4210,14 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "tar" -version = "0.4.45" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -4154,15 +4226,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.27.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.3", "once_cell", - "rustix", - "windows-sys 0.61.2", + "rustix 1.0.7", + "windows-sys 0.59.0", ] [[package]] @@ -4187,11 +4259,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.69" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl 1.0.69", + "thiserror-impl 1.0.63", ] [[package]] @@ -4205,13 +4277,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -4222,16 +4294,17 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", + "once_cell", ] [[package]] @@ -4276,20 +4349,19 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", - "serde_core", "zerovec", ] [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -4302,17 +4374,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.51.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", "mio", - "parking_lot 0.12.5", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2 0.6.0", "tokio-macros", "windows-sys 0.61.2", ] @@ -4339,13 +4411,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -4360,11 +4432,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.37", + "rustls 0.23.31", "tokio", ] @@ -4383,25 +4455,25 @@ dependencies = [ "num-bigint", "pem", "proc-macro2", - "rcgen 0.14.7", + "rcgen 0.14.3", "reqwest", "ring", - "rustls 0.23.37", + "rustls 0.23.31", "serde", "serde_json", "thiserror 2.0.18", "time", "tokio", - "tokio-rustls 0.26.4", - "webpki-roots 1.0.6", - "x509-parser", + "tokio-rustls 0.26.2", + "webpki-roots 1.0.2", + "x509-parser 0.18.0", ] [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -4422,9 +4494,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -4444,70 +4516,48 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ - "indexmap 2.13.1", - "serde_core", + "indexmap 2.10.0", + "serde", "serde_spanned", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 0.7.15", -] - -[[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" -dependencies = [ - "serde_core", - "serde_spanned", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ - "serde_core", + "serde", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" dependencies = [ - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" -version = "0.14.5" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" +checksum = "a286e33f82f8a1ee2df63f4fa35c0becf4a85a0cb03091a15fd7bf0b402dc94a" dependencies = [ "async-trait", "base64 0.22.1", @@ -4526,9 +4576,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.5" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +checksum = "d6c55a2d6a14174563de34409c9f92ff981d006f56da9c6ecd40d9d4a31500b0" dependencies = [ "bytes", "prost", @@ -4537,9 +4587,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", @@ -4557,7 +4607,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.6.0", "bytes", "futures-util", "http", @@ -4583,9 +4633,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.44" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -4595,20 +4645,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.31" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.36" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -4637,9 +4687,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.23" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", @@ -4656,6 +4706,12 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "try-lock" version = "0.2.5" @@ -4673,7 +4729,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.2", + "rand 0.9.1", "sha1", "thiserror 2.0.18", "utf-8", @@ -4687,21 +4743,21 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" @@ -4711,9 +4767,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.25" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -4730,12 +4786,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "uniffi" version = "0.30.0" @@ -4745,7 +4795,7 @@ dependencies = [ "anyhow", "camino", "cargo_metadata 0.19.2", - "clap 4.6.0", + "clap 4.5.46", "uniffi_bindgen", "uniffi_build", "uniffi_core", @@ -4770,7 +4820,7 @@ dependencies = [ "serde", "serde_json", "textwrap", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.5", "uniffi_bindgen", "uniffi_meta", "uniffi_udl", @@ -4791,7 +4841,7 @@ dependencies = [ "proc-macro2", "serde", "stringcase 0.4.0", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.5", "uniffi", "uniffi_bindgen", "uniffi_dart_macro", @@ -4811,12 +4861,12 @@ dependencies = [ "glob", "goblin", "heck 0.5.0", - "indexmap 2.13.1", + "indexmap 2.10.0", "once_cell", "serde", "tempfile", "textwrap", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.5", "uniffi_internal_macros", "uniffi_meta", "uniffi_pipeline", @@ -4867,10 +4917,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c2a6f93e7b73726e2015696ece25ca0ac5a5f1cf8d6a7ab5214dd0a01d2edf" dependencies = [ "anyhow", - "indexmap 2.13.1", + "indexmap 2.10.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -4885,8 +4935,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.117", - "toml 0.9.12+spec-1.1.0", + "syn 2.0.106", + "toml 0.9.5", "uniffi_meta", ] @@ -4910,7 +4960,7 @@ checksum = "8c27c4b515d25f8e53cc918e238c39a79c3144a40eaf2e51c4a7958973422c29" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.13.1", + "indexmap 2.10.0", "tempfile", "uniffi_internal_macros", ] @@ -4963,7 +5013,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.37", + "rustls 0.23.31", "rustls-pki-types", "serde", "serde_json", @@ -4974,15 +5024,14 @@ dependencies = [ [[package]] name = "url" -version = "2.5.8" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", - "serde_derive", ] [[package]] @@ -5005,21 +5054,21 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.3.3", "js-sys", - "rand 0.10.0", + "rand 0.9.1", "wasm-bindgen", ] [[package]] name = "valuable" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vcpkg" @@ -5044,56 +5093,62 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ - "wit-bindgen", + "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.67" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ + "cfg-if", "js-sys", "wasm-bindgen", + "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5101,65 +5156,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ - "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", + "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.1", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.15.5", - "indexmap 2.13.1", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.94" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -5206,14 +5227,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.6", + "webpki-roots 1.0.2", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] @@ -5275,7 +5296,7 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.2.1", "windows-result", "windows-strings", ] @@ -5288,7 +5309,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -5299,9 +5320,15 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] +[[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.1" @@ -5314,7 +5341,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -5323,7 +5350,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -5350,7 +5377,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.5", + "windows-targets 0.53.3", ] [[package]] @@ -5359,7 +5386,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -5380,19 +5407,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.5" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "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]] @@ -5403,9 +5430,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" @@ -5415,9 +5442,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" @@ -5427,9 +5454,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" @@ -5439,9 +5466,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" @@ -5451,9 +5478,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" @@ -5463,9 +5490,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" @@ -5475,9 +5502,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" @@ -5487,127 +5514,57 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.15" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] -name = "winnow" -version = "1.0.1" +name = "wit-bindgen-rt" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.13.1", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", + "bitflags 2.6.0", ] [[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" +name = "writeable" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.1", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] -name = "wit-parser" -version = "0.244.0" +name = "x509-parser" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.1", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.18", + "time", ] -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - [[package]] name = "x509-parser" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425" dependencies = [ "asn1-rs", "data-encoding", @@ -5615,7 +5572,6 @@ dependencies = [ "lazy_static", "nom", "oid-registry", - "ring", "rusticata-macros", "thiserror 2.0.18", "time", @@ -5623,19 +5579,20 @@ dependencies = [ [[package]] name = "xattr" -version = "1.6.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "rustix", + "linux-raw-sys 0.4.14", + "rustix 0.38.36", ] [[package]] name = "yaml-rust2" -version = "0.10.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9" +checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7" dependencies = [ "arraydeque", "encoding_rs", @@ -5653,10 +5610,11 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ + "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5664,82 +5622,103 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive 0.8.26", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ "displaydoc", "yoke", @@ -5748,11 +5727,10 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ - "serde", "yoke", "zerofrom", "zerovec-derive", @@ -5760,13 +5738,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.106", ] [[package]] @@ -5784,6 +5762,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 2f6135d72..cc63e66ba 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -433,12 +433,12 @@ dependencies = [ "bip39", "bitcoin 0.30.2", "core-rpc", - "electrum-client", - "esplora-client", + "electrum-client 0.18.0", + "esplora-client 0.6.0", "getrandom 0.2.15", "js-sys", "log", - "miniscript", + "miniscript 10.2.3", "rand 0.8.5", "serde", "serde_json", @@ -457,6 +457,55 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bdk_chain" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c290eff038799a8ac0c5a82b6160a9ca456baa299a6f22b262c771342d2846c0" +dependencies = [ + "bdk_core", + "bitcoin 0.32.8", + "miniscript 12.3.5", + "serde", +] + +[[package]] +name = "bdk_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3028782f6bf14a6df987244333d34e6b272b5a40a53e4879ec2dfd82275a3a" +dependencies = [ + "bitcoin 0.32.8", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "bdk_esplora" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83986307ea92997c3d051e8c306af8115a05add601e22acb7c1903008e6b614e" +dependencies = [ + "async-trait", + "bdk_core", + "esplora-client 0.12.3", + "futures", +] + +[[package]] +name = "bdk_wallet" +version = "3.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b989a12f0398a844bf22b14a197e2676aea2775aabca52057627f596ad3a0ef" +dependencies = [ + "bdk_chain", + "bitcoin 0.32.8", + "miniscript 12.3.5", + "rand_core 0.6.4", + "serde", + "serde_json", +] + [[package]] name = "bech32" version = "0.9.1" @@ -1358,6 +1407,22 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "electrsd" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8926868af723c2819807809e54585992aaea0e26a6f5089ac8c2598eaec8d01" +dependencies = [ + "bitcoin_hashes 0.14.0", + "corepc-client", + "corepc-node", + "electrum-client 0.24.1", + "log", + "minreq", + "nix 0.25.1", + "zip", +] + [[package]] name = "electrum-client" version = "0.18.0" @@ -1377,6 +1442,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "electrum-client" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" +dependencies = [ + "bitcoin 0.32.8", + "log", + "serde", + "serde_json", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1425,6 +1502,21 @@ dependencies = [ "ureq", ] +[[package]] +name = "esplora-client" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f19e3ea99dbfbef0c1ec26d83e69de0c579f6aa6aaac4f44597805fcc27e97af" +dependencies = [ + "bitcoin 0.32.8", + "hex-conservative 0.2.2", + "log", + "reqwest", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "extend" version = "1.2.0" @@ -1743,6 +1835,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", + "serde", ] [[package]] @@ -2375,6 +2468,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[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" @@ -2398,6 +2500,17 @@ dependencies = [ "serde", ] +[[package]] +name = "miniscript" +version = "12.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" +dependencies = [ + "bech32 0.11.0", + "bitcoin 0.32.8", + "serde", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2459,6 +2572,20 @@ dependencies = [ "tokio", ] +[[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 = "nix" version = "0.26.4" @@ -2753,10 +2880,14 @@ version = "0.2.0" dependencies = [ "anyhow", "async-trait", + "bdk_esplora", + "bdk_wallet", "bitcoind-async-client", "clap 4.5.46", "config", "dirs", + "electrsd", + "esplora-client 0.12.3", "http-body-util", "hyper", "hyper-util", diff --git a/contrib/coverage.sh b/contrib/coverage.sh index 436a00d6d..33628ce66 100755 --- a/contrib/coverage.sh +++ b/contrib/coverage.sh @@ -7,6 +7,8 @@ cargo llvm-cov clean --workspace # exclude payjoin-ffi because bindings are tested in their native language and fuzz because these tests are not coverage worthy cargo llvm-cov --no-report --workspace --all-features --exclude payjoin-ffi --exclude payjoin-fuzz # Explicitly run payjoin-cli v1 e2e tests -cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,_manual-tls +cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,_manual-tls,bitcoind +# Explicitly run payjoin-cli esplora tests +cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,v2,_manual-tls,esplora # generate report without tests cargo llvm-cov report --lcov --output-path lcov.info diff --git a/payjoin-cli/Cargo.toml b/payjoin-cli/Cargo.toml index 7722f892f..1ee44612a 100644 --- a/payjoin-cli/Cargo.toml +++ b/payjoin-cli/Cargo.toml @@ -19,19 +19,31 @@ path = "src/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["v2"] +default = ["v2", "esplora"] native-certs = ["reqwest/rustls-tls-native-roots"] _manual-tls = ["reqwest/rustls-tls", "payjoin/_manual-tls", "tokio-rustls"] v1 = ["payjoin/v1", "hyper", "hyper-util", "http-body-util"] v2 = ["payjoin/v2", "payjoin/io"] +esplora = ["bdk_wallet", "bdk_esplora", "esplora-client"] +bitcoind = ["bitcoind-async-client"] [dependencies] anyhow = "1.0.99" async-trait = "0.1.89" -bitcoind-async-client = "0.10.2" +bdk_esplora = { version = "0.22", default-features = false, features = [ + "async-https-rustls", + "std", + "tokio", +], optional = true } +bdk_wallet = { version = "3.0.0-rc.2", optional = true } +bitcoind-async-client = { version = "0.10.2", optional = true } clap = { version = "4.5.45", features = ["derive"] } config = "0.15.14" dirs = "6.0.0" +esplora-client = { version = "0.12", default-features = false, features = [ + "async-https-rustls", + "tokio", +], optional = true } http-body-util = { version = "0.1.3", optional = true } hyper = { version = "1.6.0", features = ["http1", "server"], optional = true } hyper-util = { version = "0.1.16", optional = true } @@ -57,3 +69,10 @@ url = { version = "2.5.4", features = ["serde"] } nix = { version = "0.30.1", features = ["aio", "process", "signal"] } payjoin-test-utils = { version = "0.0.1" } tempfile = "3.20.0" +# End-to-end coverage for the esplora backend spins up electrs against +# the bitcoind started by payjoin-test-utils. The `legacy` electrs +# binary exposes an HTTP REST API compatible with bdk_esplora when +# `http_enabled` is set on its Conf. +electrsd = { version = "0.36.1", default-features = false, features = [ + "esplora_a33e97e1", +] } diff --git a/payjoin-cli/contrib/lint.sh b/payjoin-cli/contrib/lint.sh index 61dfb96d6..58536f4fa 100755 --- a/payjoin-cli/contrib/lint.sh +++ b/payjoin-cli/contrib/lint.sh @@ -1,10 +1,14 @@ #!/usr/bin/env bash set -e -# Individual features with no defaults. -features=("v1" "v2") +# Protocol versions and wallet backends are orthogonal; every version must +# build against every backend, so lint them as a matrix. +versions=("v1" "v2") +backends=("bitcoind" "esplora") -for feature in "${features[@]}"; do - # Don't duplicate --all-targets clippy. Clilppy end-user code, not tests. - cargo clippy --no-default-features --features "$feature" -- -D warnings +for version in "${versions[@]}"; do + for backend in "${backends[@]}"; do + # Don't duplicate --all-targets clippy. Clippy end-user code, not tests. + cargo clippy --no-default-features --features "$version,$backend" -- -D warnings + done done diff --git a/payjoin-cli/contrib/test.sh b/payjoin-cli/contrib/test.sh index d59518991..4f54784f7 100755 --- a/payjoin-cli/contrib/test.sh +++ b/payjoin-cli/contrib/test.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash set -e -cargo test --locked --package payjoin-cli --verbose --all-features +cargo test --locked --package payjoin-cli --verbose --no-default-features --features "v1,v2,_manual-tls,esplora,native-certs" + +cargo test --locked --package payjoin-cli --verbose --no-default-features --features "v1,v2,_manual-tls,bitcoind,native-certs" diff --git a/payjoin-cli/example.config.toml b/payjoin-cli/example.bitcoind.config.toml similarity index 100% rename from payjoin-cli/example.config.toml rename to payjoin-cli/example.bitcoind.config.toml diff --git a/payjoin-cli/example.esplora.config.toml b/payjoin-cli/example.esplora.config.toml new file mode 100644 index 000000000..263a70c10 --- /dev/null +++ b/payjoin-cli/example.esplora.config.toml @@ -0,0 +1,47 @@ +## +## Payjoin config.toml configuration file. Lines beginning with # are comments. +## + +# Common Settings +# -------------- + +# The path to the database file +db_path = "payjoin.sqlite" + +# The maximum fee rate that the receiver is willing to pay (in sat/vB) +max_fee_rate = 2.0 + +# Wallet Configuration +# ------------------- +# Choose ONE backend: esplora or bitcoind +# +# Esplora backend (uses bdk_wallet with esplora API - no full node required): +# [wallet.esplora] +# descriptor = "wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/84'/1'/0'/0/*)" +# # Optional: change descriptor (auto-derived if not specified) +# # change_descriptor = "wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/84'/1'/0'/1/*)" +# esplora_url = "https://blockstream.info/api" +# network = "testnet" +# +# Bitcoind backend (uses Bitcoin Core RPC - requires full node): +# [wallet.bitcoind] +# rpchost = "http://localhost:18443/wallet/payjoin" +# # Optional: cookie file path (if not using rpcuser/rpcpassword) +# # cookie = "~/.bitcoin/testnet4/.cookie" +# # Optional: RPC credentials (if not using cookie) +# # rpcuser = "user" +# # rpcpassword = "password" + +# Version Configuration +# ------------------- +# Uncomment ONE of the following version configurations depending on which version you want to use + +# Version 1 Configuration +# [v1] +# port = 3000 +# pj_endpoint = "https://localhost:3000" + +# Version 2 Configuration +# [v2] +# pj_directory = "https://payjo.in" +# ohttp_relays = ["https://pj.benalleng.com", "https://pj.bobspacebkk.com", "https://ohttp.achow101.com"] diff --git a/payjoin-cli/src/app/config.rs b/payjoin-cli/src/app/config.rs index 6b7f8acb8..8bd393bf3 100644 --- a/payjoin-cli/src/app/config.rs +++ b/payjoin-cli/src/app/config.rs @@ -15,6 +15,7 @@ const CONFIG_DIR: &str = "payjoin-cli"; type Builder = config::builder::ConfigBuilder; +#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] #[derive(Debug, Clone, Deserialize)] pub struct BitcoindConfig { pub rpchost: Url, @@ -23,6 +24,15 @@ pub struct BitcoindConfig { pub rpcpassword: String, } +#[cfg(feature = "esplora")] +#[derive(Debug, Clone, Deserialize)] +pub struct BdkWalletConfig { + pub descriptor: Option, + pub change_descriptor: Option, + pub esplora_url: Option, + pub network: Option, +} + #[cfg(feature = "v1")] #[derive(Debug, Clone, Deserialize)] pub struct V1Config { @@ -55,7 +65,10 @@ pub enum VersionConfig { pub struct Config { pub db_path: PathBuf, pub max_fee_rate: Option, + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] pub bitcoind: BitcoindConfig, + #[cfg(feature = "esplora")] + pub wallet: Option, #[serde(skip)] pub version: Option, #[cfg(feature = "_manual-tls")] @@ -102,7 +115,7 @@ impl Config { pub(crate) fn new(cli: &Cli) -> Result { let mut config = config::Config::builder(); - config = add_bitcoind_defaults(config, cli)?; + config = add_wallet_defaults(config, cli)?; config = add_common_defaults(config, cli)?; let version = Self::determine_version(cli)?; @@ -143,7 +156,10 @@ impl Config { let mut config = Config { db_path: built_config.get("db_path")?, max_fee_rate: built_config.get("max_fee_rate").ok(), + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] bitcoind: built_config.get("bitcoind")?, + #[cfg(feature = "esplora")] + wallet: built_config.get("wallet").ok(), version: None, #[cfg(feature = "_manual-tls")] root_certificate: built_config.get("root_certificate").ok(), @@ -223,16 +239,35 @@ impl Config { } } -/// Set up default values and CLI overrides for Bitcoin RPC connection settings -fn add_bitcoind_defaults(config: Builder, cli: &Cli) -> Result { - // Set default values +/// Set up default values and CLI overrides for wallet settings +#[cfg(feature = "esplora")] +fn add_wallet_defaults(config: Builder, cli: &Cli) -> Result { + let config = config + .set_default("wallet.descriptor", None::)? + .set_default("wallet.change_descriptor", None::)? + .set_default("wallet.esplora_url", None::)? + .set_default("wallet.network", None::)?; + + let descriptor = cli.descriptor.as_deref(); + let change_descriptor = cli.change_descriptor.as_deref(); + let esplora_url = cli.esplora_url.as_deref(); + let network = cli.network.as_deref(); + + config + .set_override_option("wallet.descriptor", descriptor)? + .set_override_option("wallet.change_descriptor", change_descriptor)? + .set_override_option("wallet.esplora_url", esplora_url)? + .set_override_option("wallet.network", network) +} + +#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] +fn add_wallet_defaults(config: Builder, cli: &Cli) -> Result { let config = config .set_default("bitcoind.rpchost", "http://localhost:18443")? .set_default("bitcoind.cookie", None::)? .set_default("bitcoind.rpcuser", "bitcoin")? .set_default("bitcoind.rpcpassword", "")?; - // Override config values with command line arguments if applicable let rpchost = cli.rpchost.as_ref().map(|s| s.as_str()); let cookie_file = cli.cookie_file.as_ref().map(|p| p.to_string_lossy().into_owned()); let rpcuser = cli.rpcuser.as_deref(); @@ -245,6 +280,9 @@ fn add_bitcoind_defaults(config: Builder, cli: &Cli) -> Result Result { Ok(config) } + fn add_common_defaults(config: Builder, cli: &Cli) -> Result { let db_path = cli.db_path.as_ref().map(|p| p.to_string_lossy().into_owned()); config.set_default("db_path", db::DB_PATH)?.set_override_option("db_path", db_path) diff --git a/payjoin-cli/src/app/mod.rs b/payjoin-cli/src/app/mod.rs index f768547ab..a882d30b8 100644 --- a/payjoin-cli/src/app/mod.rs +++ b/payjoin-cli/src/app/mod.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::sync::Arc; use anyhow::Result; use payjoin::bitcoin::psbt::Psbt; @@ -9,7 +10,7 @@ use tokio::sync::watch; pub mod config; pub mod wallet; use crate::app::config::Config; -use crate::app::wallet::BitcoindWallet; +use crate::app::wallet::PayjoinWallet; #[cfg(feature = "v1")] pub(crate) mod v1; @@ -21,7 +22,7 @@ pub trait App: Send + Sync { async fn new(config: Config) -> Result where Self: Sized; - fn wallet(&self) -> BitcoindWallet; + fn wallet(&self) -> Arc; async fn send_payjoin(&self, bip21: &str, fee_rate: FeeRate) -> Result<()>; async fn receive_payjoin(&self, amount: Amount) -> Result<()>; #[cfg(feature = "v2")] diff --git a/payjoin-cli/src/app/v1.rs b/payjoin-cli/src/app/v1.rs index 9b906df3a..b630379ca 100644 --- a/payjoin-cli/src/app/v1.rs +++ b/payjoin-cli/src/app/v1.rs @@ -21,7 +21,7 @@ use tokio::net::TcpListener; use tokio::sync::watch; use super::config::Config; -use super::wallet::BitcoindWallet; +use super::wallet::{create_wallet, PayjoinWallet}; use super::App as AppTrait; use crate::app::{handle_interrupt, http_agent}; use crate::db::Database; @@ -37,7 +37,7 @@ impl payjoin::receive::v1::Headers for Headers<'_> { pub(crate) struct App { config: Config, db: Arc, - wallet: BitcoindWallet, + wallet: Arc, interrupt: watch::Receiver<()>, } @@ -47,16 +47,15 @@ impl AppTrait for App { let db = Arc::new(Database::create(&config.db_path)?); let (interrupt_tx, interrupt_rx) = watch::channel(()); tokio::spawn(handle_interrupt(interrupt_tx)); - let wallet = BitcoindWallet::new(&config.bitcoind).await?; + let wallet = create_wallet(&config)?; let app = Self { config, db, wallet, interrupt: interrupt_rx }; - app.wallet() - .network() - .context("Failed to connect to bitcoind. Check config RPC connection.")?; + app.wallet().network().context("Failed to connect to wallet. Check config.")?; Ok(app) } - fn wallet(&self) -> BitcoindWallet { self.wallet.clone() } + fn wallet(&self) -> Arc { self.wallet.clone() } + #[allow(clippy::incompatible_msrv)] async fn send_payjoin(&self, bip21: &str, fee_rate: FeeRate) -> Result<()> { let uri = Uri::try_from(bip21).map_err(|e| anyhow!("Failed to create URI from BIP21: {}", e))?; @@ -368,7 +367,7 @@ impl App { .map_err(|e| Error::Implementation(ImplementationError::new(e)))? .commit_outputs(); - let wants_fee_range = try_contributing_inputs(payjoin.clone(), &self.wallet) + let wants_fee_range = try_contributing_inputs(payjoin.clone(), self.wallet.as_ref()) .map_err(Error::Implementation)?; let provisional_payjoin = wants_fee_range.apply_fee_range(None, self.config.max_fee_rate)?; @@ -384,7 +383,7 @@ impl App { fn try_contributing_inputs( payjoin: payjoin::receive::v1::WantsInputs, - wallet: &BitcoindWallet, + wallet: &dyn PayjoinWallet, ) -> Result { let candidate_inputs = wallet.list_unspent().map_err(|e| ImplementationError::from(e.into_boxed_dyn_error()))?; diff --git a/payjoin-cli/src/app/v2/mod.rs b/payjoin-cli/src/app/v2/mod.rs index 73f4dcf85..924af31fe 100644 --- a/payjoin-cli/src/app/v2/mod.rs +++ b/payjoin-cli/src/app/v2/mod.rs @@ -20,7 +20,7 @@ use payjoin::{ImplementationError, PjParam, Uri}; use tokio::sync::watch; use super::config::Config; -use super::wallet::BitcoindWallet; +use super::wallet::{create_wallet, PayjoinWallet}; use super::App as AppTrait; use crate::app::v2::ohttp::{unwrap_ohttp_keys_or_else_fetch, RelayManager}; use crate::app::{handle_interrupt, http_agent}; @@ -38,7 +38,7 @@ const W_STATUS: usize = 15; pub(crate) struct App { config: Config, db: Arc, - wallet: BitcoindWallet, + wallet: Arc, interrupt: watch::Receiver<()>, relay_manager: Arc>, } @@ -143,15 +143,13 @@ impl AppTrait for App { let relay_manager = Arc::new(Mutex::new(RelayManager::new())); let (interrupt_tx, interrupt_rx) = watch::channel(()); tokio::spawn(handle_interrupt(interrupt_tx)); - let wallet = BitcoindWallet::new(&config.bitcoind).await?; + let wallet = create_wallet(&config)?; let app = Self { config, db, wallet, interrupt: interrupt_rx, relay_manager }; - app.wallet() - .network() - .context("Failed to connect to bitcoind. Check config RPC connection.")?; + app.wallet().network().context("Failed to connect to wallet. Check config.")?; Ok(app) } - fn wallet(&self) -> BitcoindWallet { self.wallet.clone() } + fn wallet(&self) -> Arc { self.wallet.clone() } #[allow(clippy::incompatible_msrv)] async fn send_payjoin(&self, bip21: &str, fee_rate: FeeRate) -> Result<()> { diff --git a/payjoin-cli/src/app/wallet.rs b/payjoin-cli/src/app/wallet.rs index 4b1dbbcc8..ab2ff9524 100644 --- a/payjoin-cli/src/app/wallet.rs +++ b/payjoin-cli/src/app/wallet.rs @@ -1,215 +1,605 @@ use std::collections::HashMap; use std::sync::Arc; -use anyhow::{anyhow, Context, Result}; -use bitcoind_async_client::corepc_types::model::ListUnspentItem; -use bitcoind_async_client::traits::{Broadcaster, Reader, Signer, Wallet}; -use bitcoind_async_client::types::{CreateRawTransactionOutput, WalletCreateFundedPsbtOptions}; -use bitcoind_async_client::{Auth, Client as AsyncBitcoinRpc}; -use payjoin::bitcoin::psbt::{Input, Psbt}; -use payjoin::bitcoin::{ - Address, Amount, FeeRate, Network, OutPoint, Script, Transaction, TxIn, TxOut, Txid, -}; +use anyhow::Result; +use payjoin::bitcoin::psbt::Psbt as PayjoinPsbt; +use payjoin::bitcoin::{Address, Amount, FeeRate, Network, Script, Transaction, Txid}; use payjoin::receive::InputPair; -/// Implementation of PayjoinWallet for bitcoind using async RPC client -#[derive(Clone)] -pub struct BitcoindWallet { - rpc: Arc, +pub trait PayjoinWallet: Send + Sync { + fn create_psbt( + &self, + outputs: HashMap, + fee_rate: FeeRate, + lock_unspent: bool, + ) -> Result; + + fn process_psbt(&self, psbt: &PayjoinPsbt) -> Result; + + fn can_broadcast(&self, tx: &Transaction) -> Result; + + fn broadcast_tx(&self, tx: &Transaction) -> Result; + + fn is_mine(&self, script: &Script) -> Result; + + #[cfg(feature = "v2")] + fn get_raw_transaction(&self, txid: &Txid) -> Result>; + + fn get_new_address(&self) -> Result
; + + fn list_unspent(&self) -> Result>; + + fn has_spendable_utxos(&self) -> Result; + + fn network(&self) -> Result; } -impl BitcoindWallet { - pub async fn new(config: &crate::app::config::BitcoindConfig) -> Result { - let auth = match &config.cookie { - Some(cookie) if cookie.as_os_str().is_empty() => - return Err(anyhow!( - "Cookie authentication enabled but no cookie path provided in config.toml" - )), - Some(cookie) => Auth::CookieFile(cookie.into()), - None => Auth::UserPass(config.rpcuser.clone(), config.rpcpassword.clone()), - }; +#[cfg(feature = "esplora")] +mod esplora_backend { + use std::collections::HashMap; + use std::str::FromStr; + use std::sync::{Arc, Mutex}; + + use anyhow::{anyhow, Result}; + use bdk_esplora::esplora_client::Builder; + use bdk_esplora::{esplora_client, EsploraAsyncExt}; + use bdk_wallet::bitcoin::ScriptBuf; + use bdk_wallet::signer::SignOptions; + use bdk_wallet::{KeychainKind, Wallet as BdkWalletInner}; + use payjoin::bitcoin::psbt::{Input, Psbt}; + use payjoin::bitcoin::{ + Address, Amount, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut, Txid, + }; + use payjoin::receive::InputPair; + + use crate::app::wallet::PayjoinWallet; + + #[derive(Clone)] + pub struct BdkWallet { + wallet: Arc>, + esplora_client: Arc, + } + + impl BdkWallet { + pub fn new( + descriptor: &str, + change_descriptor: Option<&str>, + network: Network, + esplora_url: &str, + ) -> Result { + let bdk_network = match network { + Network::Bitcoin => bdk_wallet::bitcoin::Network::Bitcoin, + Network::Testnet => bdk_wallet::bitcoin::Network::Testnet, + Network::Signet => bdk_wallet::bitcoin::Network::Signet, + Network::Regtest => bdk_wallet::bitcoin::Network::Regtest, + Network::Testnet4 => bdk_wallet::bitcoin::Network::Testnet4, + }; + + let change_desc = super::derive_change_descriptor(descriptor, change_descriptor); + + let wallet = BdkWalletInner::create(descriptor.to_owned(), change_desc) + .network(bdk_network) + .create_wallet_no_persist() + .map_err(|e| anyhow!("Failed to create wallet: {}", e))?; + + let esplora_client = Builder::new(esplora_url) + .build_async() + .map_err(|e| anyhow!("Failed to create esplora client: {}", e))?; + + let this = Self { + wallet: Arc::new(Mutex::new(wallet)), + esplora_client: Arc::new(esplora_client), + }; + this.sync()?; + Ok(this) + } + + pub fn sync(&self) -> Result<()> { + let request = { + let wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + wallet.start_full_scan() + }; + + let update = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + self.esplora_client + .full_scan(request, 10, 5) + .await + .map_err(|e| anyhow!("Failed to sync wallet: {}", e)) + }) + })?; + + let mut wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + wallet.apply_update(update).map_err(|e| anyhow!("Failed to apply update: {}", e))?; + Ok(()) + } + } - let rpc = AsyncBitcoinRpc::new(config.rpchost.to_string(), auth, None, None, None)?; + impl PayjoinWallet for BdkWallet { + fn create_psbt( + &self, + outputs: HashMap, + fee_rate: FeeRate, + _lock_unspent: bool, + ) -> Result { + let mut wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; - Ok(Self { rpc: Arc::new(rpc) }) + let mut builder = wallet.build_tx(); + for (address, amount) in outputs { + let bdk_addr = bdk_wallet::bitcoin::Address::from_str(&address) + .map_err(|e| anyhow!("Invalid address: {}", e))?; + let checked_addr = bdk_addr.assume_checked(); + builder.add_recipient(checked_addr.script_pubkey(), amount); + } + builder.fee_rate(fee_rate); + + let psbt = + builder.finish().map_err(|e| anyhow!("Failed to build transaction: {}", e))?; + let psbt_hex = psbt.to_string(); + let psbt: Psbt = + Psbt::from_str(&psbt_hex).map_err(|e| anyhow!("Failed to parse PSBT: {}", e))?; + Ok(psbt) + } + + fn process_psbt(&self, psbt: &Psbt) -> Result { + let wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + let psbt_hex = psbt.to_string(); + let mut bdk_psbt = bdk_wallet::bitcoin::Psbt::from_str(&psbt_hex) + .map_err(|e| anyhow!("Failed to parse PSBT: {}", e))?; + let sign_options = SignOptions { trust_witness_utxo: true, ..SignOptions::default() }; + // In payjoin, sign() will return finalized=false because the + // counterparty's inputs are not yet signed — that's fine. We only + // need BDK to sign the inputs it owns. + wallet + .sign(&mut bdk_psbt, sign_options) + .map_err(|e| anyhow!("Failed to sign PSBT: {}", e))?; + let signed_psbt_hex = bdk_psbt.to_string(); + let signed_psbt: Psbt = Psbt::from_str(&signed_psbt_hex) + .map_err(|e| anyhow!("Failed to parse signed PSBT: {}", e))?; + Ok(signed_psbt) + } + + fn can_broadcast(&self, _tx: &Transaction) -> Result { Ok(true) } + + fn broadcast_tx(&self, tx: &Transaction) -> Result { + tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + self.esplora_client + .broadcast(tx) + .await + .map_err(|e| anyhow!("Failed to broadcast transaction: {}", e)) + }) + })?; + Ok(tx.compute_txid()) + } + + fn is_mine(&self, script: &payjoin::bitcoin::Script) -> Result { + let wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + let script = ScriptBuf::from_bytes(script.as_bytes().to_vec()); + Ok(wallet.is_mine(script)) + } + + #[cfg(feature = "v2")] + fn get_raw_transaction( + &self, + _txid: &Txid, + ) -> Result> { + Ok(None) + } + + fn get_new_address(&self) -> Result
{ + let mut wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + let address_info = wallet.reveal_next_address(KeychainKind::External); + let addr_str = address_info.address.to_string(); + Ok(Address::from_str(&addr_str)?.assume_checked()) + } + + fn list_unspent(&self) -> Result> { + let wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + let unspents: Vec<_> = wallet.list_unspent().collect(); + + unspents + .into_iter() + .map(|utxo| { + let psbtin = Input { + witness_utxo: Some(TxOut { + value: utxo.txout.value, + script_pubkey: utxo.txout.script_pubkey, + }), + ..Default::default() + }; + let txin = TxIn { + previous_output: OutPoint { + txid: utxo.outpoint.txid, + vout: utxo.outpoint.vout, + }, + ..Default::default() + }; + InputPair::new(txin, psbtin, None) + .map_err(|e| anyhow!("Invalid input pair: {}", e)) + }) + .collect() + } + + fn has_spendable_utxos(&self) -> Result { + let unspent = self.list_unspent()?; + Ok(!unspent.is_empty()) + } + + fn network(&self) -> Result { + let wallet = self.wallet.lock().map_err(|e| anyhow!("Lock error: {}", e))?; + match wallet.network() { + bdk_wallet::bitcoin::Network::Bitcoin => Ok(Network::Bitcoin), + bdk_wallet::bitcoin::Network::Testnet => Ok(Network::Testnet), + bdk_wallet::bitcoin::Network::Signet => Ok(Network::Signet), + bdk_wallet::bitcoin::Network::Regtest => Ok(Network::Regtest), + _ => Ok(Network::Testnet), + } + } } + + pub use BdkWallet as BdkWalletImpl; } -impl BitcoindWallet { - /// Create a PSBT with the given outputs and fee rate - pub fn create_psbt( - &self, - outputs: HashMap, - fee_rate: FeeRate, - lock_unspent: bool, - ) -> Result { - let fee_sat_per_vb = fee_rate.to_sat_per_vb_ceil(); - tracing::debug!("Fee rate sat/vb: {}", fee_sat_per_vb); - - let options = WalletCreateFundedPsbtOptions { - fee_rate: Some(fee_sat_per_vb as f64), - lock_unspents: Some(lock_unspent), - replaceable: None, - conf_target: None, - }; +#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] +mod bitcoind_backend { + use std::collections::HashMap; + use std::sync::Arc; + + use anyhow::{anyhow, Context, Result}; + use bitcoind_async_client::corepc_types::model::ListUnspentItem; + use bitcoind_async_client::traits::{Broadcaster, Reader, Signer, Wallet}; + use bitcoind_async_client::types::{CreateRawTransactionOutput, WalletCreateFundedPsbtOptions}; + use bitcoind_async_client::{Auth, Client as AsyncBitcoinRpc}; + use payjoin::bitcoin::psbt::{Input, Psbt}; + use payjoin::bitcoin::{ + Address, Amount, FeeRate, Network, OutPoint, Script, Transaction, TxIn, TxOut, Txid, + }; + use payjoin::receive::InputPair; + + use super::PayjoinWallet; + + #[derive(Clone, Debug)] + pub struct BitcoindWallet { + rpc: Arc, + } + + impl BitcoindWallet { + pub fn new(config: &crate::app::config::BitcoindConfig) -> Result { + let auth = match &config.cookie { + Some(cookie) if cookie.as_os_str().is_empty() => + return Err(anyhow!( + "Cookie authentication enabled but no cookie path provided in config.toml" + )), + Some(cookie) => Auth::CookieFile(cookie.into()), + None => Auth::UserPass(config.rpcuser.clone(), config.rpcpassword.clone()), + }; + + let rpc = AsyncBitcoinRpc::new(config.rpchost.to_string(), auth, None, None, None)?; + + Ok(Self { rpc: Arc::new(rpc) }) + } + } + + impl PayjoinWallet for BitcoindWallet { + fn create_psbt( + &self, + outputs: HashMap, + fee_rate: FeeRate, + lock_unspent: bool, + ) -> Result { + let fee_sat_per_vb = fee_rate.to_sat_per_vb_ceil(); + tracing::debug!("Fee rate sat/vb: {}", fee_sat_per_vb); + + let options = WalletCreateFundedPsbtOptions { + fee_rate: Some(fee_sat_per_vb as f64), + lock_unspents: Some(lock_unspent), + replaceable: None, + conf_target: None, + }; + + let locktime = Some(tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.get_block_count().await }) + })? as u32); + + let result = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + self.rpc + .wallet_create_funded_psbt( + &[], + &outputs + .iter() + .map(|(k, v)| CreateRawTransactionOutput::AddressAmount { + address: k.clone(), + amount: v.to_btc(), + }) + .collect::>(), + locktime, + Some(options), + None, + ) + .await + }) + })?; + + let processed = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + self.rpc.wallet_process_psbt(&result.psbt.to_string(), None, None, None).await + }) + })? + .psbt; + + Ok(processed) + } + + fn process_psbt(&self, psbt: &Psbt) -> Result { + let psbt_str = psbt.to_string(); + let processed = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + self.rpc.wallet_process_psbt(&psbt_str, Some(true), None, None).await + }) + })?; + Ok(processed.psbt) + } - // Set locktime to current block height for anti-fee-sniping - // This is to follow wallet fingerprinting best practices and set and opinionated - // default for external wallet integrations to follow along with - let locktime = Some(tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { self.rpc.get_block_count().await }) - })? as u32); - - // Sync wrapper around async call - use tokio handle to avoid deadlock - let result = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { - self.rpc - .wallet_create_funded_psbt( - &[], // inputs - &outputs - .iter() - .map(|(k, v)| CreateRawTransactionOutput::AddressAmount { - address: k.clone(), - amount: v.to_btc(), - }) - .collect::>(), - locktime, - Some(options), - None, - ) - .await + fn can_broadcast(&self, tx: &Transaction) -> Result { + let mempool_results = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.test_mempool_accept(tx).await }) + })?; + + mempool_results + .results + .first() + .map(|result| result.reject_reason.is_none()) + .ok_or_else(|| anyhow!("No mempool results returned on broadcast check")) + } + + fn broadcast_tx(&self, tx: &Transaction) -> Result { + tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.send_raw_transaction(tx).await }) }) - })?; + .context("Failed to broadcast transaction") + } + + fn is_mine(&self, script: &Script) -> Result { + if let Ok(address) = Address::from_script(script, self.network()?) { + let info = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.get_address_info(&address).await }) + }) + .context("Failed to get address info")?; + Ok(info.is_mine) + } else { + Ok(false) + } + } - let processed = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { - self.rpc.wallet_process_psbt(&result.psbt.to_string(), None, None, None).await + #[cfg(feature = "v2")] + fn get_raw_transaction( + &self, + txid: &Txid, + ) -> Result> { + let raw_tx = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { + match self.rpc.get_transaction(txid).await { + Ok(rpc_res) => Ok(Some(rpc_res.tx)), + Err(e) => + if e.is_tx_not_found() { + Ok(None) + } else { + Err(e) + }, + } + }) + })?; + Ok(raw_tx) + } + + fn get_new_address(&self) -> Result
{ + let addr = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.get_new_address().await }) }) - })? - .psbt; + .context("Failed to get new address")?; + Ok(addr) + } - Ok(processed) - } + fn list_unspent(&self) -> Result> { + let unspent = tokio::task::block_in_place(|| { + tokio::runtime::Handle::current() + .block_on(async { self.rpc.list_unspent(None, None, None, None, None).await }) + }) + .context("Failed to list unspent")?; + Ok(unspent.0.into_iter().map(input_pair_from_corepc).collect()) + } + + fn has_spendable_utxos(&self) -> Result { + let unspent = self.list_unspent()?; + Ok(!unspent.is_empty()) + } - /// Process a PSBT, validating and signing inputs owned by this wallet - /// - /// Does not include bip32 derivations in the PSBT - pub fn process_psbt(&self, psbt: &Psbt) -> Result { - let psbt_str = psbt.to_string(); - let processed = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { - self.rpc.wallet_process_psbt(&psbt_str, Some(true), None, None).await + fn network(&self) -> Result { + tokio::task::block_in_place(|| { + tokio::runtime::Handle::current().block_on(async { self.rpc.network().await }) }) - })?; - Ok(processed.psbt) + .map_err(|e| anyhow!("Failed to get blockchain info: {e}")) + } } - pub fn can_broadcast(&self, tx: &Transaction) -> Result { - let mempool_results = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current() - .block_on(async { self.rpc.test_mempool_accept(tx).await }) - })?; - - mempool_results - .results - .first() - .map(|result| result.reject_reason.is_none()) - .ok_or_else(|| anyhow!("No mempool results returned on broadcast check")) + pub(crate) fn input_pair_from_corepc(utxo: ListUnspentItem) -> InputPair { + let psbtin = Input { + witness_utxo: Some(TxOut { + value: Amount::from_btc(utxo.amount.to_btc()).expect("Valid amount"), + script_pubkey: utxo.script_pubkey, + }), + redeem_script: None, + witness_script: None, + ..Default::default() + }; + let txin = TxIn { + previous_output: OutPoint { txid: utxo.txid, vout: utxo.vout }, + ..Default::default() + }; + InputPair::new(txin, psbtin, None).expect("Input pair should be valid") } - /// Broadcast a raw transaction - pub fn broadcast_tx(&self, tx: &Transaction) -> Result { - tokio::task::block_in_place(|| { - tokio::runtime::Handle::current() - .block_on(async { self.rpc.send_raw_transaction(tx).await }) - }) - .context("Failed to broadcast transaction") + pub use BitcoindWallet as BitcoindWalletImpl; +} + +#[cfg(feature = "esplora")] +pub(crate) fn parse_network(name: Option<&str>) -> Result { + use anyhow::anyhow; + match name { + // Mainnet currently disabled until an ohttp wrapper is available to encrypt + // messages. https://github.com/bitcoindevkit/rust-esplora-client/pull/145 + Some("mainnet") | Some("bitcoin") | None => Err(anyhow!("Mainnet disabled for esplora")), + Some("testnet") => Ok(Network::Testnet), + Some("testnet4") => Ok(Network::Testnet4), + Some("signet") => Ok(Network::Signet), + Some("regtest") => Ok(Network::Regtest), + Some(n) => Err(anyhow!("Unknown network: {}", n)), } +} - /// Check if a script belongs to this wallet - pub fn is_mine(&self, script: &Script) -> Result { - if let Ok(address) = Address::from_script(script, self.network()?) { - let info = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current() - .block_on(async { self.rpc.get_address_info(&address).await }) - }) - .context("Failed to get address info")?; - Ok(info.is_mine) +/// Derive a change descriptor from the receive descriptor when one is not +/// supplied. Assumes the BIP44-family `.../0/*` external chain convention +/// and rewrites that final step to `/1/*`. Handles both the raw-key form +/// (`tprv.../0/*`) and wrapped forms (`wpkh(tprv.../0/*)`), with or +/// without a trailing `#checksum`. The checksum is dropped on rewrite — +/// BDK recomputes it. If the descriptor does not match either shape it is +/// returned unchanged (BDK will then use the same keychain for both). +#[cfg(feature = "esplora")] +pub(crate) fn derive_change_descriptor(descriptor: &str, change: Option<&str>) -> String { + if let Some(c) = change { + return c.to_owned(); + } + let body = descriptor.rsplit_once('#').map(|(b, _)| b).unwrap_or(descriptor); + if let Some(base) = body.strip_suffix("/0/*") { + format!("{base}/1/*") + } else if let Some(inner) = body.strip_suffix(')') { + if let Some(base) = inner.strip_suffix("/0/*") { + format!("{base}/1/*)") } else { - Ok(false) + descriptor.to_owned() } + } else { + descriptor.to_owned() } +} - #[cfg(feature = "v2")] - pub fn get_raw_transaction( - &self, - txid: &Txid, - ) -> Result> { - let raw_tx = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { - match self.rpc.get_transaction(txid).await { - Ok(rpc_res) => Ok(Some(rpc_res.tx)), - Err(e) => - if e.is_tx_not_found() { - Ok(None) - } else { - Err(e) - }, - } - }) - })?; - Ok(raw_tx) - } +#[cfg(feature = "esplora")] +pub fn create_wallet(config: &super::config::Config) -> Result> { + use anyhow::anyhow; + + use crate::app::wallet::esplora_backend::BdkWalletImpl; + let wallet_config = config + .wallet + .as_ref() + .ok_or_else(|| anyhow!("wallet config required. Set --descriptor and --esplora-url"))?; + let network = parse_network(wallet_config.network.as_deref())?; + let descriptor = wallet_config + .descriptor + .as_ref() + .ok_or_else(|| anyhow!("--descriptor required for esplora backend"))?; + let esplora_url = wallet_config + .esplora_url + .as_ref() + .ok_or_else(|| anyhow!("--esplora-url required for esplora backend"))?; + Ok(Arc::new(BdkWalletImpl::new( + descriptor, + wallet_config.change_descriptor.as_deref(), + network, + esplora_url, + )?)) +} - /// Get a new address from the wallet - pub fn get_new_address(&self) -> Result
{ - let addr = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { self.rpc.get_new_address().await }) - }) - .context("Failed to get new address")?; - Ok(addr) +#[cfg(test)] +mod tests { + #[cfg(feature = "esplora")] + use super::*; + + #[cfg(feature = "esplora")] + #[test] + fn parse_network_rejects_unknown() { + let err = parse_network(Some("liquid")).unwrap_err(); + assert!(err.to_string().contains("Unknown network")); } - /// List unspent UTXOs - pub fn list_unspent(&self) -> Result> { - let unspent = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current() - .block_on(async { self.rpc.list_unspent(None, None, None, None, None).await }) - }) - .context("Failed to list unspent")?; - Ok(unspent.0.into_iter().map(input_pair_from_corepc).collect()) + #[cfg(feature = "esplora")] + #[test] + fn derive_change_descriptor_cases() { + // Explicit change descriptor overrides any derivation + let receive = "wpkh(tprv.../0/*)"; + let change = Some("wpkh(tprv.../2/*)"); + assert_eq!(derive_change_descriptor(receive, change), "wpkh(tprv.../2/*)"); + + // Raw `.../0/*` suffix should produce a change descriptor + let receive = "[fingerprint/84h/1h/0h]tprvFOO/0/*"; + let change = None; + assert_eq!(derive_change_descriptor(receive, change), "[fingerprint/84h/1h/0h]tprvFOO/1/*",); + + // Wrapped `wpkh(.../0/*)`. + let receive = "wpkh([fingerprint/84h/1h/0h]tprvFOO/0/*)"; + let change = None; + assert_eq!( + derive_change_descriptor(receive, change), + "wpkh([fingerprint/84h/1h/0h]tprvFOO/1/*)", + ); + + // Wrapped + checksum: checksum is dropped on rewrite. + let receive = "wpkh([fingerprint/84h/1h/0h]tprvFOO/0/*)#abcd1234"; + let change = None; + assert_eq!( + derive_change_descriptor(receive, change), + "wpkh([fingerprint/84h/1h/0h]tprvFOO/1/*)", + ); + + // No external-chain suffix is a direct passthrough. + let receive = "wpkh(tprv.../*)"; + let change = None; + assert_eq!(derive_change_descriptor(receive, change), "wpkh(tprv.../*)"); } - /// Check if wallet has any spendable UTXOs - pub fn has_spendable_utxos(&self) -> Result { - let unspent = self.list_unspent()?; - Ok(!unspent.is_empty()) + #[cfg(feature = "esplora")] + #[test] + fn bdk_wallet_new_rejects_invalid_descriptor() { + // Constructing a BdkWallet with garbage should fail before any network + // I/O is attempted, so this test is hermetic. + use super::esplora_backend::BdkWallet; + let res = BdkWallet::new("not a descriptor", None, Network::Regtest, "http://127.0.0.1:1"); + assert!(res.is_err()); } - /// Get the network this wallet is operating on - pub fn network(&self) -> Result { - tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { self.rpc.network().await }) - }) - .map_err(|e| anyhow!("Failed to get blockchain info: {e}")) + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[test] + fn bitcoind_wallet_new_rejects_empty_cookie() { + use url::Url; + + use crate::app::config::BitcoindConfig; + use crate::app::wallet::bitcoind_backend::BitcoindWalletImpl; + let config = BitcoindConfig { + rpchost: Url::parse("http://localhost").unwrap(), + rpcuser: "user".to_string(), + rpcpassword: "pass".to_string(), + cookie: Some(std::path::PathBuf::from("")), + }; + let result = BitcoindWalletImpl::new(&config); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!(err.to_string().contains("Cookie authentication enabled but no cookie path")); } } -pub fn input_pair_from_corepc(utxo: ListUnspentItem) -> InputPair { - let psbtin = Input { - // NOTE: non_witness_utxo is not necessary because bitcoin-cli always supplies - // witness_utxo, even for non-witness inputs - witness_utxo: Some(TxOut { - value: Amount::from_btc(utxo.amount.to_btc()).expect("Valid amount"), - script_pubkey: utxo.script_pubkey, - }), - redeem_script: None, - witness_script: None, // Not available in this version - ..Default::default() - }; - let txin = TxIn { - previous_output: OutPoint { txid: utxo.txid, vout: utxo.vout }, - ..Default::default() - }; - InputPair::new(txin, psbtin, None).expect("Input pair should be valid") +#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] +pub fn create_wallet(config: &super::config::Config) -> Result> { + use crate::app::wallet::bitcoind_backend::BitcoindWalletImpl; + Ok(Arc::new(BitcoindWalletImpl::new(&config.bitcoind)?)) +} + +#[cfg(all(not(feature = "esplora"), not(feature = "bitcoind")))] +pub fn create_wallet(_config: &super::config::Config) -> Result> { + Err(anyhow::anyhow!("No wallet backend enabled. Enable esplora or bitcoind feature.")) } diff --git a/payjoin-cli/src/cli/mod.rs b/payjoin-cli/src/cli/mod.rs index 1f35979b5..80efcf197 100644 --- a/payjoin-cli/src/cli/mod.rs +++ b/payjoin-cli/src/cli/mod.rs @@ -34,6 +34,23 @@ pub struct Cli { #[arg(long = "max-fee-rate", short = 'f', help = "The maximum fee rate to accept in sat/vB")] pub max_fee_rate: Option, + #[cfg(feature = "esplora")] + #[arg(long, num_args(1), help = "The wallet descriptor")] + pub descriptor: Option, + + #[cfg(feature = "esplora")] + #[arg(long, num_args(1), help = "The optional change descriptor")] + pub change_descriptor: Option, + + #[cfg(feature = "esplora")] + #[arg(long, num_args(1), help = "The esplora API URL")] + pub esplora_url: Option, + + #[cfg(feature = "esplora")] + #[arg(long, num_args(1), help = "The Bitcoin network to connect to")] + pub network: Option, + + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] #[arg( long, short = 'r', @@ -42,6 +59,7 @@ pub struct Cli { )] pub rpchost: Option, + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] #[arg( long = "cookie-file", short = 'c', @@ -50,9 +68,11 @@ pub struct Cli { )] pub cookie_file: Option, + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] #[arg(long = "rpcuser", num_args(1), help = "The username for the bitcoin node")] pub rpcuser: Option, + #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] #[arg(long = "rpcpassword", num_args(1), help = "The password for the bitcoin node")] pub rpcpassword: Option, diff --git a/payjoin-cli/tests/cli_esplora.rs b/payjoin-cli/tests/cli_esplora.rs new file mode 100644 index 000000000..2353794c5 --- /dev/null +++ b/payjoin-cli/tests/cli_esplora.rs @@ -0,0 +1,60 @@ +//! CLI surface tests for the esplora backend. +//! +//! These tests exercise the binary as a subprocess and assert on exit +//! status / stderr only — no network, no bitcoind, no esplora server. +//! Their job is to catch regressions in argument parsing, feature gating, +//! and the missing-config error paths. + +#![cfg(feature = "esplora")] + +use std::process::Command; + +fn bin() -> Command { Command::new(env!("CARGO_BIN_EXE_payjoin-cli")) } + +#[test] +fn help_succeeds() { + let output = bin().arg("--help").output().expect("spawn payjoin-cli"); + assert!(output.status.success(), "stderr: {}", String::from_utf8_lossy(&output.stderr)); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(stdout.contains("Payjoin")); + assert!(stdout.contains("--descriptor")); + assert!(stdout.contains("--esplora-url")); +} + +#[test] +fn send_help_succeeds() { + let output = bin().args(["send", "--help"]).output().expect("spawn payjoin-cli"); + assert!(output.status.success(), "stderr: {}", String::from_utf8_lossy(&output.stderr)); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(stdout.contains("--fee-rate")); +} + +#[test] +fn receive_help_succeeds() { + let output = bin().args(["receive", "--help"]).output().expect("spawn payjoin-cli"); + assert!(output.status.success(), "stderr: {}", String::from_utf8_lossy(&output.stderr)); +} + +#[test] +fn missing_subcommand_errors() { + let output = bin().output().expect("spawn payjoin-cli"); + assert!(!output.status.success()); +} + +#[test] +fn send_requires_bip21_and_fee_rate() { + let output = bin().arg("send").output().expect("spawn payjoin-cli"); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + // clap reports missing required args + assert!(stderr.contains("required") || stderr.contains("USAGE") || stderr.contains("Usage")); +} + +#[test] +fn invalid_fee_rate_rejected() { + let output = bin() + .args(["send", "bitcoin:tb1qexample", "--fee-rate", "not-a-number"]) + .output() + .expect("spawn payjoin-cli"); + assert!(!output.status.success()); +} diff --git a/payjoin-cli/tests/common/mod.rs b/payjoin-cli/tests/common/mod.rs new file mode 100644 index 000000000..ace942e9c --- /dev/null +++ b/payjoin-cli/tests/common/mod.rs @@ -0,0 +1,231 @@ +//! Shared fixture and process-orchestration helpers for the esplora +//! e2e tests. Kept in `tests/common/` so cargo picks it up as a module +//! of `e2e_esplora.rs` rather than compiling it as its own test target. + +#![allow(dead_code)] + +use std::path::Path; +use std::str::FromStr; +use std::time::Duration; + +use bdk_wallet::bitcoin::bip32::Xpriv; +use bdk_wallet::bitcoin::{Address as BtcAddress, Amount as BtcAmount, Network as BdkNetwork}; +use bdk_wallet::{KeychainKind, Wallet as BdkWallet}; +use electrsd::corepc_node::{Conf as NodeConf, Node}; +use electrsd::ElectrsD; +use nix::sys::signal::{kill, Signal}; +use nix::unistd::Pid; +use payjoin_test_utils::BoxSendSyncError; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::process::{Child, Command}; + +pub const RECEIVE_SATS: &str = "54321"; + +#[derive(Copy, Clone)] +pub enum Side { + Sender, + Receiver, +} + +/// A bitcoind + electrs-esplora fixture with two disjoint BIP84 BDK +/// descriptor wallets funded on regtest. Every esplora e2e test owns +/// an independent instance of this struct, so they can run in parallel +/// without clobbering each other's chain state. +pub struct EsploraFixture { + pub bitcoind: Node, + pub electrsd: ElectrsD, + pub esplora_url: String, + pub sender_desc: String, + pub sender_change: String, + pub receiver_desc: String, + pub receiver_change: String, + funding_addr: BtcAddress, +} + +impl EsploraFixture { + pub async fn new() -> Result { + let (sender_desc, sender_change) = descriptors_for(1); + let (receiver_desc, receiver_change) = descriptors_for(2); + let sender_addr_str = first_external_address(&sender_desc, &sender_change); + let receiver_addr_str = first_external_address(&receiver_desc, &receiver_change); + + // 1. Start bitcoind via the corepc-node version electrsd was + // built against so ElectrsD::with_conf accepts it. + let bitcoind_exe = electrsd::corepc_node::exe_path()?; + let mut conf = NodeConf::default(); + conf.view_stdout = false; + let bitcoind = Node::with_conf(bitcoind_exe, &conf)?; + let rpc = &bitcoind.client; + + // 2. Mine 101 blocks to a funding address and send 1 BTC to + // each descriptor's first external address, then mine one + // more block so the outputs are confirmed. + let funding_addr = rpc.new_address()?; + rpc.generate_to_address(101, &funding_addr)?; + + let one_btc = BtcAmount::from_btc(1.0)?; + let sender_addr = BtcAddress::from_str(&sender_addr_str)?.assume_checked(); + let receiver_addr = BtcAddress::from_str(&receiver_addr_str)?.assume_checked(); + rpc.send_to_address(&sender_addr, one_btc)?; + rpc.send_to_address(&receiver_addr, one_btc)?; + rpc.generate_to_address(1, &funding_addr)?; + let tip = rpc.get_block_count()?.0; + + // 3. Launch electrs-esplora pointing at the same bitcoind. + let electrs_exe = electrsd::exe_path().map_err(|e| format!("electrs exe: {e}"))?; + let mut el_conf = electrsd::Conf::default(); + el_conf.http_enabled = true; + let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &el_conf)?; + let raw_esplora = + electrsd.esplora_url.clone().expect("esplora_a33e97e1 feature must expose esplora_url"); + let esplora_url = if raw_esplora.starts_with("http") { + raw_esplora + } else { + format!("http://{raw_esplora}") + }; + wait_for_esplora_height(&esplora_url, tip).await?; + + Ok(Self { + bitcoind, + electrsd, + esplora_url, + sender_desc, + sender_change, + receiver_desc, + receiver_change, + funding_addr, + }) + } + + /// Mine one block to the fixture's funding address. Useful for v2 + /// flows that need to advance the chain after a payjoin is sent so + /// the receiver picks up the confirmation. + pub fn mine_one(&self) -> Result<(), BoxSendSyncError> { + self.bitcoind.client.generate_to_address(1, &self.funding_addr)?; + Ok(()) + } + + /// Build a `payjoin-cli` command pre-populated with the flags every + /// esplora test needs (wallet descriptor pair, esplora URL, network, + /// db path). Callers chain on subcommand- and transport-specific + /// arguments before `.spawn()`. + pub fn cli(&self, side: Side, db_path: &Path) -> Command { + let bin = env!("CARGO_BIN_EXE_payjoin-cli"); + let (desc, change) = match side { + Side::Sender => (&self.sender_desc, &self.sender_change), + Side::Receiver => (&self.receiver_desc, &self.receiver_change), + }; + let mut cmd = Command::new(bin); + cmd.arg("--descriptor") + .arg(desc) + .arg("--change-descriptor") + .arg(change) + .arg("--esplora-url") + .arg(&self.esplora_url) + .arg("--network") + .arg("regtest") + .arg("--db-path") + .arg(db_path); + cmd + } +} + +fn descriptors_for(tag: u8) -> (String, String) { + let seed = [tag; 32]; + let xprv = Xpriv::new_master(BdkNetwork::Regtest, &seed).expect("valid master key"); + let xprv_str = xprv.to_string(); + let recv = format!("wpkh({}/84h/1h/0h/0/*)", xprv_str); + let change = format!("wpkh({}/84h/1h/0h/1/*)", xprv_str); + (recv, change) +} + +fn first_external_address(desc: &str, change: &str) -> String { + let mut wallet = BdkWallet::create(desc.to_owned(), change.to_owned()) + .network(BdkNetwork::Regtest) + .create_wallet_no_persist() + .expect("build wallet"); + wallet.reveal_next_address(KeychainKind::External).address.to_string() +} + +async fn wait_for_esplora_height(url: &str, target: u64) -> Result<(), BoxSendSyncError> { + let deadline = std::time::Instant::now() + Duration::from_secs(60); + let client = reqwest::Client::new(); + let endpoint = format!("{}/blocks/tip/height", url.trim_end_matches('/')); + loop { + if let Ok(resp) = client.get(&endpoint).send().await { + if let Ok(text) = resp.text().await { + if let Ok(h) = text.trim().parse::() { + if h >= target { + return Ok(()); + } + } + } + } + if std::time::Instant::now() > deadline { + return Err(format!("esplora never reached height {target}").into()); + } + tokio::time::sleep(Duration::from_millis(250)).await; + } +} + +/// SIGINT a child and wait for it to exit. Ignores send/wait errors — +/// the child may already be gone by the time we get here. +pub async fn terminate(mut child: Child) { + if let Some(pid) = child.id() { + let _ = kill(Pid::from_raw(pid as i32), Signal::SIGINT); + } + let _ = child.wait().await; +} + +/// Spawn a background task that drains a child's stdout for its +/// lifetime, forwarding every line to the test process's stdout and +/// sending the first line matching `predicate` through a oneshot. +/// +/// Keeping the drain task alive past the first match is important: +/// if we stopped reading, the child's next stdout write would hit +/// EPIPE and the child would crash — catastrophic for long-running +/// v1 receivers that must keep serving requests after logging a URI. +pub fn match_line_background( + child: &mut Child, + predicate: F, +) -> tokio::sync::oneshot::Receiver> +where + F: Fn(&str) -> bool + Send + 'static, +{ + let stdout = child.stdout.take().expect("child stdout piped"); + let (tx, rx) = tokio::sync::oneshot::channel(); + tokio::spawn(async move { + let mut lines = BufReader::new(stdout).lines(); + let mut out = tokio::io::stdout(); + let mut tx = Some(tx); + while let Ok(Some(line)) = lines.next_line().await { + let _ = out.write_all(format!("{line}\n").as_bytes()).await; + if tx.is_some() && predicate(&line) { + let _ = tx.take().unwrap().send(Some(line)); + } + } + if let Some(sender) = tx.take() { + let _ = sender.send(None); + } + }); + rx +} + +/// Convenience wrapper around `match_line_background` with a timeout +/// and a human-readable label for error messages. +pub async fn wait_for_line( + child: &mut Child, + timeout: Duration, + label: &'static str, + predicate: F, +) -> Result +where + F: Fn(&str) -> bool + Send + 'static, +{ + let rx = match_line_background(child, predicate); + tokio::time::timeout(timeout, rx) + .await + .map_err(|_| format!("timed out waiting for {label}"))? + .map_err(|_| format!("stdout drain task for {label} dropped"))? + .ok_or_else(|| format!("{label} never appeared on stdout").into()) +} diff --git a/payjoin-cli/tests/e2e.rs b/payjoin-cli/tests/e2e.rs index 41691d491..b29136656 100644 --- a/payjoin-cli/tests/e2e.rs +++ b/payjoin-cli/tests/e2e.rs @@ -1,4 +1,7 @@ -#[cfg(feature = "_manual-tls")] +// The e2e tests drive the CLI with bitcoind RPC args, which only works when +// bitcoind is the selected backend. Skip them when esplora is enabled +// (e.g. `--all-features`) since create_wallet then prefers esplora. +#[cfg(all(feature = "_manual-tls", not(feature = "esplora")))] mod e2e { use std::process::{ExitStatus, Stdio}; diff --git a/payjoin-cli/tests/e2e_esplora.rs b/payjoin-cli/tests/e2e_esplora.rs new file mode 100644 index 000000000..58fde5be8 --- /dev/null +++ b/payjoin-cli/tests/e2e_esplora.rs @@ -0,0 +1,386 @@ +//! End-to-end coverage for the `esplora` wallet backend. +//! +//! Exercises the same three flows as `tests/e2e.rs` (v1, v2, v2→v1 +//! fallback) but drives the CLI with `--descriptor` / `--esplora-url` +//! instead of `--rpchost` / `--cookie-file`. Each test spins up its +//! own bitcoind + electrs-esplora fixture (`common::EsploraFixture`) +//! so they can run in parallel. v2 flows additionally reuse +//! `payjoin_test_utils::TestServices` for the ohttp relay + directory. + +#![cfg(all(feature = "esplora", feature = "v1", feature = "_manual-tls"))] + +mod common; + +use std::process::Stdio; +use std::time::Duration; + +use common::{terminate, wait_for_line, EsploraFixture, Side, RECEIVE_SATS}; +use payjoin_test_utils::{local_cert_key, BoxSendSyncError}; +use tempfile::tempdir; + +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +async fn send_receive_payjoin_v1_esplora() -> Result<(), BoxSendSyncError> { + let fx = EsploraFixture::new().await?; + let temp_dir = tempdir()?; + let dir = temp_dir.path(); + let receiver_db = dir.join("receiver_db"); + let sender_db = dir.join("sender_db"); + + let cert = local_cert_key(); + let cert_path = dir.join("localhost.crt"); + let key_path = dir.join("localhost.key"); + tokio::fs::write(&cert_path, cert.cert.der().to_vec()).await?; + tokio::fs::write(&key_path, cert.signing_key.serialize_der()).await?; + + let mut cli_receiver = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--certificate-key") + .arg(&key_path) + .arg("--bip78") + .arg("receive") + .arg(RECEIVE_SATS) + .arg("--port") + .arg("0") + .arg("--pj-endpoint") + .arg("https://localhost") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn payjoin-cli v1 receiver"); + + let bip21 = wait_for_line( + &mut cli_receiver, + Duration::from_secs(30), + "v1 receiver BIP21 URI", + |line| line.to_ascii_uppercase().starts_with("BITCOIN"), + ) + .await?; + tracing::debug!("Got bip21 {}", &bip21); + + let mut cli_sender = fx + .cli(Side::Sender, &sender_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--bip78") + .arg("send") + .arg(&bip21) + .arg("--fee-rate") + .arg("1") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn payjoin-cli v1 sender"); + + let _ = wait_for_line( + &mut cli_sender, + Duration::from_secs(30), + "'Payjoin sent' from v1 sender", + |line| line.contains("Payjoin sent"), + ) + .await?; + + terminate(cli_receiver).await; + terminate(cli_sender).await; + Ok(()) +} + +#[cfg(feature = "v2")] +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +async fn send_receive_payjoin_v2_esplora() -> Result<(), BoxSendSyncError> { + use payjoin_test_utils::{init_tracing, TestServices}; + + init_tracing(); + let fx = EsploraFixture::new().await?; + let mut services = TestServices::initialize().await?; + let temp_dir = tempdir()?; + + tokio::select! { + res = services.take_ohttp_relay_handle() => + Err::<(), BoxSendSyncError>(format!("ohttp relay is long running: {res:?}").into()), + res = services.take_directory_handle() => + Err(format!("directory server is long running: {res:?}").into()), + res = run_v2(&fx, &services, temp_dir.path()) => res, + } +} + +#[cfg(feature = "v2")] +async fn run_v2( + fx: &EsploraFixture, + services: &payjoin_test_utils::TestServices, + dir: &std::path::Path, +) -> Result<(), BoxSendSyncError> { + let receiver_db = dir.join("receiver_db"); + let sender_db = dir.join("sender_db"); + + let cert_path = dir.join("localhost.der"); + tokio::fs::write(&cert_path, services.cert()).await?; + services.wait_for_services_ready().await?; + let ohttp_keys = services.fetch_ohttp_keys().await?; + let ohttp_keys_path = dir.join("ohttp_keys"); + tokio::fs::write(&ohttp_keys_path, ohttp_keys.encode()?).await?; + + let directory = services.directory_url(); + let ohttp_relay = services.ohttp_relay_url(); + + // 1. Receiver initiator — enrolls with the directory and prints + // the BIP21 URI, then exits (v2 push-style). + let mut receiver_init = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("receive") + .arg(RECEIVE_SATS) + .arg("--pj-directory") + .arg(&directory) + .arg("--ohttp-keys") + .arg(&ohttp_keys_path) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 receiver initiator"); + + let bip21 = wait_for_line( + &mut receiver_init, + Duration::from_secs(30), + "v2 receiver BIP21 URI", + |line| line.to_ascii_uppercase().starts_with("BITCOIN"), + ) + .await?; + terminate(receiver_init).await; + + // 2. Sender initial attempt — polls for a response and eventually + // hits "No response yet." before its long-poll elapses. + let mut sender_init = fx + .cli(Side::Sender, &sender_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("send") + .arg(&bip21) + .arg("--fee-rate") + .arg("1") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 sender initiator"); + + let _ = wait_for_line( + &mut sender_init, + Duration::from_secs(45), + "'No response yet.' from sender", + |line| line.contains("No response yet."), + ) + .await?; + terminate(sender_init).await; + + // 3. Receiver resumer — picks up the pending session, responds to + // the sender's request with a payjoin PSBT. + let mut receiver_resume = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("resume") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 receiver resumer"); + + let _ = wait_for_line( + &mut receiver_resume, + Duration::from_secs(30), + "'Response successful' from receiver", + |line| line.contains("Response successful"), + ) + .await?; + terminate(receiver_resume).await; + + // 4. Sender resumer — finalizes and broadcasts, logs "Payjoin sent". + let mut sender_resume = fx + .cli(Side::Sender, &sender_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("send") + .arg(&bip21) + .arg("--fee-rate") + .arg("1") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 sender resumer"); + + let _ = wait_for_line( + &mut sender_resume, + Duration::from_secs(30), + "'Payjoin sent' from v2 sender", + |line| line.contains("Payjoin sent"), + ) + .await?; + terminate(sender_resume).await; + + // 5. Mine a block and resume the receiver so it picks up the + // confirmation and closes the session out. + fx.mine_one()?; + + let mut receiver_final = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("resume") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 receiver final resumer"); + + let _ = wait_for_line( + &mut receiver_final, + Duration::from_secs(30), + "'All resumed sessions completed.'", + |line| line.contains("All resumed sessions completed."), + ) + .await?; + terminate(receiver_final).await; + + // 6. Both sides should now report no more sessions to resume. + let mut receiver_empty = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("resume") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 receiver empty-resume check"); + + let _ = wait_for_line( + &mut receiver_empty, + Duration::from_secs(30), + "receiver 'No sessions to resume.'", + |line| line.contains("No sessions to resume."), + ) + .await?; + terminate(receiver_empty).await; + + let mut sender_empty = fx + .cli(Side::Sender, &sender_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("resume") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 sender empty-resume check"); + + let _ = wait_for_line( + &mut sender_empty, + Duration::from_secs(30), + "sender 'No sessions to resume.'", + |line| line.contains("No sessions to resume."), + ) + .await?; + terminate(sender_empty).await; + + Ok(()) +} + +/// Mirror of `e2e::send_receive_payjoin_v2_to_v1`: a v1 receiver +/// listens on HTTPS, and a v2-mode sender (no `--bip78`) auto-detects +/// the v1 URI emitted by the receiver and falls back to the BIP78 +/// transport to complete the payjoin. +#[cfg(feature = "v2")] +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +async fn send_receive_payjoin_v2_to_v1_esplora() -> Result<(), BoxSendSyncError> { + use payjoin_test_utils::{init_tracing, TestServices}; + + init_tracing(); + let fx = EsploraFixture::new().await?; + let services = TestServices::initialize().await?; + let temp_dir = tempdir()?; + let dir = temp_dir.path(); + + // v1 receiver listens over HTTPS with its own self-signed cert. + let cert = local_cert_key(); + let cert_path = dir.join("localhost.crt"); + let key_path = dir.join("localhost.key"); + tokio::fs::write(&cert_path, cert.cert.der().to_vec()).await?; + tokio::fs::write(&key_path, cert.signing_key.serialize_der()).await?; + + // Make sure the v2 services the sender reaches for (before + // deciding to fall back) are actually up. + services.wait_for_services_ready().await?; + + let receiver_db = dir.join("receiver_db"); + let sender_db = dir.join("sender_db"); + + let mut cli_receive_v1 = fx + .cli(Side::Receiver, &receiver_db) + .arg("--root-certificate") + .arg(&cert_path) + .arg("--certificate-key") + .arg(&key_path) + .arg("--bip78") + .arg("receive") + .arg(RECEIVE_SATS) + .arg("--port") + .arg("0") + .arg("--pj-endpoint") + .arg("https://localhost") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v1 receiver"); + + let bip21 = wait_for_line( + &mut cli_receive_v1, + Duration::from_secs(30), + "v1 receiver BIP21 URI", + |line| line.to_ascii_uppercase().starts_with("BITCOIN"), + ) + .await?; + tracing::debug!("Got v1 bip21 from receiver: {}", &bip21); + + // v2 sender, no `--bip78`: should detect the v1 BIP21 URI and + // fall back to the BIP78 transport against the receiver's HTTPS + // listener, same as tests/e2e.rs::send_receive_payjoin_v2_to_v1. + let ohttp_relay = services.ohttp_relay_url(); + let mut cli_send_v2 = fx + .cli(Side::Sender, &sender_db) + .arg("--root-certificate") + .arg(&cert_path) // receiver's self-signed cert, for the v1 fallback + .arg("--ohttp-relays") + .arg(&ohttp_relay) + .arg("send") + .arg(&bip21) + .arg("--fee-rate") + .arg("1") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("spawn v2 sender"); + + let _ = wait_for_line( + &mut cli_send_v2, + Duration::from_secs(45), + "'Payjoin sent' from v2→v1 sender", + |line| line.contains("Payjoin sent"), + ) + .await?; + + terminate(cli_receive_v1).await; + terminate(cli_send_v2).await; + Ok(()) +} From 3c9ec25a1ba9a3932b5fa46bac8823694c30b414 Mon Sep 17 00:00:00 2001 From: Benalleng Date: Wed, 8 Apr 2026 09:24:03 -0400 Subject: [PATCH 2/3] prevent electrsd network call during build for nix flake --- flake.nix | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 6f08866e3..6a4ab755e 100644 --- a/flake.nix +++ b/flake.nix @@ -128,6 +128,12 @@ } ) craneLibVersions; + # nixpkgs' blockstream-electrs build runs a flaky `test_electrum` + # integration test that fails on some sandboxes. Skip its checks. + blockstreamElectrs = pkgs.blockstream-electrs.overrideAttrs (_: { + doCheck = false; + }); + commonArgs = { inherit src; strictDeps = true; @@ -140,6 +146,8 @@ # tell bitcoind crate not to try to download during build BITCOIND_SKIP_DOWNLOAD = 1; + # same for electrsd (used in payjoin-cli esplora e2e tests) + ELECTRSD_SKIP_DOWNLOAD = 1; }; # Per-toolchain common args that include pre-vendored deps @@ -276,6 +284,8 @@ ]; BITCOIND_EXE = pkgs.lib.getExe' pkgs.bitcoind "bitcoind"; BITCOIND_SKIP_DOWNLOAD = 1; + ELECTRS_EXE = pkgs.lib.getExe' blockstreamElectrs "electrs"; + ELECTRSD_SKIP_DOWNLOAD = 1; } ) craneLibVersions; @@ -375,8 +385,12 @@ partitionType = "count"; cargoExtraArgs = "--locked --workspace --all-features --exclude payjoin-fuzz"; BITCOIND_EXE = nixpkgs.lib.getExe' pkgs.bitcoind "bitcoind"; + ELECTRS_EXE = nixpkgs.lib.getExe' blockstreamElectrs "electrs"; NGINX_EXE = nixpkgs.lib.getExe' nginxWithStream "nginx"; - nativeBuildInputs = [ nginxWithStream ]; + nativeBuildInputs = [ + nginxWithStream + blockstreamElectrs + ]; doInstallCargoArtifacts = false; } ) From acca696f6f9652e48c0079b92ef5218da29a67dc Mon Sep 17 00:00:00 2001 From: Benalleng Date: Wed, 8 Apr 2026 13:33:24 -0400 Subject: [PATCH 3/3] show esplora as a internal feature --- contrib/coverage.sh | 2 +- payjoin-cli/Cargo.toml | 4 ++-- payjoin-cli/contrib/lint.sh | 2 +- payjoin-cli/contrib/test.sh | 2 +- payjoin-cli/src/app/config.rs | 18 +++++++++--------- payjoin-cli/src/app/wallet.rs | 26 +++++++++++++------------- payjoin-cli/src/cli/mod.rs | 16 ++++++++-------- payjoin-cli/tests/cli_esplora.rs | 2 +- payjoin-cli/tests/e2e.rs | 2 +- payjoin-cli/tests/e2e_esplora.rs | 2 +- 10 files changed, 38 insertions(+), 38 deletions(-) diff --git a/contrib/coverage.sh b/contrib/coverage.sh index 33628ce66..dc6b54009 100755 --- a/contrib/coverage.sh +++ b/contrib/coverage.sh @@ -9,6 +9,6 @@ cargo llvm-cov --no-report --workspace --all-features --exclude payjoin-ffi --ex # Explicitly run payjoin-cli v1 e2e tests cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,_manual-tls,bitcoind # Explicitly run payjoin-cli esplora tests -cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,v2,_manual-tls,esplora +cargo llvm-cov --no-report --package payjoin-cli --no-default-features --features=v1,v2,_manual-tls,_esplora # generate report without tests cargo llvm-cov report --lcov --output-path lcov.info diff --git a/payjoin-cli/Cargo.toml b/payjoin-cli/Cargo.toml index 1ee44612a..bb2931957 100644 --- a/payjoin-cli/Cargo.toml +++ b/payjoin-cli/Cargo.toml @@ -19,12 +19,12 @@ path = "src/main.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["v2", "esplora"] +default = ["v2", "bitcoind"] native-certs = ["reqwest/rustls-tls-native-roots"] _manual-tls = ["reqwest/rustls-tls", "payjoin/_manual-tls", "tokio-rustls"] v1 = ["payjoin/v1", "hyper", "hyper-util", "http-body-util"] v2 = ["payjoin/v2", "payjoin/io"] -esplora = ["bdk_wallet", "bdk_esplora", "esplora-client"] +_esplora = ["bdk_wallet", "bdk_esplora", "esplora-client"] bitcoind = ["bitcoind-async-client"] [dependencies] diff --git a/payjoin-cli/contrib/lint.sh b/payjoin-cli/contrib/lint.sh index 58536f4fa..8f2550b72 100755 --- a/payjoin-cli/contrib/lint.sh +++ b/payjoin-cli/contrib/lint.sh @@ -4,7 +4,7 @@ set -e # Protocol versions and wallet backends are orthogonal; every version must # build against every backend, so lint them as a matrix. versions=("v1" "v2") -backends=("bitcoind" "esplora") +backends=("bitcoind" "_esplora") for version in "${versions[@]}"; do for backend in "${backends[@]}"; do diff --git a/payjoin-cli/contrib/test.sh b/payjoin-cli/contrib/test.sh index 4f54784f7..15a30c34b 100755 --- a/payjoin-cli/contrib/test.sh +++ b/payjoin-cli/contrib/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -e -cargo test --locked --package payjoin-cli --verbose --no-default-features --features "v1,v2,_manual-tls,esplora,native-certs" +cargo test --locked --package payjoin-cli --verbose --no-default-features --features "v1,v2,_manual-tls,_esplora,native-certs" cargo test --locked --package payjoin-cli --verbose --no-default-features --features "v1,v2,_manual-tls,bitcoind,native-certs" diff --git a/payjoin-cli/src/app/config.rs b/payjoin-cli/src/app/config.rs index 8bd393bf3..710877c75 100644 --- a/payjoin-cli/src/app/config.rs +++ b/payjoin-cli/src/app/config.rs @@ -15,7 +15,7 @@ const CONFIG_DIR: &str = "payjoin-cli"; type Builder = config::builder::ConfigBuilder; -#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] +#[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] #[derive(Debug, Clone, Deserialize)] pub struct BitcoindConfig { pub rpchost: Url, @@ -24,7 +24,7 @@ pub struct BitcoindConfig { pub rpcpassword: String, } -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] #[derive(Debug, Clone, Deserialize)] pub struct BdkWalletConfig { pub descriptor: Option, @@ -65,9 +65,9 @@ pub enum VersionConfig { pub struct Config { pub db_path: PathBuf, pub max_fee_rate: Option, - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] pub bitcoind: BitcoindConfig, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] pub wallet: Option, #[serde(skip)] pub version: Option, @@ -156,9 +156,9 @@ impl Config { let mut config = Config { db_path: built_config.get("db_path")?, max_fee_rate: built_config.get("max_fee_rate").ok(), - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] bitcoind: built_config.get("bitcoind")?, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] wallet: built_config.get("wallet").ok(), version: None, #[cfg(feature = "_manual-tls")] @@ -240,7 +240,7 @@ impl Config { } /// Set up default values and CLI overrides for wallet settings -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] fn add_wallet_defaults(config: Builder, cli: &Cli) -> Result { let config = config .set_default("wallet.descriptor", None::)? @@ -260,7 +260,7 @@ fn add_wallet_defaults(config: Builder, cli: &Cli) -> Result Result { let config = config .set_default("bitcoind.rpchost", "http://localhost:18443")? @@ -280,7 +280,7 @@ fn add_wallet_defaults(config: Builder, cli: &Cli) -> Result Result { Ok(config) } fn add_common_defaults(config: Builder, cli: &Cli) -> Result { diff --git a/payjoin-cli/src/app/wallet.rs b/payjoin-cli/src/app/wallet.rs index ab2ff9524..92117a655 100644 --- a/payjoin-cli/src/app/wallet.rs +++ b/payjoin-cli/src/app/wallet.rs @@ -34,7 +34,7 @@ pub trait PayjoinWallet: Send + Sync { fn network(&self) -> Result; } -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] mod esplora_backend { use std::collections::HashMap; use std::str::FromStr; @@ -241,7 +241,7 @@ mod esplora_backend { pub use BdkWallet as BdkWalletImpl; } -#[cfg(all(feature = "bitcoind", not(feature = "esplora")))] +#[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] mod bitcoind_backend { use std::collections::HashMap; use std::sync::Arc; @@ -449,13 +449,13 @@ mod bitcoind_backend { pub use BitcoindWallet as BitcoindWalletImpl; } -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] pub(crate) fn parse_network(name: Option<&str>) -> Result { use anyhow::anyhow; match name { // Mainnet currently disabled until an ohttp wrapper is available to encrypt // messages. https://github.com/bitcoindevkit/rust-esplora-client/pull/145 - Some("mainnet") | Some("bitcoin") | None => Err(anyhow!("Mainnet disabled for esplora")), + Some("mainnet") | Some("bitcoin") | None => Err(anyhow!("Mainnet disabled for _esplora")), Some("testnet") => Ok(Network::Testnet), Some("testnet4") => Ok(Network::Testnet4), Some("signet") => Ok(Network::Signet), @@ -471,7 +471,7 @@ pub(crate) fn parse_network(name: Option<&str>) -> Result { /// without a trailing `#checksum`. The checksum is dropped on rewrite — /// BDK recomputes it. If the descriptor does not match either shape it is /// returned unchanged (BDK will then use the same keychain for both). -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] pub(crate) fn derive_change_descriptor(descriptor: &str, change: Option<&str>) -> String { if let Some(c) = change { return c.to_owned(); @@ -490,7 +490,7 @@ pub(crate) fn derive_change_descriptor(descriptor: &str, change: Option<&str>) - } } -#[cfg(feature = "esplora")] +#[cfg(feature = "_esplora")] pub fn create_wallet(config: &super::config::Config) -> Result> { use anyhow::anyhow; @@ -518,17 +518,17 @@ pub fn create_wallet(config: &super::config::Config) -> Result Result> { use crate::app::wallet::bitcoind_backend::BitcoindWalletImpl; Ok(Arc::new(BitcoindWalletImpl::new(&config.bitcoind)?)) } -#[cfg(all(not(feature = "esplora"), not(feature = "bitcoind")))] +#[cfg(all(not(feature = "_esplora"), not(feature = "bitcoind")))] pub fn create_wallet(_config: &super::config::Config) -> Result> { Err(anyhow::anyhow!("No wallet backend enabled. Enable esplora or bitcoind feature.")) } diff --git a/payjoin-cli/src/cli/mod.rs b/payjoin-cli/src/cli/mod.rs index 80efcf197..4bd789679 100644 --- a/payjoin-cli/src/cli/mod.rs +++ b/payjoin-cli/src/cli/mod.rs @@ -34,23 +34,23 @@ pub struct Cli { #[arg(long = "max-fee-rate", short = 'f', help = "The maximum fee rate to accept in sat/vB")] pub max_fee_rate: Option, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] #[arg(long, num_args(1), help = "The wallet descriptor")] pub descriptor: Option, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] #[arg(long, num_args(1), help = "The optional change descriptor")] pub change_descriptor: Option, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] #[arg(long, num_args(1), help = "The esplora API URL")] pub esplora_url: Option, - #[cfg(feature = "esplora")] + #[cfg(feature = "_esplora")] #[arg(long, num_args(1), help = "The Bitcoin network to connect to")] pub network: Option, - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] #[arg( long, short = 'r', @@ -59,7 +59,7 @@ pub struct Cli { )] pub rpchost: Option, - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] #[arg( long = "cookie-file", short = 'c', @@ -68,11 +68,11 @@ pub struct Cli { )] pub cookie_file: Option, - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] #[arg(long = "rpcuser", num_args(1), help = "The username for the bitcoin node")] pub rpcuser: Option, - #[cfg(all(feature = "bitcoind", not(feature = "esplora")))] + #[cfg(all(feature = "bitcoind", not(feature = "_esplora")))] #[arg(long = "rpcpassword", num_args(1), help = "The password for the bitcoin node")] pub rpcpassword: Option, diff --git a/payjoin-cli/tests/cli_esplora.rs b/payjoin-cli/tests/cli_esplora.rs index 2353794c5..ad5d03a9d 100644 --- a/payjoin-cli/tests/cli_esplora.rs +++ b/payjoin-cli/tests/cli_esplora.rs @@ -5,7 +5,7 @@ //! Their job is to catch regressions in argument parsing, feature gating, //! and the missing-config error paths. -#![cfg(feature = "esplora")] +#![cfg(feature = "_esplora")] use std::process::Command; diff --git a/payjoin-cli/tests/e2e.rs b/payjoin-cli/tests/e2e.rs index b29136656..32d789fb5 100644 --- a/payjoin-cli/tests/e2e.rs +++ b/payjoin-cli/tests/e2e.rs @@ -1,7 +1,7 @@ // The e2e tests drive the CLI with bitcoind RPC args, which only works when // bitcoind is the selected backend. Skip them when esplora is enabled // (e.g. `--all-features`) since create_wallet then prefers esplora. -#[cfg(all(feature = "_manual-tls", not(feature = "esplora")))] +#[cfg(all(feature = "_manual-tls", not(feature = "_esplora")))] mod e2e { use std::process::{ExitStatus, Stdio}; diff --git a/payjoin-cli/tests/e2e_esplora.rs b/payjoin-cli/tests/e2e_esplora.rs index 58fde5be8..36873e8a2 100644 --- a/payjoin-cli/tests/e2e_esplora.rs +++ b/payjoin-cli/tests/e2e_esplora.rs @@ -7,7 +7,7 @@ //! so they can run in parallel. v2 flows additionally reuse //! `payjoin_test_utils::TestServices` for the ohttp relay + directory. -#![cfg(all(feature = "esplora", feature = "v1", feature = "_manual-tls"))] +#![cfg(all(feature = "_esplora", feature = "v1", feature = "_manual-tls"))] mod common;