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