From 95aab1506795af25f45ed152c74cd37b435a8844 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 21 Jan 2026 11:34:00 +0100 Subject: [PATCH 1/2] Add ConnectPeer API endpoint Adds a new endpoint to connect to a peer on the Lightning Network without opening a channel. This is useful for establishing connections before channel operations or for maintaining peer connectivity. The endpoint accepts node_pubkey, address, and an optional persist flag that defaults to true for automatic reconnection on restart. Co-Authored-By: Claude Opus 4.5 --- ldk-server-client/src/client.rs | 33 +++++++++++++++++++----------- ldk-server-protos/src/api.rs | 26 +++++++++++++++++++++++ ldk-server-protos/src/endpoints.rs | 1 + ldk-server/src/api/connect_peer.rs | 30 +++++++++++++++++++++++++++ ldk-server/src/api/mod.rs | 1 + ldk-server/src/service.rs | 12 +++++++---- 6 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 ldk-server/src/api/connect_peer.rs diff --git a/ldk-server-client/src/client.rs b/ldk-server-client/src/client.rs index ab3d2c2..0d137db 100644 --- a/ldk-server-client/src/client.rs +++ b/ldk-server-client/src/client.rs @@ -14,21 +14,21 @@ use bitcoin_hashes::{sha256, Hash, HashEngine}; use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, - CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, - GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, - GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, - ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, ListPaymentsRequest, - ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, - OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, SpliceInRequest, - SpliceInResponse, SpliceOutRequest, SpliceOutResponse, UpdateChannelConfigRequest, - UpdateChannelConfigResponse, + CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, + ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, + GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse, + ListChannelsRequest, ListChannelsResponse, ListForwardedPaymentsRequest, + ListForwardedPaymentsResponse, ListPaymentsRequest, ListPaymentsResponse, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, + SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; use ldk_server_protos::endpoints::{ BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, - GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, - ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, - UPDATE_CHANNEL_CONFIG_PATH, + CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, + GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, + LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, + SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use prost::Message; @@ -252,6 +252,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Connect to a peer on the Lightning Network. + /// For API contract/usage, refer to docs for [`ConnectPeerRequest`] and [`ConnectPeerResponse`]. + pub async fn connect_peer( + &self, request: ConnectPeerRequest, + ) -> Result { + let url = format!("https://{}/{CONNECT_PEER_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { diff --git a/ldk-server-protos/src/api.rs b/ldk-server-protos/src/api.rs index 439a403..35a5bc2 100644 --- a/ldk-server-protos/src/api.rs +++ b/ldk-server-protos/src/api.rs @@ -600,3 +600,29 @@ pub struct GetBalancesResponse { pub pending_balances_from_channel_closures: ::prost::alloc::vec::Vec, } +/// Connect to a peer on the Lightning Network. +/// See more: +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConnectPeerRequest { + /// The hex-encoded public key of the node to connect to. + #[prost(string, tag = "1")] + pub node_pubkey: ::prost::alloc::string::String, + /// An address which can be used to connect to a remote peer. + /// It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port + #[prost(string, tag = "2")] + pub address: ::prost::alloc::string::String, + /// Whether to persist the peer connection, i.e., whether the peer will be re-connected on + /// restart. Defaults to true. + #[prost(bool, optional, tag = "3")] + pub persist: ::core::option::Option, +} +/// The response `content` for the `ConnectPeer` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConnectPeerResponse {} diff --git a/ldk-server-protos/src/endpoints.rs b/ldk-server-protos/src/endpoints.rs index c7ed1c2..606da0d 100644 --- a/ldk-server-protos/src/endpoints.rs +++ b/ldk-server-protos/src/endpoints.rs @@ -25,3 +25,4 @@ pub const LIST_PAYMENTS_PATH: &str = "ListPayments"; pub const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; pub const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; pub const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; +pub const CONNECT_PEER_PATH: &str = "ConnectPeer"; diff --git a/ldk-server/src/api/connect_peer.rs b/ldk-server/src/api/connect_peer.rs new file mode 100644 index 0000000..3ca85ce --- /dev/null +++ b/ldk-server/src/api/connect_peer.rs @@ -0,0 +1,30 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +use crate::api::error::LdkServerError; +use crate::service::Context; +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::lightning::ln::msgs::SocketAddress; +use ldk_server_protos::api::{ConnectPeerRequest, ConnectPeerResponse}; +use std::str::FromStr; + +pub(crate) fn handle_connect_peer( + context: Context, request: ConnectPeerRequest, +) -> Result { + let node_id = PublicKey::from_str(&request.node_pubkey) + .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + let address = SocketAddress::from_str(&request.address) + .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; + + let persist = request.persist.unwrap_or(true); + + context.node.connect(node_id, address, persist)?; + + Ok(ConnectPeerResponse {}) +} diff --git a/ldk-server/src/api/mod.rs b/ldk-server/src/api/mod.rs index 0063d9d..1152f8b 100644 --- a/ldk-server/src/api/mod.rs +++ b/ldk-server/src/api/mod.rs @@ -18,6 +18,7 @@ pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; +pub(crate) mod connect_peer; pub(crate) mod error; pub(crate) mod get_balances; pub(crate) mod get_node_info; diff --git a/ldk-server/src/service.rs b/ldk-server/src/service.rs index 056b256..0f05094 100644 --- a/ldk-server/src/service.rs +++ b/ldk-server/src/service.rs @@ -20,10 +20,10 @@ use ldk_node::bitcoin::hashes::{sha256, Hash, HashEngine}; use ldk_node::Node; use ldk_server_protos::endpoints::{ BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, - GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, - ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, - UPDATE_CHANNEL_CONFIG_PATH, + CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, + GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, + LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, + SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, }; use prost::Message; @@ -32,6 +32,7 @@ use crate::api::bolt11_send::handle_bolt11_send_request; use crate::api::bolt12_receive::handle_bolt12_receive_request; use crate::api::bolt12_send::handle_bolt12_send_request; use crate::api::close_channel::{handle_close_channel_request, handle_force_close_channel_request}; +use crate::api::connect_peer::handle_connect_peer; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{AuthError, InvalidRequestError}; use crate::api::get_balances::handle_get_balances_request; @@ -292,6 +293,9 @@ impl Service> for NodeService { api_key, handle_list_forwarded_payments_request, )), + CONNECT_PEER_PATH => { + Box::pin(handle_request(context, req, auth_params, api_key, handle_connect_peer)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 20d2e6e5fdb016716ddffbf4b76513998052f166 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 21 Jan 2026 11:36:03 +0100 Subject: [PATCH 2/2] Add chaos testing framework for ldk-server Introduce ldk-server-chaos, a testing harness that stress-tests ldk-server by running multiple nodes, opening channels, and continuously sending payments while randomly killing and restarting nodes. Features: - Spawns 3 ldk-server nodes with auto-generated configs - Creates a fully connected channel topology - Runs concurrent payment loops between all node pairs - Randomly kills and restarts nodes to test resilience - Tracks payment success rates and detects timeout failures - Uses bitcoind RPC for on-chain operations and block generation Co-Authored-By: Claude Opus 4.5 --- .gitignore | 1 + Cargo.lock | 608 +++++++++++++++------------ Cargo.toml | 17 +- ldk-server-chaos/Cargo.toml | 30 ++ ldk-server-chaos/src/bitcoind.rs | 115 ++++++ ldk-server-chaos/src/config.rs | 68 +++ ldk-server-chaos/src/main.rs | 685 +++++++++++++++++++++++++++++++ ldk-server/src/main.rs | 6 + 8 files changed, 1264 insertions(+), 266 deletions(-) create mode 100644 ldk-server-chaos/Cargo.toml create mode 100644 ldk-server-chaos/src/bitcoind.rs create mode 100644 ldk-server-chaos/src/config.rs create mode 100644 ldk-server-chaos/src/main.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..60d887a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/ldk-server-chaos/data diff --git a/Cargo.lock b/Cargo.lock index 538c977..e8a5a03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,7 +133,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", "synstructure", ] @@ -145,7 +145,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -183,7 +183,7 @@ dependencies = [ "async-channel", "async-executor", "async-io 2.6.0", - "async-lock 3.4.1", + "async-lock 3.4.2", "blocking", "futures-lite 2.6.1", ] @@ -232,7 +232,7 @@ dependencies = [ "futures-lite 2.6.1", "parking", "polling 3.11.0", - "rustix 1.1.2", + "rustix 1.1.3", "slab", "windows-sys 0.61.2", ] @@ -248,9 +248,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener 5.4.1", "event-listener-strategy", @@ -283,7 +283,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -304,10 +304,16 @@ 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", + "bitcoin-internals", + "bitcoin_hashes", ] +[[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" @@ -322,9 +328,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bdk_chain" @@ -373,9 +379,9 @@ dependencies = [ [[package]] name = "bdk_wallet" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b172f2caa6311b8172cf99559cd7f7a61cb58834e35e4ca208b3299e7be8bec" +checksum = "b03f1e31ccc562f600981f747d2262b84428cbff52c9c9cdf14d15fb15bd2286" dependencies = [ "bdk_chain", "bip39", @@ -388,9 +394,9 @@ dependencies = [ [[package]] name = "bech32" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bip21" @@ -404,11 +410,11 @@ dependencies = [ [[package]] name = "bip39" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" +checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand 0.8.5", "rand_core 0.6.4", "serde", @@ -417,29 +423,23 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.32.7" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ "base58ck", "base64 0.21.7", "bech32", - "bitcoin-internals 0.3.0", + "bitcoin-internals", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", + "bitcoin_hashes", + "hex-conservative", "hex_lit", "secp256k1", "serde", ] -[[package]] -name = "bitcoin-internals" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" - [[package]] name = "bitcoin-internals" version = "0.3.0" @@ -451,14 +451,14 @@ dependencies = [ [[package]] name = "bitcoin-io" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] name = "bitcoin-payment-instructions" version = "0.6.0" -source = "git+https://github.com/tnull/bitcoin-payment-instructions?rev=fdca6c62f2fe2c53427d3e51e322a49aa7323ee2#fdca6c62f2fe2c53427d3e51e322a49aa7323ee2" +source = "git+https://github.com/tnull/bitcoin-payment-instructions?rev=ce9ff5281ae9bb05526981f6f9df8f8d929c7c44#ce9ff5281ae9bb05526981f6f9df8f8d929c7c44" dependencies = [ "bitcoin", "dnssec-prover", @@ -473,28 +473,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" dependencies = [ - "bitcoin-internals 0.3.0", + "bitcoin-internals", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.13.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" -dependencies = [ - "bitcoin-internals 0.2.0", - "hex-conservative 0.1.2", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ "bitcoin-io", - "hex-conservative 0.2.1", + "hex-conservative", "serde", ] @@ -543,9 +533,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "byteorder" @@ -555,9 +545,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] @@ -573,9 +563,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.43" +version = "1.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" dependencies = [ "find-msvc-tools", "shlex", @@ -601,13 +591,15 @@ checksum = "4b4b0fc281743d80256607bd65e8beedc42cb0787ea119c85b81b4c0eab85e5f" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-link", ] @@ -629,9 +621,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.51" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -639,9 +631,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.51" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstyle", "clap_lex", @@ -666,14 +658,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cms" @@ -724,6 +716,32 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "corepc-client" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb85495f0577f4765ea2ece0a69003d38acdddba2ac06bdde180ac2b969a9a63" +dependencies = [ + "bitcoin", + "corepc-types", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "corepc-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282d9bd7fd9d944471a0c0ad44fd1581acd87a79739652c5455ffdae25177db6" +dependencies = [ + "bitcoin", + "bitcoin-internals", + "serde", + "serde_json", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -741,9 +759,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -751,9 +769,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "der" @@ -790,7 +808,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -830,7 +848,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -839,7 +857,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "tokio", ] @@ -857,15 +875,15 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "electrum-client" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7b07e2578a6df0093b101915c79dca0119d7f7810099ad9eef11341d2ae57" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" dependencies = [ "bitcoin", "byteorder", "libc", "log", - "rustls 0.23.34", + "rustls 0.23.36", "serde", "serde_json", "webpki-roots 0.25.4", @@ -904,9 +922,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0af349d96a5d9ad77ba59f1437aa6f348b03c5865d4f7d6e7a662d60aedce39" dependencies = [ "bitcoin", - "hex-conservative 0.2.1", + "hex-conservative", "log", - "reqwest 0.12.24", + "reqwest 0.12.28", "serde", "tokio", ] @@ -976,9 +994,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" [[package]] name = "fixedbitset" @@ -1102,7 +1120,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -1137,9 +1155,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1147,9 +1165,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1209,9 +1227,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hashlink" @@ -1254,15 +1272,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" - -[[package]] -name = "hex-conservative" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" dependencies = [ "arrayvec", ] @@ -1304,12 +1316,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1331,7 +1342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -1342,7 +1353,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -1385,15 +1396,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -1425,31 +1436,31 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", - "hyper 1.7.0", + "http 1.4.0", + "hyper 1.8.1", "hyper-util", - "rustls 0.23.34", + "rustls 0.23.36", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 1.0.3", + "webpki-roots 1.0.5", ] [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "hyper 1.7.0", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", @@ -1532,9 +1543,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -1546,9 +1557,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -1588,12 +1599,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -1634,9 +1645,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -1653,20 +1664,32 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" 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 = "lapin" version = "2.5.5" @@ -1698,7 +1721,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" version = "0.8.0+git" -source = "git+https://github.com/lightningdevkit/ldk-node?rev=d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49#d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" +source = "git+https://github.com/joostjager/ldk-node?branch=mon-barrier#76005237da81f6446e170b615d98d05bd48eeb51" dependencies = [ "base64 0.22.1", "bdk_chain", @@ -1718,7 +1741,7 @@ dependencies = [ "lightning-block-sync", "lightning-invoice", "lightning-liquidity", - "lightning-macros", + "lightning-macros 0.2.0+git (git+https://github.com/lightningdevkit/rust-lightning?rev=c9f022bcccb33964604159e6bdb4722020b4d256)", "lightning-net-tokio", "lightning-persister", "lightning-rapid-gossip-sync", @@ -1727,9 +1750,9 @@ dependencies = [ "log", "prost", "rand 0.9.2", - "reqwest 0.12.24", + "reqwest 0.12.28", "rusqlite", - "rustls 0.23.34", + "rustls 0.23.36", "serde", "serde_json", "tokio", @@ -1746,9 +1769,9 @@ dependencies = [ "bytes", "chrono", "futures-util", - "hex-conservative 0.2.1", + "hex-conservative", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "lapin", "ldk-node", @@ -1764,13 +1787,31 @@ dependencies = [ "toml", ] +[[package]] +name = "ldk-server-chaos" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "corepc-client", + "futures", + "hex", + "ldk-server-client", + "ldk-server-protos", + "rand 0.9.2", + "serde", + "tempfile", + "tokio", + "toml", +] + [[package]] name = "ldk-server-cli" version = "0.1.0" dependencies = [ "clap", "clap_complete", - "hex-conservative 0.2.1", + "hex-conservative", "ldk-server-client", "serde", "serde_json", @@ -1782,7 +1823,7 @@ dependencies = [ name = "ldk-server-client" version = "0.1.0" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "ldk-server-protos", "prost", "reqwest 0.11.27", @@ -1800,9 +1841,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" @@ -1824,7 +1865,7 @@ dependencies = [ [[package]] name = "lightning" version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bech32", "bitcoin", @@ -1832,7 +1873,7 @@ dependencies = [ "hashbrown 0.13.2", "libm", "lightning-invoice", - "lightning-macros", + "lightning-macros 0.2.0+git (git+https://github.com/joostjager/rust-lightning?branch=mon-barrier)", "lightning-types", "musig2", "possiblyrandom", @@ -1841,11 +1882,11 @@ dependencies = [ [[package]] name = "lightning-background-processor" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "bitcoin-io", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "lightning", "lightning-liquidity", "lightning-rapid-gossip-sync", @@ -1855,7 +1896,7 @@ dependencies = [ [[package]] name = "lightning-block-sync" version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "chunked_transfer", @@ -1867,7 +1908,7 @@ dependencies = [ [[package]] name = "lightning-invoice" version = "0.34.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bech32", "bitcoin", @@ -1878,13 +1919,13 @@ dependencies = [ [[package]] name = "lightning-liquidity" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "chrono", "lightning", "lightning-invoice", - "lightning-macros", + "lightning-macros 0.2.0+git (git+https://github.com/joostjager/rust-lightning?branch=mon-barrier)", "lightning-types", "serde", "serde_json", @@ -1893,17 +1934,27 @@ dependencies = [ [[package]] name = "lightning-macros" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "lightning-macros" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=c9f022bcccb33964604159e6bdb4722020b4d256#c9f022bcccb33964604159e6bdb4722020b4d256" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] name = "lightning-net-tokio" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "lightning", @@ -1913,7 +1964,7 @@ dependencies = [ [[package]] name = "lightning-persister" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "lightning", @@ -1924,31 +1975,31 @@ dependencies = [ [[package]] name = "lightning-rapid-gossip-sync" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "bitcoin-io", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "lightning", ] [[package]] name = "lightning-transaction-sync" version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", "electrum-client", "esplora-client", "futures", "lightning", - "lightning-macros", + "lightning-macros 0.2.0+git (git+https://github.com/joostjager/rust-lightning?branch=mon-barrier)", ] [[package]] name = "lightning-types" version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ "bitcoin", ] @@ -1988,9 +2039,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru-slab" @@ -2027,11 +2078,21 @@ dependencies = [ "serde", ] +[[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.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -2306,16 +2367,16 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.5.2", "pin-project-lite", - "rustix 1.1.2", + "rustix 1.1.3", "windows-sys 0.61.2", ] [[package]] name = "possiblyrandom" version = "0.2.0" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" +source = "git+https://github.com/joostjager/rust-lightning?branch=mon-barrier#6ed79d99f8d99882651a064930b778661d9226a4" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] @@ -2354,9 +2415,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] @@ -2427,7 +2488,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.34", + "rustls 0.23.36", "socket2 0.6.1", "thiserror", "tokio", @@ -2447,7 +2508,7 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.34", + "rustls 0.23.36", "rustls-pki-types", "slab", "thiserror", @@ -2472,9 +2533,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -2503,7 +2564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2523,7 +2584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2532,14 +2593,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -2657,19 +2718,19 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.27.7", "hyper-util", "js-sys", @@ -2677,7 +2738,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.34", + "rustls 0.23.36", "rustls-pki-types", "serde", "serde_json", @@ -2692,7 +2753,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.3", + "webpki-roots 1.0.5", ] [[package]] @@ -2703,7 +2764,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -2767,9 +2828,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags 2.10.0", "errno", @@ -2792,15 +2853,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.34" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] @@ -2812,10 +2873,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70cc376c6ba1823ae229bacf8ad93c136d93524eab0e4e5e0e4f96b9c4e5b212" dependencies = [ "log", - "rustls 0.23.34", + "rustls 0.23.36", "rustls-native-certs", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", ] [[package]] @@ -2851,9 +2912,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -2871,9 +2932,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -2888,9 +2949,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "salsa20" @@ -2943,7 +3004,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys", "serde", @@ -3008,20 +3069,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -3075,10 +3136,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3174,9 +3236,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.108" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -3206,7 +3268,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -3244,63 +3306,63 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand 2.3.0", "getrandom 0.3.4", "once_cell", - "rustix 1.1.2", + "rustix 1.1.3", "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] name = "time" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -3333,13 +3395,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.6.1", @@ -3355,7 +3418,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -3374,15 +3437,15 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.34", + "rustls 0.23.36", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -3422,14 +3485,21 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -3442,14 +3512,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.10.0", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "iri-string", "pin-project-lite", @@ -3472,9 +3542,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-core", @@ -3482,9 +3552,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -3503,15 +3573,15 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] @@ -3524,9 +3594,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -3554,19 +3624,20 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vss-client-ng" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c6bf7f2c3e22e62c638ad7d8c48dd5dc7e79033c5e088bdd797bbc815b29bb" +checksum = "c05f61751537ec3e7cf744e6ed8a56830b8d048f9862871cb4b9c239e3d23b45" dependencies = [ "async-trait", "base64 0.22.1", "bitcoin", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "chacha20-poly1305", + "log", "prost", "prost-build", "rand 0.8.5", - "reqwest 0.12.24", + "reqwest 0.12.28", "serde", "serde_json", "tokio", @@ -3596,18 +3667,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -3618,11 +3689,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.55" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -3631,9 +3703,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3641,31 +3713,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -3689,9 +3761,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] @@ -3751,7 +3823,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -3762,7 +3834,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -4022,9 +4094,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -4041,9 +4113,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "writeable" @@ -4107,28 +4179,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] [[package]] @@ -4148,7 +4220,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", "synstructure", ] @@ -4188,5 +4260,11 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.114", ] + +[[package]] +name = "zmij" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" diff --git a/Cargo.toml b/Cargo.toml index 16d6ced..d7f0908 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "ldk-server-cli", "ldk-server-client", "ldk-server-protos", "ldk-server"] +members = [ "ldk-server-chaos", "ldk-server-cli", "ldk-server-client", "ldk-server-protos", "ldk-server"] [profile.release] panic = "abort" @@ -9,3 +9,18 @@ lto = true [profile.dev] panic = "abort" + +[patch."https://github.com/lightningdevkit/ldk-node"] +ldk-node = { git = "https://github.com/joostjager/ldk-node", branch = "mon-barrier" } + +[patch."https://github.com/lightningdevkit/rust-lightning"] +lightning = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-invoice = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-net-tokio = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-persister = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-background-processor = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-rapid-gossip-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-transaction-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-liquidity = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-types = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } +lightning-block-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "mon-barrier" } diff --git a/ldk-server-chaos/Cargo.toml b/ldk-server-chaos/Cargo.toml new file mode 100644 index 0000000..30cf949 --- /dev/null +++ b/ldk-server-chaos/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "ldk-server-chaos" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "ldk-server-chaos" +path = "src/main.rs" + +[dependencies] +ldk-server-client = { path = "../ldk-server-client" } +ldk-server-protos = { path = "../ldk-server-protos" } + +# Async runtime +tokio = { version = "1", features = ["full"] } + +# Bitcoin RPC +corepc-client = { version = "0.5", features = ["client-sync"] } + +# Serialization +serde = { version = "1", features = ["derive"] } +toml = "0.8" + +# Utilities +rand = "0.9" +tempfile = "3" +anyhow = "1" +futures = "0.3" +chrono = "0.4" +hex = "0.4.3" diff --git a/ldk-server-chaos/src/bitcoind.rs b/ldk-server-chaos/src/bitcoind.rs new file mode 100644 index 0000000..7e1f2c7 --- /dev/null +++ b/ldk-server-chaos/src/bitcoind.rs @@ -0,0 +1,115 @@ +use std::env; +use std::fs; +use std::path::PathBuf; +use std::str::FromStr; + +use corepc_client::bitcoin::Address; +use corepc_client::client_sync::v28::Client; +use corepc_client::client_sync::Auth; + +pub struct BitcoindClient { + client: Client, + pub rpc_url: String, + pub rpc_user: String, + pub rpc_password: String, +} + +pub struct BlockchainInfo { + pub blocks: u64, +} + +impl BitcoindClient { + pub fn new(rpc_url: &str, rpc_user: &str, rpc_password: &str) -> anyhow::Result { + let auth = Auth::UserPass(rpc_user.to_string(), rpc_password.to_string()); + let client = Client::new_with_auth(rpc_url, auth.clone()) + .map_err(|e| anyhow::anyhow!("Failed to create bitcoind client: {}", e))?; + + Ok(Self { + client, + rpc_url: rpc_url.to_string(), + rpc_user: rpc_user.to_string(), + rpc_password: rpc_password.to_string(), + }) + } + + pub fn new_with_cookie(rpc_url: &str, cookie_path: &str) -> anyhow::Result { + let cookie = fs::read_to_string(cookie_path)?; + let parts: Vec<&str> = cookie.trim().split(':').collect(); + if parts.len() != 2 { + anyhow::bail!("Invalid cookie format"); + } + + Self::new(rpc_url, parts[0], parts[1]) + } + + pub fn new_default() -> anyhow::Result { + let rpc_url = + env::var("BITCOIND_RPC_URL").unwrap_or_else(|_| "http://127.0.0.1:18443".to_string()); + + // Try cookie auth first - check multiple locations + let cookie_path = env::var("BITCOIND_COOKIE").ok().or_else(|| { + let home = env::var("HOME").ok()?; + + // macOS default: ~/Library/Application Support/Bitcoin/regtest/.cookie + let macos_path = + PathBuf::from(&home).join("Library/Application Support/Bitcoin/regtest/.cookie"); + if macos_path.exists() { + return Some(macos_path.to_string_lossy().to_string()); + } + + // Linux default: ~/.bitcoin/regtest/.cookie + let linux_path = PathBuf::from(&home).join(".bitcoin/regtest/.cookie"); + if linux_path.exists() { + return Some(linux_path.to_string_lossy().to_string()); + } + + None + }); + + if let Some(cookie_path) = cookie_path { + return Self::new_with_cookie(&rpc_url, &cookie_path); + } + + // Fall back to user/pass from env + let rpc_user = env::var("BITCOIND_RPC_USER").unwrap_or_else(|_| "user".to_string()); + let rpc_password = + env::var("BITCOIND_RPC_PASSWORD").unwrap_or_else(|_| "password".to_string()); + + Self::new(&rpc_url, &rpc_user, &rpc_password) + } + + pub fn get_blockchain_info(&self) -> anyhow::Result { + let info = self + .client + .get_blockchain_info() + .map_err(|e| anyhow::anyhow!("get_blockchain_info failed: {}", e))?; + Ok(BlockchainInfo { blocks: info.blocks as u64 }) + } + + /// Mine blocks to a specific address (use for funding nodes on regtest) + pub fn mine_to_address(&self, num_blocks: u32, address: &str) -> anyhow::Result<()> { + let addr = Address::from_str(address) + .map_err(|e| anyhow::anyhow!("Invalid address: {}", e))? + .assume_checked(); + + self.client + .generate_to_address(num_blocks as usize, &addr) + .map_err(|e| anyhow::anyhow!("generate_to_address failed: {}", e))?; + + Ok(()) + } + + /// Mine blocks to a dummy address (just for block production) + pub fn mine_blocks(&self, num_blocks: u32) -> anyhow::Result<()> { + // Use a burn address for regtest + let addr = Address::from_str("bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqdku202") + .unwrap() + .assume_checked(); + + self.client + .generate_to_address(num_blocks as usize, &addr) + .map_err(|e| anyhow::anyhow!("generate_to_address failed: {}", e))?; + + Ok(()) + } +} diff --git a/ldk-server-chaos/src/config.rs b/ldk-server-chaos/src/config.rs new file mode 100644 index 0000000..f8328c4 --- /dev/null +++ b/ldk-server-chaos/src/config.rs @@ -0,0 +1,68 @@ +#[derive(Clone)] +pub struct NodeConfig { + #[allow(dead_code)] + pub node_index: usize, + pub listening_address: String, + pub rest_address: String, + pub alias: String, + pub storage_dir: String, + pub bitcoind_rpc_address: String, + pub bitcoind_rpc_user: String, + pub bitcoind_rpc_password: String, +} + +impl NodeConfig { + pub fn new( + node_index: usize, storage_dir: String, bitcoind_rpc_url: String, + bitcoind_rpc_user: String, bitcoind_rpc_password: String, + ) -> Self { + // Parse bitcoind URL to get host:port + let bitcoind_rpc_address = bitcoind_rpc_url + .strip_prefix("http://") + .or_else(|| bitcoind_rpc_url.strip_prefix("https://")) + .unwrap_or(&bitcoind_rpc_url) + .to_string(); + + Self { + node_index, + listening_address: format!("localhost:{}", 9700 + node_index), + rest_address: format!("127.0.0.1:{}", 3100 + node_index), + alias: format!("ChaosNode{}", node_index), + storage_dir, + bitcoind_rpc_address, + bitcoind_rpc_user, + bitcoind_rpc_password, + } + } + + pub fn to_toml(&self) -> String { + format!( + r#"[node] +network = "regtest" +listening_addresses = ["{listening_address}"] +rest_service_address = "{rest_address}" +alias = "{alias}" + +[storage.disk] +dir_path = "{storage_dir}" + +[bitcoind] +rpc_address = "{bitcoind_rpc_address}" +rpc_user = "{bitcoind_rpc_user}" +rpc_password = "{bitcoind_rpc_password}" + +[log] +level = "Trace" +file = "{log_file}" +"#, + listening_address = self.listening_address, + rest_address = self.rest_address, + alias = self.alias, + storage_dir = self.storage_dir, + log_file = format!("{}/ldk-server.log", self.storage_dir), + bitcoind_rpc_address = self.bitcoind_rpc_address, + bitcoind_rpc_user = self.bitcoind_rpc_user, + bitcoind_rpc_password = self.bitcoind_rpc_password, + ) + } +} diff --git a/ldk-server-chaos/src/main.rs b/ldk-server-chaos/src/main.rs new file mode 100644 index 0000000..e0df430 --- /dev/null +++ b/ldk-server-chaos/src/main.rs @@ -0,0 +1,685 @@ +use std::path::PathBuf; +use std::process::{Child, Command, Stdio}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +macro_rules! tprintln { + ($($arg:tt)*) => { + println!("[{}] {}", chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), format!($($arg)*)) + }; +} + +use ldk_server_client::client::LdkServerClient; +use ldk_server_protos::api::{ + Bolt11ReceiveRequest, Bolt11SendRequest, ConnectPeerRequest, GetBalancesRequest, + GetNodeInfoRequest, ListChannelsRequest, OnchainReceiveRequest, OpenChannelRequest, +}; +use ldk_server_protos::types::bolt11_invoice_description::Kind as DescriptionKind; +use ldk_server_protos::types::Bolt11InvoiceDescription; +use rand::{Rng, SeedableRng}; +use tokio::sync::{watch, Mutex}; +use tokio::time::sleep; + +mod bitcoind; +mod config; + +use bitcoind::BitcoindClient; +use config::NodeConfig; + +const NUM_NODES: usize = 3; +const CHANNEL_AMOUNT_SATS: u64 = 500_000; +const PAYMENT_AMOUNT_MSAT: u64 = 10_000; +const PAYMENT_TIMEOUT_SECS: u64 = 60; + +/// Tracks payment statistics and timeout detection. +/// Uses a flat array indexed by sender * NUM_NODES + receiver for per-direction tracking. +struct PaymentTracker { + last_success: [AtomicU64; NUM_NODES * NUM_NODES], + total_success: AtomicU64, + total_attempts: AtomicU64, + start_time: Instant, +} + +impl PaymentTracker { + fn new() -> Self { + Self { + last_success: std::array::from_fn(|_| AtomicU64::new(0)), + total_success: AtomicU64::new(0), + total_attempts: AtomicU64::new(0), + start_time: Instant::now(), + } + } + + fn elapsed_millis(&self) -> u64 { + self.start_time.elapsed().as_millis() as u64 + } + + fn record_attempt(&self) -> u64 { + self.total_attempts.fetch_add(1, Ordering::Relaxed) + 1 + } + + fn record_success(&self, sender: usize, receiver: usize) -> u64 { + let idx = sender * NUM_NODES + receiver; + self.last_success[idx].store(self.elapsed_millis(), Ordering::Relaxed); + self.total_success.fetch_add(1, Ordering::Relaxed) + 1 + } + + fn get_counts(&self) -> (u64, u64) { + (self.total_success.load(Ordering::Relaxed), self.total_attempts.load(Ordering::Relaxed)) + } + + /// Returns Some(direction_str) if a direction has timed out, None otherwise. + fn check_timeout(&self) -> Option { + let now = self.elapsed_millis(); + let timeout_millis = PAYMENT_TIMEOUT_SECS * 1000; + + for sender in 0..NUM_NODES { + for receiver in 0..NUM_NODES { + if sender == receiver { + continue; + } + let idx = sender * NUM_NODES + receiver; + let last = self.last_success[idx].load(Ordering::Relaxed); + // Only check timeout if we've had at least one success in that direction + if last > 0 && now - last > timeout_millis { + return Some(format!("{}->{}", sender, receiver)); + } + } + } + None + } +} + +struct NodeHandle { + config: NodeConfig, + process: Option, + client: Option, + data_dir: PathBuf, +} + +impl NodeHandle { + fn new(config: NodeConfig, data_dir: PathBuf) -> Self { + Self { config, process: None, client: None, data_dir } + } + + async fn start(&mut self) -> anyhow::Result<()> { + // Write config file + let config_path = self.data_dir.join("config.toml"); + std::fs::write(&config_path, self.config.to_toml())?; + + // Start ldk-server process (logs go to configured log file, suppress stdout/stderr) + let process = Command::new("cargo") + .args(["run", "--bin", "ldk-server", "--"]) + .arg(&config_path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()?; + + self.process = Some(process); + + // Wait for server to start and TLS cert to be generated + let cert_path = self.data_dir.join("tls.crt"); + let log_path = self.data_dir.join("ldk-server.log"); + for i in 0..60 { + if cert_path.exists() { + break; + } + // Check if process died + if let Some(ref mut proc) = self.process { + if let Ok(Some(status)) = proc.try_wait() { + // Process exited, read log file for errors + let log_output = std::fs::read_to_string(&log_path).unwrap_or_default(); + anyhow::bail!( + "ldk-server exited with status {} after {}s. Log:\n{}", + status, + i / 2, + log_output + ); + } + } + sleep(Duration::from_millis(500)).await; + } + + if !cert_path.exists() { + // Read log file for errors + let log_output = std::fs::read_to_string(&log_path).unwrap_or_default(); + if let Some(ref mut proc) = self.process { + let _ = proc.kill(); + } + anyhow::bail!( + "TLS certificate not generated after 30s - ldk-server may have failed to start. Log:\n{}", + log_output + ); + } + + // Small additional delay for server to be ready + sleep(Duration::from_secs(2)).await; + + // Create client - read API key from file (server generates it in regtest/api_key) + let cert_pem = std::fs::read(&cert_path)?; + let api_key_path = self.data_dir.join("regtest").join("api_key"); + let api_key_bytes = std::fs::read(&api_key_path)?; + let api_key = hex::encode(&api_key_bytes); + let client = LdkServerClient::new(self.config.rest_address.clone(), api_key, &cert_pem) + .map_err(|e| anyhow::anyhow!(e))?; + + self.client = Some(client); + Ok(()) + } + + fn kill(&mut self) { + if let Some(mut process) = self.process.take() { + // Hard kill - SIGKILL, no graceful shutdown + let _ = process.kill(); + let _ = process.wait(); + } + self.client = None; + } + + fn client(&self) -> Option<&LdkServerClient> { + self.client.as_ref() + } +} + +impl Drop for NodeHandle { + fn drop(&mut self) { + self.kill(); + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tprintln!("=== LDK Server Chaos Test ===\n"); + + // Use a fixed data directory under ldk-server-chaos for persistence and easy access + let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("data"); + // Clean up any previous run + if data_dir.exists() { + std::fs::remove_dir_all(&data_dir)?; + } + std::fs::create_dir_all(&data_dir)?; + + tprintln!("Data directory: {}", data_dir.display()); + tprintln!("Node logs will be at:"); + for i in 0..NUM_NODES { + tprintln!(" Node {}: {}", i, data_dir.join(format!("node{}/ldk-server.log", i)).display()); + } + + // Connect to bitcoind + let bitcoind = BitcoindClient::new_default()?; + tprintln!("Connected to bitcoind"); + + // Ensure we have enough blocks + let info = bitcoind.get_blockchain_info()?; + if info.blocks < 101 { + tprintln!("Mining initial blocks..."); + bitcoind.mine_blocks(101 - info.blocks as u32)?; + } + + // Create and start nodes + let mut nodes: Vec>> = Vec::new(); + + for i in 0..NUM_NODES { + let node_dir = data_dir.join(format!("node{}", i)); + std::fs::create_dir_all(&node_dir)?; + + let config = NodeConfig::new( + i, + node_dir.to_str().unwrap().to_string(), + bitcoind.rpc_url.clone(), + bitcoind.rpc_user.clone(), + bitcoind.rpc_password.clone(), + ); + + let mut handle = NodeHandle::new(config, node_dir); + tprintln!("Starting node {}...", i); + handle.start().await?; + tprintln!("Node {} started (REST: {})", i, handle.config.rest_address); + + nodes.push(Arc::new(Mutex::new(handle))); + } + + // Get node info and fund nodes by mining to their addresses + let mut node_ids = Vec::new(); + let mut node_addresses = Vec::new(); + + for (i, node) in nodes.iter().enumerate() { + let node = node.lock().await; + let client = node.client().expect("Node not started"); + let info = client.get_node_info(GetNodeInfoRequest {}).await?; + node_ids.push(info.node_id.clone()); + node_addresses.push(node.config.listening_address.clone()); + tprintln!("Node {} pubkey: {}", i, info.node_id); + + // Get funding address and mine blocks to it + let addr_resp = client.onchain_receive(OnchainReceiveRequest {}).await?; + tprintln!("Node {} funding address: {}", i, addr_resp.address); + + // Fund by mining blocks directly to the node's address + bitcoind.mine_to_address(10, &addr_resp.address)?; + tprintln!("Node {} funded with 10 block rewards", i); + } + + // Mine 101 blocks to mature the coinbase outputs (100 block requirement) + tprintln!("\nMining 101 blocks to mature coinbase outputs..."); + bitcoind.mine_blocks(101)?; + + // Wait for nodes to have spendable balance + tprintln!("Waiting for nodes to sync and have spendable balance..."); + for (i, node) in nodes.iter().enumerate() { + loop { + let node = node.lock().await; + let client = node.client().expect("Node not started"); + let balances = client.get_balances(GetBalancesRequest {}).await?; + if balances.spendable_onchain_balance_sats > 0 { + tprintln!( + "Node {} has spendable balance: {} sats", + i, + balances.spendable_onchain_balance_sats + ); + break; + } + drop(node); + sleep(Duration::from_secs(1)).await; + } + } + + // Open channels: Node0 -> Node1, Node1 -> Node2 (payments route through Node1) + tprintln!("\nOpening channels..."); + + // Node 0 -> Node 1 (private channel - routing hints in invoices) + { + let node0 = nodes[0].lock().await; + let client = node0.client().expect("Node not started"); + let resp = client + .open_channel(OpenChannelRequest { + node_pubkey: node_ids[1].clone(), + address: node_addresses[1].clone(), + channel_amount_sats: CHANNEL_AMOUNT_SATS, + push_to_counterparty_msat: Some((CHANNEL_AMOUNT_SATS / 2) * 1000), + channel_config: None, + announce_channel: false, + }) + .await?; + tprintln!("Opened private channel 0->1: {}", resp.user_channel_id); + } + + // Node 1 -> Node 2 (private channel - routing hints in invoices) + { + let node1 = nodes[1].lock().await; + let client = node1.client().expect("Node not started"); + let resp = client + .open_channel(OpenChannelRequest { + node_pubkey: node_ids[2].clone(), + address: node_addresses[2].clone(), + channel_amount_sats: CHANNEL_AMOUNT_SATS, + push_to_counterparty_msat: Some((CHANNEL_AMOUNT_SATS / 2) * 1000), + channel_config: None, + announce_channel: false, + }) + .await?; + tprintln!("Opened private channel 1->2: {}", resp.user_channel_id); + } + + // Wait for funding transactions to be broadcast to mempool + tprintln!("\nWaiting for funding transactions to reach mempool..."); + sleep(Duration::from_secs(2)).await; + + // Mine blocks to confirm channels + tprintln!("Mining blocks to confirm channels..."); + bitcoind.mine_blocks(6)?; + + // Wait for nodes to sync the new blocks (poll until all channels on all nodes have 6+ confirmations) + // Note: ldk-node's lightning wallet sync interval is 30 seconds by default + tprintln!("Waiting for nodes to sync new blocks (up to 30s for lightning wallet sync)..."); + let mut last_min_conf = 0; + loop { + let mut all_confirmed = true; + let mut global_min_conf = u32::MAX; + let mut total_channels = 0; + + for node in &nodes { + let node = node.lock().await; + let client = node.client().expect("Node not started"); + let channels = client.list_channels(ListChannelsRequest {}).await?; + for ch in &channels.channels { + total_channels += 1; + let conf = ch.confirmations.unwrap_or(0); + if conf < 6 { + all_confirmed = false; + } + if conf < global_min_conf { + global_min_conf = conf; + } + } + } + + if total_channels > 0 && all_confirmed { + tprintln!("All {} channels have at least 6 confirmations", total_channels); + break; + } + + if global_min_conf != u32::MAX && global_min_conf != last_min_conf { + tprintln!("Min confirmations across {} channels: {}", total_channels, global_min_conf); + last_min_conf = global_min_conf; + } + + sleep(Duration::from_secs(2)).await; + } + + // Wait for channels to become usable + tprintln!("Waiting for channels to become usable..."); + for (i, node) in nodes.iter().enumerate() { + let mut printed_status = false; + loop { + let node = node.lock().await; + let client = node.client().expect("Node not started"); + let channels = client.list_channels(ListChannelsRequest {}).await?; + let all_usable = channels.channels.iter().all(|ch| ch.is_usable); + if !channels.channels.is_empty() && all_usable { + tprintln!("Node {} has {} usable channel(s)", i, channels.channels.len()); + for ch in &channels.channels { + tprintln!( + " - Channel {} usable={} announced={} capacity={}", + ch.user_channel_id, + ch.is_usable, + ch.is_announced, + ch.channel_value_sats + ); + } + break; + } + if !printed_status { + tprintln!( + "Node {} channels: {} total, {} usable", + i, + channels.channels.len(), + channels.channels.iter().filter(|ch| ch.is_usable).count() + ); + for ch in &channels.channels { + tprintln!( + " - Channel {} ready={} usable={} confirmations={}", + ch.user_channel_id, + ch.is_channel_ready, + ch.is_usable, + ch.confirmations.unwrap_or(0) + ); + } + printed_status = true; + } + drop(node); + sleep(Duration::from_secs(1)).await; + } + } + + // Start payment loop and chaos monkeys + tprintln!("\n=== Starting payment loops and chaos monkeys ===\n"); + + // Shutdown signal + let (shutdown_tx, _) = watch::channel(false); + + // Payment tracker for timeout detection + let payment_tracker = Arc::new(PaymentTracker::new()); + + // Start 20 parallel payment loops + let mut payment_handles = Vec::new(); + for loop_id in 0..20 { + let nodes_clone = nodes.clone(); + let tracker_clone = payment_tracker.clone(); + let mut shutdown_rx = shutdown_tx.subscribe(); + let handle = tokio::spawn(async move { + payment_loop(nodes_clone, loop_id, tracker_clone, &mut shutdown_rx).await; + }); + payment_handles.push(handle); + } + + // Start independent chaos monkey for each node + let mut chaos_handles = Vec::new(); + for node_idx in 0..NUM_NODES { + let nodes_clone = nodes.clone(); + let node_ids_clone = node_ids.clone(); + let node_addresses_clone = node_addresses.clone(); + let mut shutdown_rx = shutdown_tx.subscribe(); + let handle = tokio::spawn(async move { + chaos_monkey_for_node( + nodes_clone, + node_ids_clone, + node_addresses_clone, + node_idx, + &mut shutdown_rx, + ) + .await + }); + chaos_handles.push(handle); + } + + // Timeout monitor task + let tracker_clone = payment_tracker.clone(); + let shutdown_rx = shutdown_tx.subscribe(); + let timeout_handle = tokio::spawn(async move { + loop { + if *shutdown_rx.borrow() { + return None; + } + if let Some(direction) = tracker_clone.check_timeout() { + return Some(direction); + } + sleep(Duration::from_millis(500)).await; + } + }); + + // Wait for Ctrl+C, any chaos monkey detecting channel closure, or payment timeout + tokio::select! { + _ = tokio::signal::ctrl_c() => { + tprintln!("\nReceived Ctrl+C, shutting down..."); + } + _ = futures::future::select_all(chaos_handles) => { + tprintln!("\nA chaos monkey exited (channel closed?), shutting down..."); + } + result = timeout_handle => { + if let Ok(Some(direction)) = result { + tprintln!("\nPAYMENT TIMEOUT: No successful payment in direction {} for {}s, shutting down...", direction, PAYMENT_TIMEOUT_SECS); + } + } + } + + // Signal all tasks to stop + let _ = shutdown_tx.send(true); + + // Wait for payment tasks to finish (with timeout) + let _ = + tokio::time::timeout(Duration::from_secs(5), futures::future::join_all(payment_handles)) + .await; + + // Cleanup + tprintln!("\nKilling nodes..."); + for node in &nodes { + node.lock().await.kill(); + } + + tprintln!("Done!"); + Ok(()) +} + +async fn payment_loop( + nodes: Vec>>, loop_id: usize, tracker: Arc, + shutdown: &mut watch::Receiver, +) { + let mut rng = rand::rngs::SmallRng::from_os_rng(); + + loop { + if *shutdown.borrow() { + return; + } + + // Pick random sender and receiver (must be different) + let sender_idx = rng.random_range(0..NUM_NODES); + let receiver_idx = loop { + let r = rng.random_range(0..NUM_NODES); + if r != sender_idx { + break r; + } + }; + + // Get invoice from receiver + let invoice = { + let receiver = nodes[receiver_idx].lock().await; + let Some(client) = receiver.client() else { + tprintln!("[L{}] Node {} down, skipping", loop_id, receiver_idx); + sleep(Duration::from_secs(1)).await; + continue; + }; + match client + .bolt11_receive(Bolt11ReceiveRequest { + amount_msat: Some(PAYMENT_AMOUNT_MSAT), + description: Some(Bolt11InvoiceDescription { + kind: Some(DescriptionKind::Direct(format!("L{}", loop_id))), + }), + expiry_secs: 3600, + }) + .await + { + Ok(resp) => resp.invoice, + Err(e) => { + tprintln!("[L{}] Invoice failed: {}", loop_id, e); + sleep(Duration::from_secs(1)).await; + continue; + }, + } + }; + + // Send payment from sender + { + let sender = nodes[sender_idx].lock().await; + let Some(client) = sender.client() else { + tprintln!("[L{}] Node {} down, skipping", loop_id, sender_idx); + sleep(Duration::from_secs(1)).await; + continue; + }; + + let payment_num = tracker.record_attempt(); + + match client + .bolt11_send(Bolt11SendRequest { + invoice, + amount_msat: None, + route_parameters: None, + }) + .await + { + Ok(resp) => { + let success_count = tracker.record_success(sender_idx, receiver_idx); + let (_, total) = tracker.get_counts(); + tprintln!( + "[L{}] {} -> {}: OK ({}) [{}/{}]", + loop_id, + sender_idx, + receiver_idx, + resp.payment_id, + success_count, + total + ); + }, + Err(e) => { + let (success, _) = tracker.get_counts(); + tprintln!( + "[L{}] {} -> {}: FAIL ({}) [{}/{}]", + loop_id, + sender_idx, + receiver_idx, + e, + success, + payment_num + ); + }, + } + } + } +} + +async fn chaos_monkey_for_node( + nodes: Vec>>, node_ids: Vec, node_addresses: Vec, + node_idx: usize, shutdown: &mut watch::Receiver, +) { + // Use a Send-safe RNG with unique seed per node + let mut rng = rand::rngs::SmallRng::from_os_rng(); + + loop { + if *shutdown.borrow() { + return; + } + + // Wait random interval (1-5 seconds) + let wait_secs = rng.random_range(1..=5); + tprintln!("[Chaos-{}] Waiting {}s before next action...", node_idx, wait_secs); + sleep(Duration::from_secs(wait_secs)).await; + + tprintln!("[Chaos-{}] SIGKILL node {}...", node_idx, node_idx); + { + let mut node = nodes[node_idx].lock().await; + node.kill(); + } + + // Restart + tprintln!("[Chaos-{}] Restarting node {}...", node_idx, node_idx); + { + let mut node = nodes[node_idx].lock().await; + if let Err(e) = node.start().await { + tprintln!("[Chaos-{}] Failed to restart node {}: {}", node_idx, node_idx, e); + continue; + } else { + tprintln!("[Chaos-{}] Node {} restarted successfully", node_idx, node_idx); + } + } + + // Reconnect to all other peers in a loop until all succeed + tprintln!("[Chaos-{}] Reconnecting node {} to other nodes...", node_idx, node_idx); + for peer_idx in 0..NUM_NODES { + if peer_idx == node_idx { + continue; + } + loop { + if *shutdown.borrow() { + return; + } + let node = nodes[node_idx].lock().await; + let Some(client) = node.client() else { + drop(node); + sleep(Duration::from_millis(500)).await; + continue; + }; + match client + .connect_peer(ConnectPeerRequest { + node_pubkey: node_ids[peer_idx].clone(), + address: node_addresses[peer_idx].clone(), + persist: Some(false), // Don't persist, already persisted from channel open + }) + .await + { + Ok(_) => { + tprintln!( + "[Chaos-{}] Node {} reconnected to node {}", + node_idx, + node_idx, + peer_idx + ); + break; // Success, move to next peer + }, + Err(e) => { + tprintln!( + "[Chaos-{}] Node {} failed to reconnect to {}: {}, retrying...", + node_idx, + node_idx, + peer_idx, + e + ); + drop(node); + sleep(Duration::from_millis(500)).await; + // Continue retrying + }, + } + } + } + } +} diff --git a/ldk-server/src/main.rs b/ldk-server/src/main.rs index acc1a9b..7c090fe 100644 --- a/ldk-server/src/main.rs +++ b/ldk-server/src/main.rs @@ -144,6 +144,12 @@ fn main() { Network::Regtest => storage_dir.join("regtest"), }; + // Create network directory if it doesn't exist + if let Err(e) = fs::create_dir_all(&network_dir) { + eprintln!("Failed to create network directory {}: {e}", network_dir.display()); + std::process::exit(-1); + } + let log_file_path = config_file.log_file_path.map(PathBuf::from).unwrap_or_else(|| { let mut default_log_path = network_dir.clone(); default_log_path.push("ldk-server.log");