diff --git a/Cargo.lock b/Cargo.lock index b1c67002..8d9ca68e 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstyle" version = "1.0.10" @@ -66,6 +75,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-stream" version = "0.3.6" @@ -218,6 +233,16 @@ dependencies = [ "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", + "bitcoin_hashes", +] + [[package]] name = "base64" version = "0.13.1" @@ -236,39 +261,147 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bdk_chain" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c290eff038799a8ac0c5a82b6160a9ca456baa299a6f22b262c771342d2846c0" +dependencies = [ + "bdk_core", + "bitcoin", + "miniscript", + "serde", +] + +[[package]] +name = "bdk_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3028782f6bf14a6df987244333d34e6b272b5a40a53e4879ec2dfd82275a3a" +dependencies = [ + "bitcoin", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "bdk_electrum" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b59a3f7fbe678874fa34354097644a171276e02a49934c13b3d61c54610ddf39" +dependencies = [ + "bdk_core", + "electrum-client", +] + +[[package]] +name = "bdk_esplora" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83986307ea92997c3d051e8c306af8115a05add601e22acb7c1903008e6b614e" +dependencies = [ + "async-trait", + "bdk_core", + "esplora-client", + "futures", +] + +[[package]] +name = "bdk_wallet" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03f1e31ccc562f600981f747d2262b84428cbff52c9c9cdf14d15fb15bd2286" +dependencies = [ + "bdk_chain", + "bip39", + "bitcoin", + "miniscript", + "rand_core 0.6.4", + "serde", + "serde_json", +] + [[package]] name = "bech32" -version = "0.9.1" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" + +[[package]] +name = "bip21" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe7a7f5928d264879d5b65eb18a72ea1890c57f22d62ee2eba93f207a6a020b" +dependencies = [ + "bitcoin", + "percent-encoding-rfc3986", +] + +[[package]] +name = "bip39" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "unicode-normalization", +] [[package]] name = "bitcoin" -version = "0.30.2" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ + "base58ck", + "base64 0.21.7", "bech32", - "bitcoin-private", + "bitcoin-internals", + "bitcoin-io", + "bitcoin-units", "bitcoin_hashes", + "hex-conservative", "hex_lit", "secp256k1", "serde", ] [[package]] -name = "bitcoin-private" -version = "0.1.0" +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" + +[[package]] +name = "bitcoin-units" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals", + "serde", +] [[package]] name = "bitcoin_hashes" -version = "0.12.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "bitcoin-private", + "bitcoin-io", + "hex-conservative", "serde", ] @@ -291,7 +424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.5.2", "constant_time_eq", ] @@ -334,6 +467,30 @@ 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 = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "chunked_transfer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" + [[package]] name = "clap" version = "4.5.34" @@ -375,22 +532,23 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cln-grpc" -version = "0.1.9" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d528ade112e169cbb79ceae2f235b4502fee6e939326bbaa36aafcdfd54cd91c" +checksum = "dbdc4ee84f8c5cc1212a7bec468b5e9256d9bb617b2e9677bb1d279832f50bb9" dependencies = [ "anyhow", "bitcoin", + "cfg-if", "futures-core", "hex", "log", - "prost 0.11.9", + "prost 0.12.6", "serde", "tokio", "tokio-stream", "tokio-util", - "tonic 0.8.3", - "tonic-build 0.8.4", + "tonic 0.11.0", + "tonic-build 0.11.0", ] [[package]] @@ -477,6 +635,31 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "corepc-client" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7755b8b9219b23d166a5897b5e2d8266cbdd0de5861d351b96f6db26bcf415f3" +dependencies = [ + "bitcoin", + "corepc-types", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "corepc-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22db78b0223b66f82f92b14345f06307078f76d94b18280431ea9bc6cd9cbb6" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -582,7 +765,7 @@ dependencies = [ "console", "shell-words", "tempfile", - "thiserror", + "thiserror 1.0.69", "zeroize", ] @@ -608,6 +791,12 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "dnssec-prover" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" + [[package]] name = "downcast" version = "0.11.0" @@ -620,6 +809,23 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "electrum-client" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" +dependencies = [ + "bitcoin", + "byteorder", + "libc", + "log", + "rustls 0.23.25", + "serde", + "serde_json", + "webpki-roots 0.25.4", + "winapi", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -651,6 +857,21 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "esplora-client" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f19e3ea99dbfbef0c1ec26d83e69de0c579f6aa6aaac4f44597805fcc27e97af" +dependencies = [ + "bitcoin", + "hex-conservative", + "log", + "reqwest", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "expanduser" version = "1.2.2" @@ -662,6 +883,18 @@ dependencies = [ "pwd", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.3.0" @@ -853,8 +1086,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -864,9 +1099,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -919,11 +1156,21 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[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" @@ -934,6 +1181,15 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -967,9 +1223,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec 0.7.6", +] [[package]] name = "hex_lit" @@ -979,11 +1238,11 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1134,6 +1393,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.2", "tower-service", + "webpki-roots 0.26.11", ] [[package]] @@ -1196,6 +1456,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -1404,12 +1688,66 @@ dependencies = [ "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 = "ldk-node" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830ef2d6b00f089fb6e3ac845370ebf0f35f9d11ce81b3a097c1580d2dce358" +dependencies = [ + "base64 0.22.1", + "bdk_chain", + "bdk_electrum", + "bdk_esplora", + "bdk_wallet", + "bip21", + "bip39", + "bitcoin", + "chrono", + "electrum-client", + "esplora-client", + "libc", + "lightning", + "lightning-background-processor", + "lightning-block-sync", + "lightning-invoice", + "lightning-liquidity", + "lightning-macros", + "lightning-net-tokio", + "lightning-persister", + "lightning-rapid-gossip-sync", + "lightning-transaction-sync", + "lightning-types", + "log", + "prost 0.11.9", + "rand 0.9.4", + "reqwest", + "rusqlite", + "rustls 0.23.25", + "serde", + "serde_json", + "tokio", + "vss-client-ng", + "winapi", +] + [[package]] name = "libc" version = "0.2.171" @@ -1423,26 +1761,169 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] -name = "lightning" -version = "0.0.123" +name = "libsqlite3-sys" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd92d4aa159374be430c7590e169b4a6c0fb79018f5bc4ea1bffde536384db3" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ - "bitcoin", - "hex-conservative", + "cc", + "pkg-config", + "vcpkg", ] [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "lightning" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "4c90397b635e3ece6b9a723fb470a46cb9b3592f217d72e40540a5fada00289d" +dependencies = [ + "bech32", + "bitcoin", + "dnssec-prover", + "hashbrown 0.13.2", + "libm", + "lightning-invoice", + "lightning-macros", + "lightning-types", + "possiblyrandom", +] [[package]] -name = "linux-raw-sys" -version = "0.9.3" +name = "lightning-background-processor" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "abdc5450264184deba88b1dc61fa8d2ca905e21748bad556915757ac73d91103" +dependencies = [ + "bitcoin", + "bitcoin-io", + "bitcoin_hashes", + "lightning", + "lightning-liquidity", + "lightning-rapid-gossip-sync", + "possiblyrandom", +] + +[[package]] +name = "lightning-block-sync" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee5069846b07a62aaecdaf25233e067bc69f245b7c8fd00cc9c217053221f875" +dependencies = [ + "bitcoin", + "chunked_transfer", + "lightning", + "serde_json", + "tokio", +] + +[[package]] +name = "lightning-invoice" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b85e5e14bcdb30d746e9785b04f27938292e8944f78f26517e01e91691f6b3f2" +dependencies = [ + "bech32", + "bitcoin", + "lightning-types", + "serde", +] + +[[package]] +name = "lightning-liquidity" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58a6480d4d7726c49b4cd170b18a39563bbe897d0b8960be11d5e4a0cebd43b0" +dependencies = [ + "bitcoin", + "chrono", + "lightning", + "lightning-invoice", + "lightning-macros", + "lightning-types", + "serde", + "serde_json", +] + +[[package]] +name = "lightning-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c717494cdc2c8bb85bee7113031248f5f6c64f8802b33c1c9e2d98e594aa71" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "lightning-net-tokio" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8055737e3d2d06240a3fdf10e26b2716110fcea90011a0839e8e82fc6e58ff5e" +dependencies = [ + "bitcoin", + "lightning", + "tokio", +] + +[[package]] +name = "lightning-persister" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d78990de56ca75c5535c3f8e6f86b183a1aa8f521eb32afb9e8181f3bd91d7" +dependencies = [ + "bitcoin", + "lightning", + "tokio", + "windows-sys 0.48.0", +] + +[[package]] +name = "lightning-rapid-gossip-sync" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b094f79f22713aa95194a166c77b2f6c7d68f9d76622a43552a29b8fe6fa92d0" +dependencies = [ + "bitcoin", + "bitcoin-io", + "bitcoin_hashes", + "lightning", +] + +[[package]] +name = "lightning-transaction-sync" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7260095a79a44b09ebd97e77855ec8b7996ab939223369f66244974a374bd2c" +dependencies = [ + "bitcoin", + "electrum-client", + "esplora-client", + "futures", + "lightning", + "lightning-macros", +] + +[[package]] +name = "lightning-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1aac93f22f2c2eac8a0ee83bb1a1ea58673caa2c82847302710b83364d04e6" +dependencies = [ + "bitcoin", +] + +[[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.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" @@ -1462,9 +1943,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "matchers" @@ -1509,6 +1996,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[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.5" @@ -1518,6 +2016,16 @@ dependencies = [ "adler2", ] +[[package]] +name = "minreq" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "mio" version = "1.0.3" @@ -1568,7 +2076,7 @@ dependencies = [ "log", "parking_lot", "queue-ext", - "rand", + "rand 0.8.5", "std-ext", ] @@ -1779,6 +2287,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "percent-encoding-rfc3986" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3637c05577168127568a64e9dc5a6887da720efef07b3d9472d45f63ab191166" + [[package]] name = "petgraph" version = "0.6.5" @@ -1827,6 +2341,15 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "possiblyrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b122a615d72104fb3d8b26523fdf9232cd8ee06949fb37e4ce3ff964d15dffd" +dependencies = [ + "getrandom 0.2.15", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2052,7 +2575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c71c0c79b9701efe4e1e4b563b2016dd4ee789eb99badcb09d61ac4b92e4a2" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2067,6 +2590,61 @@ dependencies = [ "pin-project-lite", ] +[[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.25", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.2", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls 0.23.25", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "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.59.0", +] + [[package]] name = "quote" version = "1.0.40" @@ -2089,8 +2667,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -2100,7 +2688,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "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.5", ] [[package]] @@ -2112,6 +2710,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.2", +] + [[package]] name = "rand_distr" version = "0.4.3" @@ -2119,7 +2726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -2201,6 +2808,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.8", @@ -2220,7 +2828,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.25", "rustls-pemfile 2.2.0", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -2228,30 +2839,18 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.2", + "tokio-socks", "tower 0.5.2", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.26.11", "windows-registry", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.14" @@ -2262,10 +2861,24 @@ dependencies = [ "cfg-if", "getrandom 0.2.15", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] +[[package]] +name = "rusqlite" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" +dependencies = [ + "bitflags 2.9.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rust-argon2" version = "0.8.3" @@ -2284,6 +2897,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustix" version = "0.38.44" @@ -2312,26 +2931,28 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.9" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.16.20", + "ring", + "rustls-webpki 0.101.7", "sct", - "webpki", ] [[package]] name = "rustls" -version = "0.21.12" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.14", - "rustls-webpki 0.101.7", - "sct", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", ] [[package]] @@ -2340,7 +2961,9 @@ version = "0.23.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" dependencies = [ + "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki 0.103.1", "subtle", @@ -2370,6 +2993,9 @@ name = "rustls-pki-types" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -2377,8 +3003,19 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -2387,9 +3024,9 @@ version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ - "ring 0.17.14", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -2425,26 +3062,27 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes", + "rand 0.8.5", "secp256k1-sys", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -2569,7 +3207,7 @@ dependencies = [ "hex", "log", "openssl", - "rand", + "rand 0.8.5", "serde", "serde_json", "simln-lib", @@ -2587,28 +3225,30 @@ dependencies = [ "async-trait", "bitcoin", "cln-grpc", + "corepc-client", "csv", "expanduser", "fedimint-tonic-lnd", "futures", "hex", + "ldk-node", "lightning", "log", "mockall", "mpsc", "ntest", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_distr", "reqwest", "serde", "serde_json", "serde_millis", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-util", - "tonic 0.8.3", + "tonic 0.11.0", "triggered", ] @@ -2649,12 +3289,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2776,7 +3410,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", ] [[package]] @@ -2790,6 +3433,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -2843,6 +3497,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +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.44.1" @@ -2895,22 +3564,22 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.20.9", + "rustls 0.21.12", "tokio", - "webpki", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.21.12", + "rustls 0.22.4", + "rustls-pki-types", "tokio", ] @@ -2924,6 +3593,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-socks" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" +dependencies = [ + "either", + "futures-util", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -2970,17 +3651,15 @@ dependencies = [ [[package]] name = "tonic" -version = "0.8.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ "async-stream", "async-trait", "axum 0.6.20", - "base64 0.13.1", + "base64 0.21.7", "bytes", - "futures-core", - "futures-util", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", @@ -2988,25 +3667,23 @@ dependencies = [ "hyper-timeout 0.4.1", "percent-encoding", "pin-project", - "prost 0.11.9", - "prost-derive 0.11.9", + "prost 0.12.6", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls 0.24.1", "tokio-stream", - "tokio-util", "tower 0.4.13", "tower-layer", "tower-service", "tracing", - "tracing-futures", ] [[package]] name = "tonic" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", @@ -3021,10 +3698,10 @@ dependencies = [ "percent-encoding", "pin-project", "prost 0.12.6", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls-pemfile 2.2.0", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls 0.25.0", "tokio-stream", "tower 0.4.13", "tower-layer", @@ -3064,22 +3741,22 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.8.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" dependencies = [ - "prettyplease 0.1.25", + "prettyplease 0.2.31", "proc-macro2", - "prost-build 0.11.9", + "prost-build 0.12.6", "quote", - "syn 1.0.109", + "syn 2.0.100", ] [[package]] name = "tonic-build" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" +checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" dependencies = [ "prettyplease 0.2.31", "proc-macro2", @@ -3099,7 +3776,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util", @@ -3168,16 +3845,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -3218,16 +3885,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "unicode-width" -version = "0.2.0" +name = "unicode-normalization" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] [[package]] -name = "untrusted" -version = "0.7.1" +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "untrusted" @@ -3276,6 +3946,28 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vss-client-ng" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05f61751537ec3e7cf744e6ed8a56830b8d048f9862871cb4b9c239e3d23b45" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bitcoin", + "bitcoin_hashes", + "chacha20-poly1305", + "log", + "prost 0.11.9", + "prost-build 0.11.9", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "tokio", + "url", +] + [[package]] name = "want" version = "0.3.1" @@ -3388,13 +4080,37 @@ dependencies = [ ] [[package]] -name = "webpki" -version = "0.22.4" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "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 = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", ] [[package]] @@ -3431,20 +4147,61 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "windows-link" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-registry" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result", - "windows-strings", + "windows-result 0.3.2", + "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -3454,7 +4211,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-link", + "windows-link 0.1.1", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3463,7 +4229,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link", + "windows-link 0.1.1", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -3493,6 +4268,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/sim-cli/Cargo.toml b/sim-cli/Cargo.toml index 6e4a9ac4..76c86d6a 100755 --- a/sim-cli/Cargo.toml +++ b/sim-cli/Cargo.toml @@ -20,7 +20,7 @@ serde_json = "1.0.104" simple_logger = "4.2.0" simln-lib = { path = "../simln-lib" } tokio = { version = "1.26.0", features = ["full"] } -bitcoin = { version = "0.30.1" } +bitcoin = { version = "0.32" } ctrlc = "3.4.0" rand = "0.8.5" hex = {version = "0.4.3"} diff --git a/sim-cli/src/parsing.rs b/sim-cli/src/parsing.rs index c5b06b7f..6a9e0217 100755 --- a/sim-cli/src/parsing.rs +++ b/sim-cli/src/parsing.rs @@ -9,7 +9,7 @@ use simln_lib::sim_node::{ SimGraph, SimNode, SimulatedChannel, }; use simln_lib::{ - cln, cln::ClnNode, eclair, eclair::EclairNode, lnd, lnd::LndNode, serializers, + cln, cln::ClnNode, eclair, eclair::EclairNode, ldk, lnd, lnd::LndNode, serializers, ActivityDefinition, Amount, Interval, LightningError, LightningNode, NodeId, NodeInfo, Simulation, SimulationCfg, WriteResults, }; @@ -152,6 +152,9 @@ pub struct SimParams { pub activity: Vec, #[serde(default)] pub exclude: Vec, + /// Optional hub configuration. See [`ldk::LdkHubConfig`] for how absence is interpreted. + #[serde(default)] + pub ldk_hub: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -160,6 +163,7 @@ pub enum NodeConnection { Lnd(lnd::LndConnection), Cln(cln::ClnConnection), Eclair(eclair::EclairConnection), + Ldk(ldk::LdkNodeConfig), } /// Data structure that is used to parse information from the simulation file. It is used to @@ -260,6 +264,7 @@ pub async fn create_simulation_with_network( sim_network, activity: _activity, exclude, + ldk_hub: _, } = sim_params; // Convert nodes representation for parsing to SimulatedChannel @@ -351,9 +356,10 @@ pub async fn create_simulation( sim_network: _sim_network, activity: _activity, exclude: _, + ldk_hub: _, } = sim_params; - let (clients, clients_info) = get_clients(nodes.to_vec()).await?; + let (clients, clients_info) = get_clients(nodes.to_vec(), sim_params.ldk_hub.clone()).await?; let (shutdown_trigger, shutdown_listener) = triggered::trigger(); let validated_activities = @@ -374,10 +380,9 @@ pub async fn create_simulation( )) } -/// Connects to the set of nodes providing, returning a map of node public keys to LightningNode implementations and -/// a map of public key to node info to be used for validation. async fn get_clients( nodes: Vec, + ldk_hub: Option, ) -> Result< ( HashMap>>, @@ -388,18 +393,32 @@ async fn get_clients( let mut clients: HashMap>> = HashMap::new(); let mut clients_info: HashMap = HashMap::new(); - for connection in nodes { - // TODO: Feels like there should be a better way of doing this without having to Arc>> it at this time. - // Box sort of works, but we won't know the size of the dyn LightningNode at compile time so the compiler will - // scream at us when trying to create the Arc> later on while adding the node to the clients map + let (ldk_connections, other_connections): (Vec<_>, Vec<_>) = + nodes.into_iter().partition(|n| matches!(n, NodeConnection::Ldk(_))); + + let ldk_configs: Vec = ldk_connections + .into_iter() + .filter_map(|n| match n { + NodeConnection::Ldk(cfg) => Some(cfg), + _ => None, + }) + .collect(); + + for ldk_node in ldk::build_ldk_nodes(ldk_configs, ldk_hub).await? { + let info = ldk_node.get_info().clone(); + let node: Arc> = Arc::new(Mutex::new(ldk_node)); + clients.insert(info.pubkey, node); + clients_info.insert(info.pubkey, info); + } + + for connection in other_connections { let node: Arc> = match connection { NodeConnection::Lnd(c) => Arc::new(Mutex::new(LndNode::new(c).await?)), NodeConnection::Cln(c) => Arc::new(Mutex::new(ClnNode::new(c).await?)), NodeConnection::Eclair(c) => Arc::new(Mutex::new(EclairNode::new(c).await?)), + NodeConnection::Ldk(_) => unreachable!(), }; - let node_info = node.lock().await.get_info().clone(); - clients.insert(node_info.pubkey, node); clients_info.insert(node_info.pubkey, node_info); } diff --git a/simln-lib/Cargo.toml b/simln-lib/Cargo.toml index 39d2f5ca..b276b6fd 100755 --- a/simln-lib/Cargo.toml +++ b/simln-lib/Cargo.toml @@ -10,15 +10,17 @@ Components to build a network-agnostic lightning payments simulator. Used as the # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ldk-node = "0.7.0" +corepc-client = { version = "0.10.0", features = ["client-sync"] } anyhow = { version = "1.0.69", features = ["backtrace"] } -cln-grpc = "0.1.3" +cln-grpc = "0.6.0" expanduser = "1.2.2" serde = { version="1.0.183", features=["derive"] } serde_json = "1.0.104" -bitcoin = { version = "0.30.1", features=["serde"] } -lightning = { version = "0.0.123" } +bitcoin = { version = "0.32", features=["serde"] } +lightning = { version = "0.2.2" } tonic_lnd = { package="fedimint-tonic-lnd", version="0.1.2", features=["lightningrpc", "routerrpc"]} -tonic = { version = "0.8", features = ["tls", "transport"] } +tonic = { version = "0.11", features = ["tls", "transport"] } async-trait = "0.1.73" thiserror = "1.0.45" log = "0.4.20" diff --git a/simln-lib/src/cln.rs b/simln-lib/src/cln.rs index 5bfa1aa0..a3bff1d7 100644 --- a/simln-lib/src/cln.rs +++ b/simln-lib/src/cln.rs @@ -8,8 +8,8 @@ use cln_grpc::pb::{ KeysendRequest, KeysendResponse, ListchannelsRequest, ListnodesRequest, ListpaysRequest, ListpaysResponse, }; -use lightning::ln::features::NodeFeatures; -use lightning::ln::PaymentHash; +use lightning::types::features::NodeFeatures; +use lightning::types::payment::PaymentHash; use serde::{Deserialize, Serialize}; use tokio::fs::File; use tokio::io::{AsyncReadExt, Error}; @@ -94,7 +94,7 @@ impl ClnNode { let pubkey = PublicKey::from_slice(&info.id) .map_err(|err| LightningError::GetInfoError(err.to_string()))?; - let mut alias = info.alias.unwrap_or_default(); + let mut alias = info.alias; connection.id.validate(&pubkey, &mut alias)?; let features = match info.our_features { @@ -216,8 +216,8 @@ impl LightningNode for ClnNode { .into_inner(); if let Some(pay) = pays.first() { - let payment_status = ListpaysPaysStatus::from_i32(pay.status) - .ok_or(LightningError::TrackPaymentError("Invalid payment status".to_string()))?; + let payment_status = ListpaysPaysStatus::try_from(pay.status) + .map_err(|_| LightningError::TrackPaymentError("Invalid payment status".to_string()))?; let payment_outcome = match payment_status { ListpaysPaysStatus::Pending => continue, diff --git a/simln-lib/src/eclair.rs b/simln-lib/src/eclair.rs index bea94575..90d9b4cd 100644 --- a/simln-lib/src/eclair.rs +++ b/simln-lib/src/eclair.rs @@ -5,8 +5,8 @@ use crate::{ use async_trait::async_trait; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; -use lightning::ln::features::NodeFeatures; -use lightning::ln::{PaymentHash, PaymentPreimage}; +use lightning::types::features::NodeFeatures; +use lightning::types::payment::{PaymentHash, PaymentPreimage}; use reqwest::multipart::Form; use reqwest::{Client, Method, Url}; use serde::{Deserialize, Serialize}; diff --git a/simln-lib/src/latency_interceptor.rs b/simln-lib/src/latency_interceptor.rs index 9034b8b1..70e64673 100644 --- a/simln-lib/src/latency_interceptor.rs +++ b/simln-lib/src/latency_interceptor.rs @@ -59,7 +59,7 @@ mod tests { use crate::sim_node::{CustomRecords, HtlcRef, InterceptRequest}; use crate::test_utils::get_random_keypair; use crate::ShortChannelID; - use lightning::ln::PaymentHash; + use lightning::types::payment::PaymentHash; use ntest::assert_true; use rand::distributions::Distribution; use rand::Rng; diff --git a/simln-lib/src/ldk.rs b/simln-lib/src/ldk.rs new file mode 100644 index 00000000..a6a40386 --- /dev/null +++ b/simln-lib/src/ldk.rs @@ -0,0 +1,809 @@ +use crate::{ + serializers, Graph, LightningError, LightningNode, Listener, Network, NodeId, NodeInfo, + PaymentHash, PaymentOutcome, PaymentResult, PublicKey, +}; +use async_trait::async_trait; +use corepc_client::client_sync::{v17::Client as BitcoindClient, Auth}; +use ldk_node::lightning::ln::channelmanager::PaymentId; +use ldk_node::payment::PaymentStatus; +use ldk_node::{Builder, Event, Node}; +use lightning::routing::gossip::NodeId as LightningNodeId; +use lightning::types::features::NodeFeatures; +use log::{debug, info, warn}; +use serde::{Deserialize, Serialize}; +use std::net::TcpListener; +use std::path::PathBuf; +use std::sync::Arc; + +/// Total capacity of each leaf→hub channel in sats. +// const CHANNEL_CAPACITY_SATS: u64 = 10_000_000; +const CHANNEL_CAPACITY_SATS: u64 = 10_000; +/// Amount pushed to the hub at channel open (in msat), giving each side equal liquidity. +const PUSH_MSAT: u64 = CHANNEL_CAPACITY_SATS * 1000 / 2; +/// On-chain fee buffer added on top of channel capacity when computing required funding. +const FUNDING_FEE_RESERVE_SATS: u64 = 50_000; + +pub struct LdkNode { + node: Arc, + info: NodeInfo, + network: Network, + pub listening_addr: String, + _shutdown: triggered::Trigger, +} + +/// Maps any displayable error to `LightningError::ConnectionError`. +fn conn_err(e: E) -> LightningError { + LightningError::ConnectionError(e.to_string()) +} + +/// Runs a synchronous closure with a fresh `BitcoindClient`, handling the +/// `spawn_blocking` boilerplate and mapping all errors to `LightningError`. +async fn with_bitcoind(url: String, auth: Auth, f: F) -> Result +where + F: FnOnce(BitcoindClient) -> Result + Send + 'static, + R: Send + 'static, +{ + tokio::task::spawn_blocking(move || { + let client = BitcoindClient::new_with_auth(&url, auth).map_err(conn_err)?; + f(client) + }) + .await + .map_err(|e| LightningError::ConnectionError(format!("task join error: {e}")))? +} + +/// Sets up channels between leaf LDK nodes and the hub. +/// +/// When `bitcoind_rpc_creds` is `Some`, mines to leaf addresses on regtest to fund +/// them, then mines blocks to confirm channels. When `None` (non-regtest network or +/// Electrum/Esplora chain source), prints each leaf node's on-chain address and the +/// required funding amount, then waits for the user to fund them externally before +/// proceeding to open channels and waiting for natural confirmations. +pub async fn setup_ldk_channels( + bitcoind_rpc_creds: Option<(String, u16, String, String)>, + nodes: &mut Vec, +) -> Result<(), LightningError> { + // When using bitcoind_rpc, verify connectivity with a direct RPC call before + // proceeding. ldk-node's sync_wallets() swallows chain-source errors internally + // and returns Ok regardless, so we need an explicit check here. + if let Some((rpc_host, rpc_port, rpc_user, rpc_password)) = &bitcoind_rpc_creds { + let url = format!("http://{}:{}", rpc_host, rpc_port); + let auth = Auth::UserPass(rpc_user.clone(), rpc_password.clone()); + with_bitcoind(url, auth, |bitcoind| { + bitcoind.get_block_count().map_err(conn_err)?; + Ok(()) + }) + .await + .map_err(|e| LightningError::ConnectionError(format!("bitcoind unreachable: {e}")))?; + } + + // Sync all nodes so LDK updates stale persisted channel state (e.g. after a + // chain reset, funding TXOs will be seen as spent and channels marked closed). + for node in nodes.iter() { + node.node.sync_wallets().map_err(|e| { + LightningError::ConnectionError(format!("[{}] chain sync failed: {e}", node.info.alias)) + })?; + } + + let leaf_count = nodes.len().saturating_sub(1); + + // If every leaf already has a ready channel (e.g. persisted from a prior run), + // there is nothing to fund or open. + if leaf_count > 0 + && nodes + .iter() + .take(leaf_count) + .all(|n| n.node.list_channels().iter().any(|c| c.is_channel_ready)) + { + info!("All LDK leaf nodes already have ready channels; skipping funding setup."); + return Ok(()); + } + + if nodes.len() < 2 { + return Ok(()); + } + + // Phase 1: ensure leaves have on-chain funds to open channels. + match &bitcoind_rpc_creds { + Some((rpc_host, rpc_port, rpc_user, rpc_password)) => { + fund_leaves_regtest( + nodes, + leaf_count, + rpc_host, + *rpc_port, + rpc_user, + rpc_password, + ) + .await? + }, + None => fund_leaves_external(nodes, leaf_count).await?, + } + + // Phase 2: connect leaves to hub and open channels. + open_channels_to_hub(nodes, leaf_count).await?; + + // Phase 3: wait for channels to become ready, mining blocks on regtest to + // speed up confirmation. + if let Some((rpc_host, rpc_port, rpc_user, rpc_password)) = &bitcoind_rpc_creds { + mine_channel_confirmations(nodes, rpc_host, *rpc_port, rpc_user, rpc_password).await?; + } + wait_for_channels_ready(nodes, leaf_count).await; + + Ok(()) +} + +/// Mines coins to each leaf address and waits for the blocks to be seen by the first node. +async fn fund_leaves_regtest( + nodes: &[LdkNode], + leaf_count: usize, + rpc_host: &str, + rpc_port: u16, + rpc_user: &str, + rpc_password: &str, +) -> Result<(), LightningError> { + let leaf_addresses: Vec<_> = nodes + .iter() + .take(leaf_count) + .map(|n| n.node.onchain_payment().new_address().map_err(conn_err)) + .collect::>()?; + + let url = format!("http://{}:{}", rpc_host, rpc_port); + let auth = Auth::UserPass(rpc_user.to_string(), rpc_password.to_string()); + let target_height = with_bitcoind(url, auth, move |bitcoind| { + let current: u64 = bitcoind.get_block_count().map_err(conn_err)?.0; + for addr in &leaf_addresses { + bitcoind.generate_to_address(3, addr).map_err(conn_err)?; + } + // Extra blocks so coinbase rewards reach maturity. + bitcoind + .generate_to_address(105, &leaf_addresses[0]) + .map_err(conn_err)?; + Ok(current + leaf_addresses.len() as u64 + 100) + }) + .await?; + + let first_node = &nodes[0]; + loop { + let best = first_node.node.status().current_best_block; + if u64::from(best.height) >= target_height { + info!("Funding confirmed at block {:?}", best); + break; + } + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + } + + Ok(()) +} + +/// Prints on-chain addresses for leaves that need funding and waits until they are all funded. +async fn fund_leaves_external(nodes: &[LdkNode], leaf_count: usize) -> Result<(), LightningError> { + let required_sats = CHANNEL_CAPACITY_SATS + FUNDING_FEE_RESERVE_SATS; + let unfunded: Vec<_> = nodes + .iter() + .take(leaf_count) + .filter(|n| n.node.list_balances().spendable_onchain_balance_sats < required_sats) + .collect(); + + if unfunded.is_empty() { + return Ok(()); + } + + info!( + "LDK nodes need on-chain funding ({} sats each). Send to the following addresses:", + required_sats + ); + for node in &unfunded { + let addr = node + .node + .onchain_payment() + .new_address() + .map_err(conn_err)?; + info!(" {} → {}", node.info.alias, addr); + } + + loop { + for node in nodes.iter().take(leaf_count) { + let _ = node.node.sync_wallets(); + } + let all_funded = nodes + .iter() + .take(leaf_count) + .all(|n| n.node.list_balances().spendable_onchain_balance_sats >= required_sats); + if all_funded { + info!("All LDK nodes are funded; proceeding to open channels."); + break; + } + tokio::time::sleep(std::time::Duration::from_secs(10)).await; + } + + Ok(()) +} + +/// Connects each leaf to the hub and opens a channel from each leaf to the hub. +async fn open_channels_to_hub(nodes: &[LdkNode], leaf_count: usize) -> Result<(), LightningError> { + let hub = nodes + .last() + .ok_or_else(|| LightningError::ConnectionError("no hub node found".to_string()))?; + + info!( + "Hub '{}' spendable balance: {} sats", + hub.info.alias, + hub.node.list_balances().spendable_onchain_balance_sats + ); + + let hub_pubkey = + ldk_node::bitcoin::secp256k1::PublicKey::from_slice(&hub.info.pubkey.serialize()) + .map_err(conn_err)?; + let hub_addr = hub + .listening_addr + .parse::() + .map_err(|e| LightningError::ConnectionError(format!("invalid hub listening_addr: {e}")))?; + + for node in nodes.iter().take(leaf_count) { + if let Err(e) = node.node.connect(hub_pubkey, hub_addr.clone(), true) { + warn!("[{}] connect to hub failed: {:?}", node.info.alias, e); + } + } + tokio::time::sleep(std::time::Duration::from_millis(2000)).await; + + // Sync wallets so each leaf sees its UTXOs before opening channels. + for node in nodes.iter().take(leaf_count) { + if let Err(e) = node.node.sync_wallets() { + warn!("[{}] sync_wallets failed: {:?}", node.info.alias, e); + } + } + + for node in nodes.iter().take(leaf_count) { + let res = node.node.open_announced_channel( + hub_pubkey, + hub_addr.clone(), + CHANNEL_CAPACITY_SATS, + Some(PUSH_MSAT), + None, + ); + info!("open_channel '{}' → hub: {:?}", node.info.alias, res); + } + + Ok(()) +} + +/// Mines blocks to confirm the pending channels, then waits for the node to see them. +async fn mine_channel_confirmations( + nodes: &[LdkNode], + rpc_host: &str, + rpc_port: u16, + rpc_user: &str, + rpc_password: &str, +) -> Result<(), LightningError> { + let hub = nodes + .last() + .ok_or_else(|| LightningError::ConnectionError("no hub node found".to_string()))?; + + let confirm_addr = hub.node.onchain_payment().new_address().map_err(conn_err)?; + + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + let url = format!("http://{}:{}", rpc_host, rpc_port); + let auth = Auth::UserPass(rpc_user.to_string(), rpc_password.to_string()); + with_bitcoind(url, auth, move |bitcoind| { + bitcoind + .generate_to_address(40, &confirm_addr) + .map_err(conn_err)?; + Ok(()) + }) + .await?; + + let confirm_target = u64::from(nodes[0].node.status().current_best_block.height) + 8; + loop { + let best = nodes[0].node.status().current_best_block; + info!("waiting for confirmation, best block: {:?}", best); + if u64::from(best.height) >= confirm_target { + break; + } + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + } + + Ok(()) +} + +/// Polls until all leaf nodes have at least one ready channel. +async fn wait_for_channels_ready(nodes: &[LdkNode], leaf_count: usize) { + loop { + for node in nodes.iter() { + if let Err(e) = node.node.sync_wallets() { + warn!("[{}] sync_wallets failed: {:?}", node.info.alias, e); + } + } + let all_ready = nodes + .iter() + .take(leaf_count) + .all(|n| n.node.list_channels().iter().any(|c| c.is_channel_ready)); + if all_ready { + info!("All channels ready."); + break; + } + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + } +} + +/// Chain data source configuration for ldk-node. +/// Maps to Builder::set_chain_source_* methods. +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum ChainSourceConfig { + Esplora { + server_url: String, + }, + Electrum { + server_url: String, + }, + #[serde(rename = "bitcoind_rpc")] + BitcoindRpcClientConfig { + rpc_host: String, + rpc_port: u16, + rpc_user: String, + rpc_password: String, + }, + #[serde(rename = "bitcoind_rest")] + BitcoindRestClientConfig { + rest_host: String, + rest_port: u16, + rpc_host: String, + rpc_port: u16, + rpc_user: String, + rpc_password: String, + }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LdkNodeConfig { + #[serde(with = "serializers::serde_node_id")] + pub id: NodeId, + pub chain_source: ChainSourceConfig, + pub network: Network, + pub listening_addr: String, + /// Directory where LDK node state (keys, channels, gossip) is persisted across runs. + /// If `None`, a temporary directory is used and all state is discarded on exit. + /// Set this to a stable path to survive restarts and avoid re-funding/re-opening channels. + #[serde(default)] + pub storage_dir: Option, +} + +/// Configuration for the hub node that sim-ln injects to connect leaf LDK nodes. +/// +/// Absence of this field in `sim.json` is interpreted per-network: +/// - On `Regtest` with `bitcoind_rpc`: sim-ln auto-injects a hub with all fields defaulted. +/// - On any other network or chain source: no hub is injected; leaves are expected to have +/// channels via an external source or persisted from a prior run. +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct LdkHubConfig { + /// Address the hub listens on. If `None`, a free loopback port is picked at start time. + #[serde(default)] + pub listening_addr: Option, + /// Directory where the hub's LDK state is persisted. If `None`, a throwaway temp + /// directory is used. + #[serde(default)] + pub storage_dir: Option, +} + +/// Asks the OS for a free TCP port on the loopback interface and returns it as +/// `127.0.0.1:`. The listener is dropped immediately so the caller can rebind. +fn pick_free_loopback_addr() -> Result { + let listener = TcpListener::bind("127.0.0.1:0")?; + let port = listener.local_addr()?.port(); + Ok(format!("127.0.0.1:{}", port)) +} + +/// Builds and starts all LDK nodes, injecting a hub when appropriate, and sets up +/// channels between the leaf nodes and the hub. +/// +/// A hub is injected when: +/// - `hub` is `Some(_)` and at least one LDK config is present, OR +/// - `hub` is `None` and the first node is on `Regtest` with `BitcoindRpc` (auto-inject). +/// +/// When a hub is injected, `setup_ldk_channels` is called to fund and open channels. +/// The bitcoind RPC credentials are forwarded when available so the fast mining path +/// (regtest) is used; otherwise leaves are funded externally. +pub async fn build_ldk_nodes( + configs: Vec, + hub: Option, +) -> Result, LightningError> { + if configs.is_empty() { + return Ok(vec![]); + } + + // Mining (and therefore hub auto-funding) requires Regtest + BitcoindRpc. + let can_mine = configs[0].network == Network::Regtest + && matches!( + configs[0].chain_source, + ChainSourceConfig::BitcoindRpcClientConfig { .. } + ); + + let inject_hub = match &hub { + Some(_) => true, + None => can_mine, + }; + + // Extract bitcoind creds before consuming configs — needed later for channel setup. + let bitcoind_creds = match &configs[0].chain_source { + ChainSourceConfig::BitcoindRpcClientConfig { + rpc_host, + rpc_port, + rpc_user, + rpc_password, + } => Some(( + rpc_host.clone(), + *rpc_port, + rpc_user.clone(), + rpc_password.clone(), + )), + _ => None, + }; + + let mut all_configs = configs; + if inject_hub { + let hub_cfg = hub.unwrap_or_default(); + let listening_addr = match hub_cfg.listening_addr { + Some(addr) => addr, + None => pick_free_loopback_addr().map_err(|e| { + LightningError::ValidationError(format!("could not pick hub port: {e}")) + })?, + }; + // Hub inherits chain source and network from the first leaf. + let first = &all_configs[0]; + all_configs.push(LdkNodeConfig { + id: NodeId::Alias(String::from("HubNode")), + chain_source: first.chain_source.clone(), + network: first.network, + listening_addr, + storage_dir: hub_cfg.storage_dir, + }); + } + + let mut nodes = Vec::new(); + for cfg in all_configs { + nodes.push(LdkNode::build(cfg).await?); + } + + if inject_hub { + // Pass bitcoind creds through when available so setup_ldk_channels uses + // the fast regtest mining path. Without creds it falls back to external funding. + setup_ldk_channels(bitcoind_creds, &mut nodes).await?; + } + + Ok(nodes) +} + +impl LdkNode { + pub async fn build(config: LdkNodeConfig) -> Result { + let mut builder = Builder::new(); + + match config.chain_source { + ChainSourceConfig::BitcoindRpcClientConfig { + rpc_host, + rpc_port, + rpc_user, + rpc_password, + } => { + builder.set_chain_source_bitcoind_rpc(rpc_host, rpc_port, rpc_user, rpc_password); + }, + ChainSourceConfig::BitcoindRestClientConfig { + rest_host, + rest_port, + rpc_host, + rpc_port, + rpc_user, + rpc_password, + } => { + builder.set_chain_source_bitcoind_rest( + rest_host, + rest_port, + rpc_host, + rpc_port, + rpc_user, + rpc_password, + ); + }, + ChainSourceConfig::Esplora { server_url } => { + builder.set_chain_source_esplora(server_url, None); + }, + ChainSourceConfig::Electrum { server_url } => { + builder.set_chain_source_electrum(server_url, None); + }, + } + + let storage_dir = config.storage_dir.unwrap_or_else(|| { + let ts = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_nanos()) + .unwrap_or(0); + std::env::temp_dir().join(format!("simln-ldk-{}", ts)) + }); + builder.set_storage_dir_path(storage_dir.to_string_lossy().to_string()); + builder.set_network(config.network); + + let alias = match config.id { + NodeId::Alias(ref a) => a.clone(), + NodeId::PublicKey(ref pk) => pk.to_string(), + }; + let listening_addr = config + .listening_addr + .parse::() + .map_err(|_| { + LightningError::ValidationError(format!( + "invalid listening_addr: {}", + config.listening_addr + )) + })?; + builder + .set_listening_addresses(vec![listening_addr]) + .map_err(conn_err)?; + builder.set_node_alias(alias.clone()).map_err(conn_err)?; + + let node = Arc::new(builder.build().map_err(conn_err)?); + node.start().map_err(conn_err)?; + + let pubkey = PublicKey::from_slice(&node.node_id().serialize()).map_err(conn_err)?; + let info = NodeInfo { + pubkey, + alias: alias.clone(), + features: ldk_node_features(), + }; + + let (shutdown_trigger, shutdown_listener) = triggered::trigger(); + let event_node = node.clone(); + tokio::spawn(async move { + loop { + tokio::select! { + biased; + _ = shutdown_listener.clone() => { + info!("[{}] Event loop shutting down.", alias); + break; + } + event = event_node.next_event_async() => { + handle_event(&alias, &event); + if let Err(e) = event_node.event_handled() { + warn!("[{}] Failed to mark event handled: {:?}", alias, e); + } + } + } + } + }); + + Ok(LdkNode { + node, + info, + network: config.network, + listening_addr: config.listening_addr.clone(), + _shutdown: shutdown_trigger, + }) + } +} + +fn handle_event(alias: &str, event: &Event) { + match event { + Event::PaymentSuccessful { + payment_id, + payment_hash, + fee_paid_msat, + .. + } => { + info!( + "[{}] Payment successful: hash={}, id={:?}, fee={:?}msat", + alias, payment_hash, payment_id, fee_paid_msat + ); + }, + Event::PaymentFailed { + payment_id, + payment_hash, + reason, + } => { + warn!( + "[{}] Payment failed: hash={:?}, id={:?}, reason={:?}", + alias, payment_hash, payment_id, reason + ); + }, + Event::PaymentReceived { + payment_hash, + amount_msat, + .. + } => { + info!( + "[{}] Payment received: hash={}, amount={}msat", + alias, payment_hash, amount_msat + ); + }, + Event::PaymentForwarded { + prev_channel_id, + next_channel_id, + total_fee_earned_msat, + .. + } => { + info!( + "[{}] Payment forwarded: {} -> {}, fee={:?}msat", + alias, prev_channel_id, next_channel_id, total_fee_earned_msat + ); + }, + Event::PaymentClaimable { + payment_hash, + claimable_amount_msat, + .. + } => { + info!( + "[{}] Payment claimable: hash={}, amount={}msat", + alias, payment_hash, claimable_amount_msat + ); + }, + Event::ChannelPending { + channel_id, + counterparty_node_id, + .. + } => { + info!( + "[{}] Channel pending: id={}, counterparty={}", + alias, channel_id, counterparty_node_id + ); + }, + Event::ChannelReady { + channel_id, + counterparty_node_id, + .. + } => { + info!( + "[{}] Channel ready: id={}, counterparty={:?}", + alias, channel_id, counterparty_node_id + ); + }, + Event::ChannelClosed { + channel_id, + counterparty_node_id, + reason, + .. + } => { + warn!( + "[{}] Channel closed: id={}, counterparty={:?}, reason={:?}", + alias, channel_id, counterparty_node_id, reason + ); + }, + _ => { + debug!("[{}] Unhandled event: {:?}", alias, event); + }, + } +} + +fn ldk_node_features() -> NodeFeatures { + let mut flags = vec![0u8; 7]; + flags[6] = 0x80; + NodeFeatures::from_le_bytes(flags) +} + +#[async_trait] +impl LightningNode for LdkNode { + fn get_info(&self) -> &NodeInfo { + &self.info + } + + fn get_network(&self) -> Network { + self.network + } + + async fn send_payment( + &self, + dest: PublicKey, + amount_msat: u64, + ) -> Result { + let payment_id = self + .node + .spontaneous_payment() + .send(amount_msat, dest, None) + .map_err(|e| LightningError::SendPaymentError(e.to_string()))?; + + Ok(PaymentHash(payment_id.0)) + } + + async fn track_payment( + &self, + hash: &PaymentHash, + shutdown: Listener, + ) -> Result { + let payment_id = PaymentId(hash.0); + + loop { + tokio::select! { + biased; + _ = shutdown.clone() => { + return Err(LightningError::TrackPaymentError( + "Shutdown before tracking results".to_string(), + )); + } + _ = tokio::time::sleep(tokio::time::Duration::from_millis(100)) => { + match self.node.payment(&payment_id) { + None => { + return Err(LightningError::TrackPaymentError( + format!("Payment not found: {:?}", hash), + )); + } + Some(details) => match details.status { + PaymentStatus::Pending => continue, + // ldk-node spontaneous payments don't support MPP (as of the time of + // writing), so there is always exactly one HTLC on success. + PaymentStatus::Succeeded => { + return Ok(PaymentResult { + htlc_count: 1, + payment_outcome: PaymentOutcome::Success, + }); + } + PaymentStatus::Failed => { + return Ok(PaymentResult { + htlc_count: 0, + payment_outcome: PaymentOutcome::UnexpectedError, + }); + } + }, + } + } + } + } + } + + async fn get_node_info(&self, node_id: &PublicKey) -> Result { + let network_graph = self.node.network_graph(); + let lightning_node_id = LightningNodeId::from_pubkey(node_id); + + let node = network_graph + .node(&lightning_node_id) + .ok_or_else(|| LightningError::GetNodeInfoError(node_id.to_string()))?; + + let (alias, features) = match &node.announcement_info { + Some(info) => (info.alias().to_string(), info.features().clone()), + None => (String::new(), NodeFeatures::empty()), + }; + + Ok(NodeInfo { + pubkey: *node_id, + alias, + features, + }) + } + + async fn channel_capacities(&self) -> Result { + Ok(self + .node + .list_channels() + .iter() + .filter(|c| c.is_channel_ready) + .map(|c| c.channel_value_sats * 1000) + .sum()) + } + + async fn get_graph(&self) -> Result { + let network_graph = self.node.network_graph(); + let mut nodes_by_pk = std::collections::HashMap::new(); + + for node_id in network_graph.list_nodes() { + let pubkey = PublicKey::from_slice(node_id.as_slice()) + .map_err(|e| LightningError::GetGraphError(e.to_string()))?; + + let node_by_id = match network_graph.node(&node_id) { + Some(n) => n, + None => continue, + }; + + // Nodes learned from channel announcements may not have a node announcement yet. + let (alias, features) = match &node_by_id.announcement_info { + Some(info) => (info.alias().to_string(), info.features().clone()), + None => continue, + }; + + nodes_by_pk.insert( + pubkey, + NodeInfo { + pubkey, + alias, + features, + }, + ); + } + + Ok(Graph { nodes_by_pk }) + } +} diff --git a/simln-lib/src/lib.rs b/simln-lib/src/lib.rs index a1b5fe0e..1bab296a 100755 --- a/simln-lib/src/lib.rs +++ b/simln-lib/src/lib.rs @@ -5,8 +5,8 @@ use self::clock::Clock; use async_trait::async_trait; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; -use lightning::ln::features::NodeFeatures; -use lightning::ln::PaymentHash; +use lightning::types::features::NodeFeatures; +use lightning::types::payment::PaymentHash; use rand::{Rng, RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use random_activity::RandomActivityError; @@ -36,6 +36,7 @@ pub mod clock; mod defined_activity; pub mod eclair; pub mod latency_interceptor; +pub mod ldk; pub mod lnd; mod random_activity; pub mod serializers; @@ -43,7 +44,7 @@ pub mod sim_node; mod test_utils; /// Represents a node id, either by its public key or alias. -#[derive(Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone)] pub enum NodeId { /// The node's public key. PublicKey(PublicKey), @@ -1950,7 +1951,7 @@ mod tests { let pl = payments_list.clone(); mock_node.expect_send_payment().returning(move |a, _| { pl.lock().unwrap().push(a); - Ok(lightning::ln::PaymentHash(payment_hash)) + Ok(lightning::types::payment::PaymentHash(payment_hash)) }); } diff --git a/simln-lib/src/lnd.rs b/simln-lib/src/lnd.rs index 4bbc9470..531abc5d 100644 --- a/simln-lib/src/lnd.rs +++ b/simln-lib/src/lnd.rs @@ -9,8 +9,8 @@ use async_trait::async_trait; use bitcoin::hashes::{sha256, Hash}; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; -use lightning::ln::features::NodeFeatures; -use lightning::ln::{PaymentHash, PaymentPreimage}; +use lightning::types::features::NodeFeatures; +use lightning::types::payment::{PaymentHash, PaymentPreimage}; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use tonic_lnd::lnrpc::{payment::PaymentStatus, GetInfoRequest}; diff --git a/simln-lib/src/serializers.rs b/simln-lib/src/serializers.rs index c15d5217..8e7ee48f 100644 --- a/simln-lib/src/serializers.rs +++ b/simln-lib/src/serializers.rs @@ -2,7 +2,7 @@ use expanduser::expanduser; use serde::Deserialize; pub mod serde_option_payment_hash { - use lightning::ln::PaymentHash; + use lightning::types::payment::PaymentHash; pub fn serialize(hash: &Option, serializer: S) -> Result where diff --git a/simln-lib/src/sim_node.rs b/simln-lib/src/sim_node.rs index 801315f1..23633298 100755 --- a/simln-lib/src/sim_node.rs +++ b/simln-lib/src/sim_node.rs @@ -15,17 +15,17 @@ use std::time::UNIX_EPOCH; use tokio::task::JoinSet; use tokio_util::task::TaskTracker; -use lightning::ln::features::{ChannelFeatures, NodeFeatures}; use lightning::ln::msgs::{ LightningError as LdkError, UnsignedChannelAnnouncement, UnsignedChannelUpdate, }; -use lightning::ln::{PaymentHash, PaymentPreimage}; use lightning::routing::gossip::{NetworkGraph, NodeId}; use lightning::routing::router::{find_route, Path, PaymentParameters, Route, RouteParameters}; use lightning::routing::scoring::{ ProbabilisticScorer, ProbabilisticScoringDecayParameters, ScoreUpdate, }; use lightning::routing::utxo::{UtxoLookup, UtxoResult}; +use lightning::types::features::{ChannelFeatures, NodeFeatures}; +use lightning::types::payment::{PaymentHash, PaymentPreimage}; use lightning::util::logger::{Level, Logger, Record}; use thiserror::Error; use tokio::select; @@ -645,7 +645,7 @@ async fn find_payment_route( &Default::default(), &[0; 32], ) - .map_err(|e| SimulationError::SimulatedNetworkError(e.err)) + .map_err(|e| SimulationError::SimulatedNetworkError(e.to_string())) } #[async_trait] @@ -1159,7 +1159,7 @@ pub fn populate_network_graph( &channel.node_1.policy.pubkey, &channel.node_2.policy.pubkey, ) - .to_v0_p2wsh(), + .to_p2wsh(), }; graph.update_channel_from_unsigned_announcement(&announcement, &Some(&utxo_validator))?; @@ -1172,9 +1172,11 @@ pub fn populate_network_graph( chain_hash, short_channel_id: channel.short_channel_id.into(), timestamp: now, + // message_flags bit 0 indicates htlc_maximum_msat is present (required since LDK 0.2). + message_flags: 1, // The least significant bit of the channel flag field represents the direction that the channel update // applies to. This value is interpreted as node_1 if it is zero, and node_2 otherwise. - flags: i as u8, + channel_flags: i as u8, cltv_expiry_delta: node.policy.cltv_expiry_delta as u16, htlc_minimum_msat: node.policy.min_htlc_size_msat, htlc_maximum_msat: node.policy.max_htlc_size_msat, @@ -1609,7 +1611,7 @@ struct UtxoValidator { impl UtxoLookup for UtxoValidator { fn get_utxo(&self, _genesis_hash: &ChainHash, _short_channel_id: u64) -> UtxoResult { UtxoResult::Sync(Ok(TxOut { - value: self.amount_sat, + value: bitcoin::Amount::from_sat(self.amount_sat), script_pubkey: self.script.clone(), })) } diff --git a/simln-lib/src/test_utils.rs b/simln-lib/src/test_utils.rs index e00af515..20e56896 100644 --- a/simln-lib/src/test_utils.rs +++ b/simln-lib/src/test_utils.rs @@ -2,7 +2,8 @@ use async_trait::async_trait; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use bitcoin::Network; -use lightning::ln::features::Features; +use lightning::types::features::Features; +use lightning::types::payment::PaymentHash; use mockall::mock; use rand::distributions::Uniform; use rand::Rng; @@ -82,10 +83,10 @@ mock! { &self, dest: bitcoin::secp256k1::PublicKey, amount_msat: u64, - ) -> Result; + ) -> Result; async fn track_payment( &self, - hash: &lightning::ln::PaymentHash, + hash: &PaymentHash, shutdown: triggered::Listener, ) -> Result; async fn get_node_info(&self, node_id: &PublicKey) -> Result;